简体   繁体   English

ViewChild返回“未定义”-Angular2

[英]ViewChild returns 'undefined' - Angular2

I'm trying to execute a function of a child component with a push of a button on the parent but for some reason its undefined. 我试图通过按下父级上的按钮来执行子级组件的功能,但由于某种原因其未定义。

Parent: 上级:

.. com1.html
  <ng-template #content let-c="close" let-d="dismiss">
    <div class="modal-header">
      <h4 class="modal-title">Title</h4>
    </div>
    <div class="modal-body" style="display: flex; justify-content: center;">
      <app-com2 [var1]="value" #traceRef></app-com2>
    </div>
    <div class="modal-footer">
      <button type="button" class="btn btn-outline-dark" (click)="savePNG()"><i class="fa fa-download"></i>PNG</button>
      <button type="button" class="btn btn-outline-dark" (click)="c()">Close</button>
    </div>
  </ng-template>

<button class="btn btn-sm btn-secondary" (click)="open(content)">Button</button>

...com1.ts
export class com1 implements OnInit {
@ViewChild('traceRef') traceRef;
value = "something";

  constructor(private modalService: NgbModal) {}

  savePNG() {
    this.traceRef.savePNG();
  }

  open(content: any) {
    this.modalService.open(content, { windowClass: 'temp-modal' });
  }
}

Could anyone point me in the right directions cuz the other threads were of no help :( Even with ngAfterViewInit its still undefined. 任何人都可以向我指出正确的方向,因为其他线程没有帮助:(即使使用ngAfterViewInit,它仍然是未定义的。

The reason why it is not working as it would be in common scenario with ng-template is that NgbModal service creates template and doesn't attach it to parent view but rather to root ApplicationRef 之所以无法像在ng-template中常见的情况那样工作,是因为NgbModal服务会创建模板,并且不会将其附加到父视图,而是附加到根ApplicationRef

const viewRef = content.createEmbeddedView(context);
this._applicationRef.attachView(viewRef);

https://github.com/ng-bootstrap/ng-bootstrap/blob/0f8055f54dad84e235810ff7bfc846911c168b7a/src/modal/modal-stack.ts#L107-L109 https://github.com/ng-bootstrap/ng-bootstrap/blob/0f8055f54dad84e235810ff7bfc846911c168b7a/src/modal/modal-stack.ts#L107-L109

This means your query will be always undirty for your component. 这意味着您的查询对于您的组件将始终是干净的。

In common cases(see example provided by @ConnorsFan) we use vcRef.createEmbeddedView which is responsible for checking queries in parent view: 在通常情况下(参见例如由@ConnorsFan提供),我们使用vcRef.createEmbeddedView它负责检查父视图的查询:

vcRef.createEmbeddedView
          ||
          \/
function attachEmbeddedView(
   ...
  Services.dirtyParentQueries(view);  <========== set dirty for queries

https://github.com/angular/angular/blob/0ebdb3d12f8cab7f9a24a414885ae3c646201e90/packages/core/src/view/view_attach.ts#L12-L23 https://github.com/angular/angular/blob/0ebdb3d12f8cab7f9a24a414885ae3c646201e90/packages/core/src/view/view_attach.ts#L12-L23

The simple solution i can see here is just pass or call reference directly in template: 我在这里可以看到的简单解决方案就是直接在模板中通过或调用引用:

(click)="traceRef.savePNG()"

I think you need something as below. 我认为您需要以下内容。 replace ChildComponent with your child class name 用您的子类名称替换ChildComponent

@ViewChild('traceRef') 
      traceRef:ChildComponent

I notice that your parent template is a modal, which you open using a template variable here: ((click)="open(content)" via your modal service. So this means it gets added to the DOM dynamically. 我注意到您的父模板是模态的,您可以通过模态服务在此处使用模板变量((click)="open(content)"它,因此这意味着它是动态添加到DOM的。

So this could be a timing issue because the parent is loaded dynamically. 因此,这可能是一个时序问题,因为父级是动态加载的。

I would try this, in the ngAfterViewInit of the CHILD, fire an event using EventEmitter. 我将在CHILD的ngAfterViewInit中尝试使用EventEmitter触发事件。 Grab the event in the parent, and then set a flag to true. 抓住父事件,然后将标志设置为true。 Then IN THEORY you can do this in the parent: 然后,在理论上,您可以在父级中执行此操作:

  savePNG() {
    if (this.childLoaded) this.traceRef.savePNG();
  }

You know for sure the child is loaded and so savePNG is available. 您肯定知道孩子已加载,因此savePNG可用。 However, see my note - traceRef will still be undefined. 但是,请参阅我的注释-traceRef仍将是未定义的。

So you need to pass a reference to the child function in the EventEmitter and use that instead of #traceRef. 因此,您需要在EventEmitter中传递对子函数的引用,并使用该引用代替#traceRef。

Eg - in the child: 例如-在孩子中:

export class app-com2 implements blah blah {
  @Output() childLoaded: EventEmitter<any> = new EventEmitter<any>();

  savePNG() {
    // code to save the image
  }

  ngAfterViewInit() {
    this.childLoaded.emit(this.savePNG);
  }
}

Parent: 上级:

.. com1.html .. com1.html

  <ng-template #content let-c="close" let-d="dismiss">
    <div class="modal-header">
      <h4 class="modal-title">Title</h4>
    </div>
    <div class="modal-body" style="display: flex; justify-content: center;">
      <app-com2 [var1]="value" (childLoaded)="handleChildLoaded($event)"></app-com2>
    </div>

..com1.ts ..com1.ts

handleChildLoaded(save: any) {
  const result = save;
  console.log(result);
}

Docs on child to parent comms. 关于子对母通讯的文档

NOTE 注意

Thinking about this more - this is a lifecycle/timing issue, so your code will never work. 多考虑一下-这是生命周期/定时问题,因此您的代码将永远无法工作。 This might be why: 这可能是原因:

  1. Your parent component loads, fires all lifecycle hooks (eg. ngOnInit and ngAfterViewInit etc). 您的父组件加载并触发所有生命周期挂钩(例如ngOnInit和ngAfterViewInit等)。 #content gets processed and becomes available in ngAfterViewInit and later hooks. #content将被处理并在ngAfterViewInit和更高版本的挂钩中变得可用。

  2. You now click a button to load #content (which is available). 现在,您单击一个按钮以加载#content(可用)。 But it has <app-com2> component, which is referenced with the #traceRef template variable. 但是它具有<app-com2>组件,该组件由#traceRef模板变量引用。 But template variables are only processed just before the ngAfterViewInit hook fires - and that has already fired for the parent, and so #traceRef arrives too late for Angular to hook it up. 但是模板变量仅在ngAfterViewInit钩子触发之前处理-并且已经为父级触发了,因此#traceRef到来太晚了,Angular无法将其挂接。 Hence it will always be undefined. 因此,它将始终是不确定的。

See comments below regarding (2) - not quite right, but I suspect it is because of the way you are loading the modal that #traceRef will always be undefined. 请参阅以下有关(2)的注释-不太正确,但是我怀疑是由于加载模式的方式而导致#traceRef始终未定义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM