Angular7 child1到父级-父子到child2通讯错误

时间:2019-12-05 19:16:46

标签: angular observable

仅是我的问题的一个示例:- 父母有孩子1和孩子2。

我正在数组child2的onLoad中显示月份列表。

在child1上单击按钮,将按一次弹出几个月。

在child1上单击一个按钮,它将向父级发送新值,并且该值将从父级发送到child2.ts并更新月份的数组

问题是,从父级到子级2的通信时出现错误。 我使用了可观察的订阅方法,它显示为

this.months.asObservable is not a function

下面是我的代码。

////////////////child1.ts///////////////////////////////////

onClick() {
  this.navigateMonths.emit(this.month);
}



////////////// parent.ts//////////////////////
months: Subject < void > = new Subject < void > ();
navigatedMonths(months) {
  this.months = months;
  this.months.asObservable();
}

/////////child2.ts////////////////////////
@Input() navigatedMonths: Observable < void > ;
ngOnInit() {
  this.navigatedMonths.subscribe((months) => {
    this.months = months;
  })
  this.getMonths(this.year, this.month);

}
////////////// parent.html//////////////////////////////////////////
< child2 class="row-items" [navigatedMonths]="months">< /child2>
< child1(navigateMonths)='navigatedMonths($event)'> Next Month< /child1>

3 个答案:

答案 0 :(得分:1)

快速修正-摆脱不需要的可观察对象/主题

////////////// parent.ts//////////////////////
months: any[]; // no subject anymore
navigatedMonths(months) {
  this.months = months;
}

/////////child2.ts////////////////////////
@Input() 
set navigatedMonths(months: any[]) { // make a setter from your input
   // Do whatever you want when new months come in
} 

您可能应该考虑引入两个孩子之间共享的服务。父母不必知道这几个月。

阅读:https://angular.io/guide/component-interaction父母和子女通过服务进行沟通)-组件之间的通信同样适用(即使他们没有父母与孩子的关系)

该服务可能如下所示:

export class MonthsService {

  // private for internal use
  private monthsSource: BehaviorSubject<string[]> = new BehaviorSubject([]); // init with empty array

  // public for use in components or other services
  months$: Observable<string[]> = this.monthsSource.asObservable(); 

  addMonth(newMonth: string) {
    const months = [...this.monthsSource.getValue(), newMonth]; // Create new months array
    this.monthsSource.next(months);
  }
}

完整示例:https://stackblitz.com/edit/ng-zorro-antd-start-ddozvn

现在,子级不再有输入或输出,父级组件保持干净。每个对数据感兴趣的组件都只订阅了可观察的months $。

答案 1 :(得分:1)

您提到的场景可以通过从child1 to parent发出数据(使用eventEmitters)来实现

  

child1.ts

  i = 0;
  months = ["jan","feb","march","april"];
  @Output() messageEvent = new EventEmitter<string>();
  sendMessage() {
     this.messageEvent.emit(this.months[this.i]);
     this.i++;
  }

,然后从parent to child2(使用@viewChild)。

  

parent.ts

  message:string;
  @ViewChild(Child2Component) child;
  receiveMessage($event) {
     this.message = $event
     this.child.addMonth(this.message);
  }
  

child2.ts

  months:any[] = [];
  @Input() childMessage: string;
  addMonth(month){
     this.months.push(month);
     console.log(this.months);
  }

添加了工作演示:demo

注意:可以在控制台上看到child2的months数组的输出。

编辑:以下是在Subject中使用service的第二种方法。此方法可用于所有类型的组件交互。无论是parent-child还是child-parentsiblings交互。

您应遵循以下步骤:

  

myService.ts

创建正在使用的主题。 (主题需要从rxjs导入)

mySubject = new Subject();
  

child1.ts

使用next()向主体添加/推送项目:

this.myService.mySubject.next(this.months[this.i++])
  

child2.ts

订阅主题以阅读该项目:

ngOnInit(){
   this.myService.mySubject.subscribe((data)=>{
     this.months.push(data);
     console.log(this.months);
   });
}

答案 2 :(得分:0)

另一种选择是对@Input()@Output()EventEmitter使用双向绑定。通过将@Output() EventEmitter命名为与@Input()相同的名称,并在名称后附加Change,可以实现双向绑定。

child1.component.ts

@Input()
public message: Message;

@Output()
public messageChange: EventEmitter<Message> = new EventEmitter<Message>();

public text: string;

send() {
  if (this.text.trim().length > 0) {
    this.messageChange.emit(new Message(`Child1: ${this.text}`));
  }
}

parent.component.html

<app-child1 [(message)]="message"></app-child1>
<app-child2 [(message)]="message"></app-child2>
  

https://stackblitz.com/edit/angular-46ndlt

     

https://medium.com/@preethi.s/angular-custom-two-way-data-binding-3e618309d6c7