新しいコンポーネントResultComponent
を作成しようとしていますが、そのngOnInit()
メソッドが2回呼び出されており、なぜこれが発生するのかわかりません。コードでは、ResultComponent
は親コンポーネント@Input
からmcq-component
を継承します。
コードは次のとおりです。
親コンポーネント(MCQComponent)
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'mcq-component',
template: `
<div *ngIf = 'isQuestionView'>
.....
</div>
<result-comp *ngIf = '!isQuestionView' [answers] = 'ansArray'><result-comp>
`,
styles: [
`
....
`
],
providers: [AppService],
directives: [SelectableDirective, ResultComponent]
})
export class MCQComponent implements OnInit{
private ansArray:Array<any> = [];
....
constructor(private appService: AppService){}
....
}
子コンポーネント(result-comp)
import { Component, OnInit, Input } from '@angular/core';
@Component({
selector:'result-comp',
template: `
<h2>Result page:</h2>
`
})
export class ResultComponent implements OnInit{
@Input('answers') ans:Array<any>;
ngOnInit(){
console.log('Ans array: '+this.ans);
}
}
実行すると、console.log
が2回表示されます。1回目は正しい配列を表示し、2回目はundefined
を表示します。私はそれを理解することができませんでした:ngOnInit
in ResultComponent
が2回呼び出されるのはなぜですか?
現在、コンポーネントのコンテンツ/ビューの子の変更の検出中にエラーが発生した場合、ngOnInitが2回呼び出されます(DynamicChangeDetectorで表示)。これにより、元のエラーを隠すフォローアップエラーが発生する可能性があります。
この情報は、これに基づいています github issue
したがって、あなたの間違いは、このコンポーネントに関連するコードの他の場所にOriginを持っているようです。
これは、コンポーネントHTMLの欠陥のために私に起こっていました。 Hostコンポーネントのセレクタータグを閉じるのを忘れていました。 <search><search>
の代わりに<search></search>
がありました-構文エラーに注意してください。
@dylanの回答に関連して、コンポーネントのHTML構造とその親の構造を確認してください。
私の場合の問題は、子コンポーネントをブートストラップする方法でした。 my@ NgModuleデコレータのメタデータオブジェクトでは、 'child componentを渡していました'bootstapプロパティと'parent component ' bootstapプロパティで子コンポーネントを渡すことはresetting子コンポーネントpropertiesおよびOnInit()が2回発生しました。
@NgModule({
imports: [ BrowserModule,FormsModule ], // to use two-way data binding ‘FormsModule’
declarations: [ parentComponent,Child1,Child2], //all components
//bootstrap: [parentComponent,Child1,Child2] // will lead to errors in binding Inputs in Child components
bootstrap: [parentComponent] //use parent components only
})
app.module.tsでplatformBrowserDynamic().bootstrapModule(AppModule);
を使用した場合は、コメントして試してください。同じ問題がありました。これが役立つと思う
誰かがここにくる場合に備えて、これをここに置きます。ブラウザのデフォルトボタンタイプが「送信」の場合、NgOnInitを2回呼び出すこともできます。たとえば、以下がある場合、ChromeではNextComponentのNgOnInitが2回呼び出されます。
<button class="btn btn-primary" (click)="navigateToNextComponent()">
修正するには、タイプを設定します:
<button class="btn btn-primary" type="button" (click)="navigateToNextComponent()">
これは、AppComponent
をデフォルトルートとして設定したために発生する可能性があります
RouterModule.forRoot([
{ path: '', component: AppComponent } // remove it
])
注:AppComponent
はデフォルトでangular
で呼び出されるため、呼び出す必要はありません
ngOnInit()
は、すべてのディレクティブがインスタンス化された後に一度だけフックします。サブスクリプションinsidengOnInit()
があり、サブスクリプションが解除されていない場合、サブスクライブされたデータが変更されると、再度実行されます。
次のStackblitzの例では、ngOnInit()
内にサブスクリプションがあり、結果をコンソールします。一度読み込まれ、データが変更され、再び読み込まれるため、2回コンソールになります。
これは、テンプレートエラーがある場合に常に発生します。
私の場合、間違ったテンプレート参照を使用し、それを修正して問題を修正しました。
これは、<router-outlet>
の中に*ngFor
sという名前を付けていないために起こりました。ループの各反復でロードされました。
その場合の解決策は、各アウトレットに一意の名前を付けるか、DOMに一度に1つだけ(たとえば[*ngIf
)が1つだけ存在するようにすることです。
私の場合、これはコンポーネントがOnChangesとOnInitの両方を実装しているときに起こります。これらのクラスのいずれかを削除してください。 ngAfterViewInitメソッドを使用することもできます。これは、ビューが初期化された後にトリガーされるため、1回呼び出されることが保証されます。
私にとって、これはRouteで同じコンポーネントを2回登録したために起こりました。
{
path: 'meal-services',
children: [
{
path: '',
component: InitTwiceComponent,
canActivate: [AppVendorOpsGuard],
data: { roleWhitelist: [UserRoles.Manage] }
},
{
path: ':itemID',
component: InitTwiceComponent,
canActivate: [AppVendorOpsGuard],
data: { roleWhitelist: [UserRoles.Manage] }
}]
},
}
私自身も同様の問題を抱えていました。コンポーネントを要求し、ルーターアウトレットを介して同じコンポーネントを参照していました。
<layout>
<router-outlet></router-outlet>
</layout>
そして、アウトレットルートもレイアウトを指していました。
私の場合、ngOnInit内にあったすべてのサブスクリプションのサブスクリプションを解除しませんでした。 ngOnDestroy内のすべてのサブスクリプションからnsubscribedを取得しただけで、問題は解決しました。