web-dev-qa-db-ja.com

Angular 4 ngOnInitはrouter.navigateの後に呼び出されません

3つのタブがあり、そのうちの1つのタブには従業員のリストを含むテーブルが表示されます。 ngOnInitは、http getを使用してサーバーからデータを取得します。その後、新しい従業員の追加をクリックしてフォームを開き、ユーザーからの入力を受け取り、その送信をクリックすると、http postサービスを呼び出す関数を呼び出して、データをサーバーに投稿し、レコードを挿入してから従業員コンポーネントにリダイレクトされますが、従業員コンポーネントが既にロードされているため、コードを再コンパイルしない限り、テーブルに挿入した新しいレコードを見ることができません。

employee.component.ts(employeeテーブルをロードします)

import { Component, OnInit, OnDestroy } from '@angular/core';
import { EmployeeService } from '../employee.service';
@Component({
  selector: 'app-employees',
  templateUrl: './employees.component.html',
  styleUrls: ['./employees.component.css']
})
export class EmployeesComponent implements OnInit {

public employeeObj:any[] = [{emp_id:'',empname:'',joindate:'',salary:''}] ;
constructor(private employeService:EmployeeService) { }

ngOnInit() {    
this.employeService.getEmployees().subscribe(res => this.employeeObj = res);
}

}

form.component.ts

import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
import { EmployeeService } from '../../employee.service';
import { Router } from '@angular/router';

@Component({
    selector: 'app-form',
    templateUrl: './form.component.html',
    styleUrls: ['./form.component.css'],

})
export class FormComponent implements OnInit {
empform;

ngOnInit() { 
this.empform = new FormGroup({
    empname: new FormControl(""),
    joindate: new FormControl(""),
    salary: new FormControl("")
})
} 
constructor(private employeeService: EmployeeService, private router:Router) 
{ }

 onSubmit = function(user){
    this.employeeService.addEmployee(user)
    .subscribe(
        (response) => { this.router.navigate(['/employees']); }  
    );

}
}

employee.service.ts

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import 'rxjs/add/operator/map';
import 'rxjs/Rx';
@Injectable()
export class EmployeeService{
constructor(private http:Http){}
addEmployee(empform: any[]){
    return this.http.post('MY_API',empform);
}

getEmployees(){
    return 
this.http.get('MY_API').map((response:Response)=>response.json());
}
}

AppModule.ts

    import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ReactiveFormsModule } from '@angular/forms';

import { HttpModule } from '@angular/http';
import { RouterModule } from '@angular/router';
import { EmployeeService } from './employee.service';
import { AppComponent } from './app.component';
import { HeaderComponent } from './header/header.component';
import { NavComponent } from './nav/nav.component';
import { ContainerComponent } from './container/container.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import { EmployeesComponent } from './employees/employees.component';
import { CompaniesComponent } from './companies/companies.component';
import { InternsComponent } from './interns/interns.component';
import { FormComponent } from './employees/form/form.component';
import { ComformComponent } from './companies/comform/comform.component';
import { InternformComponent } from './interns/internform/internform.component';

@NgModule({
  declarations: [
    AppComponent,
    HeaderComponent,
    NavComponent,
    ContainerComponent,
    DashboardComponent,
    EmployeesComponent,
    CompaniesComponent,
    InternsComponent,
    FormComponent,
    ComformComponent,
    InternformComponent
  ],
  imports: [    
    BrowserModule,
    FormsModule,
    ReactiveFormsModule,
    HttpModule,
    RouterModule.forRoot([
            {
                path:'dashboard',
                component:DashboardComponent
            },
            {
                path:'employees',
                component:EmployeesComponent
            },
            {
                path:'companies',
                component:CompaniesComponent
            },
            {
                path:'interns',
                component:InternsComponent
            },
            {
                path:'addemployee',
                component:FormComponent
            },
            {
                path:'comform',
                component:ComformComponent
            },
            {
                path:'internform',
                component:InternformComponent
            }       
      ])
  ],
  providers: [EmployeeService],
  bootstrap: [AppComponent]
})
export class AppModule { }

問題は、ngOnInitからAPIを呼び出していることです。ngOnInitは、コンポーネントが初めてロードされたときに完全にロードされます。フォームを送信すると、APIに送信され、従業員コンポーネントにリダイレクトされますが、データは必要に応じて更新されません。

追伸:このような小さな投稿で申し訳ありません。私はこのウェブサイトにちょっと新しいです。

更新:

このスレッドを投稿してから1年以上が経ちましたが、多くの人がこのスレッドの恩恵を受けているかどうかはわかりません。しかし、エラーの原因をすでに理解していることを指摘したいと思います。解決策を理解できるようにしようと思います。

ここで適応する最も重要な概念はAngular Life Cycle Hooks です。何が起こるかというと、コンポーネントが最初にロードされるときにngOnInitを呼び出し、これは1回だけ起動しますangularアプリケーションがブートストラップされるとき。これはクラスコンストラクターに似ていますが、1回だけ起動します。したがって、DOM関連の変更をここに置かないでください。Angularこの問題を解決するためのライフサイクルフック過去8か月からVuejsに移行したため、有効な解決策はありませんが、空き時間にここに更新を投稿します。

16
Viral Patel

routerイベントをemployeeコンポーネントに追加してみてください。毎回/employee url状態がルーティングされ、従業員の詳細が取得されます。

employee.tsコンポーネント

constructor(private employeeService: EmployeeService, private router:Router) 
{ }

ngOnInit() {    
  this.router.events.subscribe(
    (event: Event) => {
           if (event instanceof NavigationEnd) {
                this.employeService.getEmployees().subscribe(res => this.employeeObj = res);
           }
    });
}
6
Amit Chigadani

一般的なルールとして、ルーティングする場合、angularルーターは可能な場合はコンポーネントの同じインスタンスを再利用します。

そのため、たとえば、/component/1から/component/2にナビゲートすると、URLが同じコンポーネントにマップされます(ただし、異なるパラメーターを使用)すると、/component/1を選択し、/component/2に移動したときに同じインスタンスを再利用します。あなたが説明していることに基づいて(ngOnInitは一度だけ呼び出されます)、これはあなたが遭遇していることのように見えます。あなたのテンプレートとルート設定を見ずに、確実に言うのは難しいです。 URLが/employeesから/formに変更されていることを知っていますが、テンプレートとルート構成の設定方法によっては、それは重要ではありません。必要に応じて、そのコード(テンプレートとルーター構成)をここに投稿して確認することができます。

それを除いて、別のオプションは、ルーターがすべてのイベントをストリームとして公開することです。したがって、単にngOnInitに依存するのではなく、そのストリームにサブスクライブして、それに基づいて行動できます。

employee.component.ts内

.....
export class EmployeesComponent implements OnInit {

.....

ngOnInit() {


   this.router.events
              // every navigation is composed of several events,
              // NavigationStart, checks for guards etc
              // we don't want to act on all these intermediate events,
              // we just care about the navigation as a whole,
              // so only focus on the NavigationEnd event
              // which is only fired once per router navigation
              .filter(e => e instanceof NavigationEnd)
              // after each navigation, we want to convert that event to a call to our API
              // which is also an Observable
              // use switchMap (or mergeMap) when you want to take events from one observable
              // and map each event to another observable 
              .switchMap(e => this.employeeService.getEmployees())
              .subscribe(res => this.employeeObj = res);    
}

[〜#〜] edit [〜#〜]

私は奇妙なコードの一部を見ています:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
import { EmployeeService } from '../../employee.service';
import { Router } from '@angular/router';

@Component({
    selector: 'app-form',
    templateUrl: './form.component.html',
    styleUrls: ['./form.component.css'],

})
export class FormComponent implements OnInit {
  empform;

  ngOnInit() { 
    this.empform = new FormGroup({
      empname: new FormControl(""),
      joindate: new FormControl(""),
      salary: new FormControl("")
    })
  } 

  constructor(private employeeService: EmployeeService, private router:Router) { }

 onSubmit(user){   // <--  change this line
    this.employeeService.addEmployee(user)
    .subscribe(
        (response) => { this.router.navigate(['/employees']); }  
    );

  }
}

しかし、全体的に言って、従業員コンポーネントに移動してからフォームコンポーネントに移動し、従業員コンポーネントに戻った場合、従業員コンポーネントに2回目に当たると、従業員リストは更新されません。

console.logステートメントを使用して、上記の画面フローでngOnInitが複数回呼び出されていることを確認できますか?ルーターの構成に基づいて、従業員リストに移動してフォームを作成したり戻したりするときに、従業員コンポーネントを再初期化する必要があります(ngOnInitを再度呼び出して)

3
snorkpete

コンポーネントがルートにリンクされている場合は、ActivatedRoute paramsにサブスクライブし、変更検出を強制するコンストラクターにコードを追加することをお勧めします。例:

constructor(private route: ActivatedRoute, private changeDetector: ChangeDetectorRef) {
    super();
    this.route.params.subscribe((data) => {
    */update model here/*
    this.changeDetector.detectChanges();
   } 
}
2
Anji K

<route-outlet></route-outlet> app.component.html内。これはAngular 5。

1
Nizar B.

私はそれが起こると思うのは、あなたがルート呼び出しがAngularライフサイクルの外側にあるということです。なぜなら、あなたは非同期呼び出しを正しくしているのですか?

まず、ログに次のようなものがあるかどうかを確認します。

WARN: 'Navigation triggered outside Angular zone, did you forget to call 'ngZone.run()'?'

これが事実である場合、ソリューションは本当にシンプルです。ライフサイクル内でルーティングディレクティブを呼び出すには、Angularを伝える必要があります。

次のコードで問題を修正する必要があります。

import { NgZone } from '@angular/core';
import { Router } from '@angular/router';

...
constructor(
    private employeeService: EmployeeService, 
    private router:Router,
    private ngZone: NgZone) { }

 onSubmit = function(user) {
   this.employeeService.addEmployee(user)
     .subscribe(
       (response) => { 
         this.ngZone.run(() =>
           this.router.navigate(['/employees']));
       }  
     );
}

1
Carlos Verdes

@ angular/router @ 4.1.3をダウングレードすると、routerLinkのどこで機能しているように見えますが、ナビゲートするとngOnInitがトリガーされます

1
Rey Ramos

1.ナビゲートされるコンポーネントをインポートする

例えば。 import { SampleComponent} from './Sample.component';

2.コンポーネントをナビゲートするコンストラクターに追加します

constructor( private Comp: SampleComponent){}

3.ナビゲートする必要がある場所にこのコードを追加します

this.Comp.ngOnInit();
this._router.navigate(['/SampleComponent']);--/SampleComponent-your router path

例:従業員の挿入後、従業員リストページにリダイレクトします

 this.service.postData(Obj)
          .subscribe(data => {
            (alert("Inserted Successfully"));
            this.Comp.ngOnInit();
            this._router.navigate(['/SampleComponent']);
          },
            error => {
              alert(error);
          });
0
Mali