【问题标题】:Angular 2 : ViewChild is undefined on parentAngular 2:ViewChild 在父级上未定义
【发布时间】:2017-11-25 21:48:15
【问题描述】:

我有以下错误:

错误:未捕获(承诺中):TypeError:无法设置未定义的属性“test_id” TypeError:无法设置未定义的属性“test_id”

错误是在这一行触发的:

    console.log('after view init testList', this.productList.test_id);

我看到了很多帖子,但所有帖子似乎都过时了,其中大多数都说我必须使用我所做的函数 ngAfterViewInit。 我有一个触发 updateTestId 的 clic 操作,我想将此 id 传递给我的子视图 ProductListComponent。 这是我的父组件:

import { Component,ViewChild} from '@angular/core';

import {Test,TestData} from './testService';

import { LocalDataSource } from 'ng2-smart-table';
import {ProductListComponent} from '../../components/product/list/productList.component';



@Component({
  selector: 'test-list',
  templateUrl: './testList.html',
  styleUrls: ['./testList.scss']
})
export class TestListComponent{

  //tests: Test[];
  tests: any[];
  selected_test : number;


  @ViewChild(ProductListComponent)
  private productList: ProductListComponent;

  constructor(protected service: TestData){
    this.service.getData().then((data) => {
      this.tests = data.tests;
      this.source.load(data);
    });


  }

  settings = {
    editable : false,
    actions: {
      add:false,
      edit:false,
      delete:false
  },
  columns: {
      id: {
        title: 'ID',
        type: 'number'
      },
      nb_cartons: {
        title: 'Cartons',
        type: 'number'
      },
      nb_items: {
        title: 'Items',
        type: 'number'
      },
      nb_pallets: {
        title: 'Pallets',
        type: 'number'
      },
  };

  //source : Test[];
  source: LocalDataSource = new LocalDataSource();


  public updateTestId(value:any):void {

    this.selected_test = value.data.id;
    console.log('rowSelect', this.selected_test );
    //console.log(this.productList.test_id)

  }


}

这是我的子组件:

    import { Component,Input,Output, OnChanges, SimpleChanges } from '@angular/core';

import { LocalDataSource } from 'ng2-smart-table';
import {Test} from '../../test/testService';

@Component({
  selector: 'product-list',
  templateUrl: './productList.html',
  styleUrls: ['./productList.scss']
})
export class ProductListComponent implements OnChanges{

  @Input() test_id : number = null;

  settings = {
    editable : false,
    actions: {
      add:false,
      edit:false,
      delete:false
    },
    columns: {
      id: {
        title: 'ID',
        type: 'number'
      },
      sku: {
        title: 'SKU',
        type: 'string'
      },
      reference: {
        title: 'Reference',
        type: 'string'
      },
      size: {
        title: 'Size',
        type: 'string'
      },
    },
    edit: {
      editButtonContent: '<i class="ion-edit"></i>',
      saveButtonContent: '<i class="ion-checkmark"></i>',
      cancelButtonContent: '<i class="ion-close"></i>',
    }
  };

  source: LocalDataSource = new LocalDataSource();


  constructor() {

  }

  ngOnChanges(changes: SimpleChanges) {
    console.log(changes['test_id'],changes['test_id'].currentValue);
    console.log('change in child',changes.test_id);
  }

  /*
  @Input()
  set _test_id(id: number) {
    this._test_id = id;
  }

  get test_id(): number { return this._test_id; }
*/

}

我像这样使用子选择器:

<test-list></test-list>
<product-list #productList [test_id]="selected_test"></product-list>

【问题讨论】:

  • test_id ?你还没有定义它....所以它会很明显地抛出错误
  • 它在我的子组件中定义(我更新了我的帖子:@Input() test_id : number = null;)
  • 这样做的目的是什么?
  • 如上所述,我的主要目标是将此测试 id 传递给我的子组件。这个 id 是在我的父组件上定义的,点击父组件内的列表行
  • 你能在问题中包含完整的 testList.html 吗?里面没有ngIf 指令?如果把有问题的行注释掉,能看到你的子组件(ProductListComponent)吗?

标签: javascript angular


【解决方案1】:

在模板中的product-list 中添加一个template reference variable 名称

<product-list #productList [test_id]="selected_test"></product-list>

并在组件中引用它

@ViewChild('productList')
private productList: ProductListComponent;

编辑:

在这种情况下,Vivek Doshi 的回答是正确的,因为您通过 @Input 将数据传递给孩子,所以您不需要它。但仍然 - 如果您想使用 ViewChild,这是一个解决方案 :)

【讨论】:

  • 我试过你的解决方案,它没有改变错误。这是一个很好的提示,因为现在我的 ide 很好地重定向到 productList 组件的 test_id 而不是搜索它,但遗憾的是它没有解决我的问题
【解决方案2】:

如果你想将数据从父母传递给孩子,你可以直接传递

<product-list [test_id]="selected_test"></product-list>

就是这样,仅此而已。

无需通过@ViewChild访问


从产品列表组件中检测随时间变化的值

ngOnChanges(changes: SimpleChanges) {
    console.log(changes['test_id'].currentValue);
}

示例:

@Component({selector: 'my-cmp', template: `...`})
class MyComponent implements OnChanges {
  @Input()
  prop: number;

  ngOnChanges(changes: SimpleChanges) {
    // changes.prop contains the old and the new value...
  }
}

注意事项: 您需要在子组件上implements OnChanges

更多详情请阅读doc

【讨论】:

  • 我再次尝试了您的解决方案,但它没有触发任何更改,因为我的点击设置了 selected_test 。我只在加载时显示了一次日志并且它是未定义的(此时正常)我确实实现了 OnChanges 并在测试列表(在 selected_test 上)和产品列表(在 test_id 上)中添加了日志消息。所以没有检测到更改的值,我不知道为什么。我会用 viewChild 再试一次,除非你有解决方案
  • 应该可以,请检查,代码会有一些小问题,不需要使用ViewChild。如果你有 plunker ,请在这里分享。
  • 这正是我所做的,但它不起作用。当我使用 ng2-admin 生成我的列表时,我可能需要几个小时在 plunker 中重建我的代码,我有依赖项和 api 调用来模拟,所以创建它并不容易。我尝试了几种方法(@input,viewChild...),但我想如果我没有明确的解决方案,我将不得不采用肮脏的方式并将其保存在会话中。
  • 试试 console.log(changes['text_id'].currentValue);
  • 您能发布完整的组件代码吗?有问题?
猜你喜欢
  • 2017-01-08
  • 2019-07-28
  • 2016-04-29
  • 1970-01-01
  • 2018-01-24
  • 2019-06-23
  • 2019-10-19
  • 2018-02-25
相关资源
最近更新 更多