【问题标题】:How Communication takes between two sibling component in Angular 2 (plus)Angular 2 中两个兄弟组件之间的通信方式(加)
【发布时间】:2018-08-21 15:55:43
【问题描述】:

我正在研究 Angular 2。我发现两个兄弟组件之间或从子组件到父组件之间的通信很困难。甚至在 Angular 2 文档中也没有提到它

您能否提供一些有关它的信息,因为两个兄弟组件的通信方式看起来比父组件使用“ViewChild”装饰器与其子组件通信的方式复杂。但不可能始终按照项目要求在两个组件之间建立父子关系。

<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script>
var finalvalue = {};
var increment=0;
var uniqueKey = [];
var divv;
function myFunction() {
var a=[" ","number","text","textbox","date"];  
   divv=document.createElement("div");
   divv.id="grandparentss"
   $("#demo").prop("disabled",true);
   main(a); 
  document.body.appendChild(divv);
}
function main(aa){
var div = document.createElement("div");
div.classList.add("class1");
var input = document.createElement("input");
input.id="input";
input.value="";
input.placeholder="label";
input.classList.add("design");
input.addEventListener("keyup", function(){addButtonFunction()});
var select = document.createElement("select");
select.id="select";
select.classList.add("design");
select.addEventListener("change", function(){addButtonFunction()});
var i=0;
for(i;i<aa.length;i++){
  var option = document.createElement("option");
  var txt = document.createTextNode(aa[i]);
  option.appendChild(txt);
  select.appendChild(option);
 }

var add = document.createElement("button");
add.id="button";
add.classList.add("design");
var txt1=document.createTextNode("add");
add.appendChild(txt1);
add.setAttribute("disabled","");
add.addEventListener("click", function(){ if(uniqueKey.indexOf($("#input").val()) === -1){ getValue($("#input").val(),$("#select").val())};result(input.value);$("#select").val(""); $("#input").val("");addButtonFunction()});
var submit = document.createElement("button");
  submit.id = "submit"
  submit.classList.add("design");
  var txt2=document.createTextNode("submit"); 
  submit.appendChild(txt2);
  submit.setAttribute("disabled","");
  submit.addEventListener("click", function(){submiting()});
  div.appendChild(input);
  div.appendChild(select);
  div.appendChild(add);
  div.appendChild(submit);
  divv.appendChild(div); 
}


function addButtonFunction(){
  if($("#input").val() && $("#select").val()){
        document.getElementById("button").removeAttribute("disabled");
    } 
    else{
        document.getElementById("button").setAttribute("disabled","");
    }

}

function getValue(key,value){
  var div = document.createElement("div");
  div.id= key+"11"+increment;
  div.classList.add("form-inline");
  var div1 = document.createElement("div"); 
  div1.classList.add("form-group");
  div1.id= key+"$"+increment;
  var label = document.createElement("label");
  var txt = document.createTextNode(key);
  label.appendChild(txt);
  if(value === "textbox"){
  var input = document.createElement("textarea");
  }
  else{
  var input = document.createElement("input");
  input.classList.add("form-control");
  if(value === "date"){input.type="date"
  }
  else if(value === "number"){input.type="number"}
  input.placeholder="please write"+ key;
  }
  input.classList.add("form-control");
  input.id=key;
  input.addEventListener("input", function(){result(input.id);$(`#${input.id}`).val()});
  div1.appendChild(label);
  div1.appendChild(input);
  var add = document.createElement("button");
  var txt1=document.createTextNode("x");
  add.appendChild(txt1);
  add.addEventListener("click", function(){deleted(div.id,div1.id); deleteJson(input.id)});
  div1.appendChild(add);
  div.appendChild(div1);
  divv.appendChild(div);
  increment++;
}

function result(input){
 finalvalue[input]= $(`#${input}`).val();
 uniqueKey=Object.keys(finalvalue);
 if(Object.keys(finalvalue).length){document.getElementById("submit").removeAttribute("disabled");}else{document.getElementById("button").setAttribute("disabled","");}

}

function deleted(parent,child){
 document.getElementById(parent).removeChild(document.getElementById(child));
 document.getElementById("grandparentss").removeChild(document.getElementById(parent));
}

function deleteJson(input){
 delete finalvalue[input];
 uniqueKey=Object.keys(finalvalue);
}

function submiting(){
 document.getElementById("output").innerHTML= JSON.stringify(finalvalue);
   console.log(finalvalue);
}
</script>

<style>

.class1{
margin-top: 47px;
margin-bottom: 20px;
margin-left: 44px;
}

.form{
margin-top: 21px;
margin-left: 20px;

}
.form-inline{
    margin-top: 47px;
    margin-bottom: 20px;
    margin-left: 95px;
    }
.design{
margin-left: 57px;
}
.form-control{
margin-left: 65px;
}
</style>
</head>
<body>
<button onclick="myFunction()" class="form" id="demo">create Form</button>
<br><br>
<p id="output"></P>
</body>
</html>

【问题讨论】:

  • 我会建议你去使用状态管理技术来实现更多的交互

标签: angular angular5 angular2-services


【解决方案1】:

你的结构应该是这样的

parent
  |-- Sibling 1
  |-- Sibling 2

如果是这种情况,您可以使用ViewChildHost 指令。

在父级中:

@ViewChild(ChildOneComponent) one: ChildOneComponent;
@ViewChild(ChildTwoComponent) two: ChildTwoComponent;

在你的孩子中:

constructor(@Host() public parent: ParentComponent)

现在在第一个孩子中,你可以使用这个:

this.parent.one.methodFromChildOne();

这是众多示例之一,可能不是最好的示例(紧密耦合,gna gna gna),但我认为它是最容易理解和理解的示例。

【讨论】:

  • 如果它是父母孩子意味着我们可以使用这个感谢您的重播......很好的答案你能有任何工作示例或任何链接来理解
【解决方案2】:

您可以使用 mobx-angular、ngrx-store 之类的状态管理,也可以使用 @Input、@Output 或双向绑定 [(variable)],这取决于您的需要。

【讨论】:

    【解决方案3】:

    或者您可以使用双向服务。即使您的组件位于不同的模块中也很有用。

    服务

    import { Injectable } from '@angular/core';
    import { Subject }    from 'rxjs/Subject';
    
    @Injectable()
    export class AppShareService {
      private readonly subjectSource$ = new Subject<object>();
    
      public get newData(): Observable<object> {
        return this.subjectSource$.asObservable();
      }
    
      public publish(data: any) {
        this.subjectSource$.next(data);
      }
    }
    

    您可以像这样发布类似事件的消息:

    export class AppComponent {
      constructor(public appShareService: AppShareService ) {
        appShareService.publish({data: 'some data'});
      }
    }
    

    您可以订阅这些事件:

    export class HomeComponent implements OnDestroy {
      mySubscription: Subscription;
    
      constructor(public appShareService: AppShareService ) {
        this.mySubscription = appShareService.newData.subscribe((data) => {
          console.log(data); // {data: 'some data'}
        });
      }
    
    ngOnDestroy(): void {
      if (this.mySubscription) {
        this.mySubscription.unsubscribe();
      }
     }
    }
    

    良好的做法是始终取消订阅 Observable。 ngOnDestroy 是一个很好的地方。

    【讨论】:

    • 谢谢兄弟...这是我需要的,但我想知道是否需要在两个模块中导入此服务。
    • @Guvaliour 我之前没有注意到你的问题。实际上这个服务应该在CoreModule。而CoreModule 总是导入到AppModule 中。所以你应该可以在应用程序的任何地方访问。如果对您有帮助,请标记此答案:) 您可以在此处阅读有关模块结构的更多信息:stackoverflow.com/questions/42695931/…
    【解决方案4】:

    也可以使用@Input/@Output 和 Observables 和 EventEmitters。 这有助于 OnPush 更改检测。如果您使用默认更改检测,那么它会更容易。您可以使用共享服务技术。下面的示例在子级和父级中带有 @Input@Output 以及要订阅的 Observables 和异步管道。

    示例:

        @Component({
        selector: 'parent',
        template: `<div><notes-grid 
                [Notes]="(NotesList$ | async)"
                (selectedNote)="ReceiveSelectedNote($event)"
            </notes-grid>
            <note-edit 
                [gridSelectedNote]="(SelectedNote$ | async)"
            </note-edit></div>`,
        styleUrls: ['./parent.component.scss']
    })
    export class ParentComponent {
    
        // create empty observable
        NotesList$: Observable<Note[]> = of<Note[]>([]);
        SelectedNote$: Observable<Note> = of<Note>();
    
        //passed from note-grid for selected note to edit.
        ReceiveSelectedNote(selectedNote: Note) {
        if (selectedNote !== null) {
            // change value direct subscribers or async pipe subscribers will get new value.
            this.SelectedNote$ = of<Note>(selectedNote);
        }
        }
        //used in subscribe next() to http call response.  Left out all that code for brevity.  This just shows how observable is populated.
        onNextData(n: Note[]): void {
        // Assign to Obeservable direct subscribers or async pipe subscribers will get new value.
        this.NotesList$ = of<Note[]>(n.NoteList);  //json from server
        }
    }
    
    //child 1 sibling
    @Component({
      selector: 'note-edit',
      templateUrl: './note-edit.component.html', // just a textarea for noteText and submit and cancel buttons.
      styleUrls: ['./note-edit.component.scss'],
      changeDetection: ChangeDetectionStrategy.OnPush
    })
    export class NoteEditComponent implements OnChanges {
      @Input() gridSelectedNote: Note;
    
        constructor() {
        }
    
    // used to capture @Input changes for new gridSelectedNote input
    ngOnChanges(changes: SimpleChanges) {
         if (changes.gridSelectedNote && changes.gridSelectedNote.currentValue !== null) {      
          this.noteText = changes.gridSelectedNote.currentValue.noteText;
          this.noteCreateDtm = changes.gridSelectedNote.currentValue.noteCreateDtm;
          this.noteAuthorName = changes.gridSelectedNote.currentValue.noteAuthorName;
          }
      }
    
    }
    
    //child 2 sibling
    
    @Component({
        selector: 'notes-grid',
        templateUrl: './notes-grid.component.html',  //just an html table with notetext, author, date
        styleUrls: ['./notes-grid.component.scss'],
        changeDetection: ChangeDetectionStrategy.OnPush
    })
    export class NotesGridComponent {
    
    // the not currently selected fromt eh grid.
        CurrentSelectedNoteData: Note;
    
        // list for grid
        @Input() Notes: Note[];
    
        // selected note of grid sent out to the parent to send to sibling.
        @Output() readonly selectedNote: EventEmitter<Note> = new EventEmitter<Note>();
    
        constructor() {
        }
    
        // use when you need to send out the selected note to note-edit via parent using output-> input .
        EmitSelectedNote(){
        this.selectedNote.emit(this.CurrentSelectedNoteData);
        }
    
    }
    
    
    // here just so you can see what it looks like.
    
    export interface Note {
        noteText: string;
        noteCreateDtm: string;
        noteAuthorName: string;
    }
    

    【讨论】:

      猜你喜欢
      • 2017-01-01
      • 2016-06-23
      • 1970-01-01
      • 2017-07-18
      • 1970-01-01
      • 2016-07-08
      • 2017-05-04
      • 2017-10-30
      • 1970-01-01
      相关资源
      最近更新 更多