【问题标题】:Cannot pass data from Parent to Child component无法将数据从父组件传递到子组件
【发布时间】:2021-02-22 13:22:24
【问题描述】:

你对下面这个奇怪的问题有什么想法吗?

我正在将数据从父组件传递到子组件,该子组件从服务方法返回,将数据返回为Observable<DemoModel>。但是,在加载子组件时,数据未定义,仅在ngAfterViewInit 之后填充(我也尝试过通过此方法获取数据,但数据仍然未定义)。所以,我也尝试应用一些ngOnchanges 方法,但问题更多与从父组件检索到的数据在子组件加载时尚未准备好(我也尝试使用异步等而不是订阅。在加载子组件时我应该如何获取数据以使其准备就绪?

父子组件如下图:

家长比较

<child-component
    [courses]="courses|async" 
>
</child-component>



courses: any;

this.service.listCourses().subscribe((course: Course) => {
  this.courses = course;
});

儿童补偿

private courses: any;

@Input()
set data(data: any) {
    this.courses.next(data);
}

myControl = new FormControl('');

ngAfterViewInit() {

  // >>> THIS THROWS ERROR AS this.courses is undefined
  this.myControl.setValidators([
    Validators.required,
    forbiddenNamesValidator(this.courses)
  ]);
}

我也尝试在html中使用一些*ngIf,但是由于方法中使用了this.courses参数,因此检查html中的数据没有任何意义。

这个问题可能是subscribe方法引起的,不过我也试过用promise(不知道是不是用对了)。

【问题讨论】:

    标签: javascript angular typescript


    【解决方案1】:

    您当前的实现存在一些问题:

    • 在您的父组件中,课程是一个数组(我假设)不是可观察的 - 无需使用 async 管道
    • 在您的 Child 组件中,您已将输入字段命名为 data,并使用 setter 对应为数组的变量调用 .next - 即 .next 将不存在。

    下面应该修复你当前的实现

    家长比较

    <child-component
        [courses]="courses" 
    >
    </child-component>
    
    courses: any;
    
    this.service.listCourses().subscribe((course: Course) => {
      this.courses = course;
    });
    

    儿童补偿

    @Input() courses: any;
    

    需要注意的是listCourses 是异步的

    这意味着courses 在调用ngAfterViewInit 时不一定保证有一个值,并且可能会抛出类似的错误。

    我可以建议解决以下问题:

    <child-component
        *ngIf="courses?.length"
        [courses]="courses" 
    >
    </child-component>
    

    您不必等待ngAfterViewInit,而只需等待ngOnInit

    ngOnInit(): void {
        this.myControl.setValidators([
            Validators.required,
            forbiddenNamesValidator(this.courses)
        ]);
    }
    

    评论

    将列表从父母传递给孩子,我应该使用可观察/承诺/数组等吗?

    这完全取决于你,我更喜欢在处理 observables 时使用 async 管道,因为这样我就不必担心取消订阅了。

    <child-component
        [courses]="courses | async" 
    >
    </child-component>
    
    courses = this.service.listCourses()
    

    我认为子组件中的课程不需要使用get/set,因为列表不会改变

    在处理发生变化的数据时,您甚至不需要使用 get/set。 Angular 将为您更新 @Input 数据,因此您无需担心使用 get/set,除非您明确需要该功能。

    我应该调用this.myControl.setValidators([]}onInitafterViewInit 中的过滤方法

    无需将验证器设置为您的afterViewInit,您无需等待组件的视图初始化后再设置验证器。

    【讨论】:

    • 1. 为了将列表从父母传递给孩子,您有什么建议?使用带有可观察变量的asyncpromise 等?当我的 listCourses() 方法返回 Observable 时,使用异步会更好吗?
    • 2. 我认为没有必要对子组件中的课程使用get/set,因为列表不会改变(实际上它加载 SelectList 值。所以,最好不要订阅,我应该在这个场景中使用什么来填充父组件中的列表?
    • 3. 我应该在子组件中调用onInitafterViewInit 上的子组件this.myControl.setValidators([]} 和过滤方法ib ?
    • 已更新,请记住,如果答案解决了您的问题 - 请将其标记为已接受,以便您的问题可以结束。
    • 非常感谢一一详细的解释。
    【解决方案2】:

    第一种方式:添加ngIf查看是否有数据。

    <child-component [courses]="courses" *ngIf="courses.length > 0"> </child-component>
    

    第二种方式:如果你想使用async,那么不要在你的组件中订阅它。

    <child-component [courses]="courses$ | async" *ngIf="(courses$| async)?.length > 0"> </child-component>
    

    组件:

    courses$: Observable<any>;
    
    this.courses$ = this.service.listCourses().pipe(shareReplay());
    

    【讨论】:

    • 子组件中输入的变量名也是错误的。
    • @uiTeam324 在我尝试之前有什么需要纠正的吗?
    • @uiTeam324 由于课程列表用于填写下拉列表,并且不会更改,所以最好不要订阅它?如果是这样,为什么使用.pipe(shareReplay() 部分而不是仅使用this.service.listCourses()
    • @PragDopravy,如果您在同一个视图中多次使用async,它将多次调用 API 端点。 shareReplay 将阻止这种情况,并通过一次调用在他们之间共享数据。
    • 非常感谢,但我无法投票,因为我没有足够的 repo。对我的问题有任何投票吗?
    猜你喜欢
    • 2019-02-27
    • 2017-04-20
    • 2018-02-12
    • 1970-01-01
    • 1970-01-01
    • 2020-10-22
    • 2017-06-10
    相关资源
    最近更新 更多