web-dev-qa-db-ja.com

Angular ng-template内の6つのネストされたViewChildがnullです

アプリケーションではモーダル( ng-bootstrap's one )を使用しています。そのモーダルは次のようになります。

<ng-template #modal let-modal>
    <app-audio #audio></app-audio>
</ng-template>

そしてそれは論理です:

@ViewChild('modal')
modal: ElementRef;

@ViewChild('audio')
audio: AudioComponent;

モーダルは次のように開かれます。

this.modalService.open(this.modal、{size: 'lg'});

ここまではすべて問題ありません。モーダルが開き、オーディオコンポーネントが表示されます。しかし今、私たちはコンポーネント内にあるロジックにアクセスしたいと思っています。

this.audio.somePublicComponentFunction()

This.audioがnullであることが起こります。私はすでにangularの変更検出器を使用して子を取得しようとしましたが、this.audioを実際のコンポーネントに適切にリンクする方法を見つけることができません。何か案は?どうもありがとう。

ここで問題を確認できます:stackblitz.com/edit/angular-ofmpju

4
Erwol

このようにrefrence変数なしで子コンポーネントを読み取ることができます

_@ViewChild(AudioComponent)
audio: AudioComponent;
_

これにより、子コンポーネントのインスタンスが提供されます-メソッドにアクセスできます

this.audio.someComponentFunction()

あなたのhtml

_<ng-template #modal let-modal>
    <app-audio></app-audio>
</ng-template>
_

これは私が思うあなたの問題を解決します-ハッピーコーディング

更新:

この問題の回避策が見つかったことを願っています-1つの関数のみをトリガーする場合は、この方法を使用できます

gettersetterでプロパティを追加し、値をsetしたときに関数をトリガーしました

_@Input()
  get triggerFunction(): boolean {
    return this.runFuntion;
  }

  set triggerFunction(value: boolean) {
    this.runFuntion = value;
    this.someFunction();
  }  
_

したがって、これにより、モデルが表示されるたびに関数がトリガーされます-上記のプロパティは、_<ng-template>_内にネストされた子コンポーネントに属しているため、最終的にモデルテンプレートは次のように読み取られます。

_<ng-template #modal let-modal>
  <app-audio [triggerFunction]="true"></app-audio>
</ng-template>
_

これが今のところ回避策として機能することを願っています-ありがとう

4
Rahul

テンプレート自体からメソッドaudio.someFunction()を呼び出すことができます。

<ng-template #modal let-modal>
  <div style="background-color: red;"> 
  <h1>Modal header</h1>
  <app-audio #audio></app-audio>
  <!-- on click, call audio comp method someFunction() using its reference --> 
  <button (click)="audio.someFunction()">Operate with audio from inside modal</button>
  </div>
</ng-template>

ここでは@ViewChildプロパティは必要ありません。これはあなたのためにトリックをするはずです。

フォーク デモ

4
Amit Chigadani

私にとって、このすべてのソリューションは機能せず、サードパーティのng-template内の自分のコンポーネントにアクセスしたかったのです。これが私の「解決策」です。これはベストプラクティスではないと思いますが、私が欲しいものを手に入れるための必死の解決策です;-)もちろんそれはあなた自身のコンポーネントに対してのみ機能します。

// mycomponent.ts => component that needs to be accessed 
import { Component, Output, EventEmitter, AfterViewInit } from '@angular/core';

@Component({
    selector: 'my-component',
    templateUrl: './mycomponent.html'
})
export class MyComponent implements AfterViewInit {
   @Output() initialized: EventEmitter<MyComponent> = new EventEmitter<MyComponent>();

   ngAfterViewInit(): void {
        this.initialized.emit(this);
   }

   reload(): void {
        // Do something
   }
}


// somecomponent.html => component with <ng-template> holding MyComponent

<ng-template>
    <div class="btn-group ml-2">
      <my-component (initialized)="onMyComponentInitialized($event)"></my-component>
    </div>
</ng-template>


// somecomponent.ts => component with <ng-template> holding MyComponent
import { Component, OnDestroy } from '@angular/core';
import { MyComponent } from '../../my-component';

@Component({
    selector: 'some-component',
    templateUrl: './some-component.html'
})
export class SomeComponent implements OnDestroy {
    private _myComponent: MyComponent = null;

    onMyComponentInitialized(component: MyComponent) {
        this._myComponent = component;
    }

    someOtherMethod() {
        if (this._myComponent) {
            // Call some method on the component
            this._myComponent.reload();
        }
    }

    ngOnDestroy() {
        this._myComponent = null;
    }
}
1