簡體   English   中英

在 router.navigate 之后未調用 Angular 4 ngOnInit

[英]Angular 4 ngOnInit not called after router.navigate

我有 3 個選項卡,其中一個選項卡顯示一個包含員工列表的表格。 第一次加載時效果很好。 ngOnInit 使用 http get 從服務器獲取數據。 之后,當我單擊添加新員工以打開一個表單,該表單接受用戶的輸入並單擊該提交時,我調用一個函數,該函數調用 http post 服務將該數據發布到我的服務器,並在其中插入記錄,然后在此之后它被重定向回員工組件,但現在員工組件已經加載,除非我重新編譯我的代碼,否則我看不到我插入表中的新記錄。

employee.component.ts(加載員工表)

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']); }  
    );

}
}

員工服務.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,它在組件第一次加載時完美加載。 當我提交表單時,它會轉到我的 API,然后它會被重定向回員工組件,但數據並未按應有的方式更新。

PS:我很抱歉這么小的帖子。 我是這個網站的新手。

更新 :

自從我發布此主題以來已經一年多了,我看到很多人從中受益,也可能沒有。 但是我想指出的是,我已經了解導致錯誤的原因,現在我將嘗試讓您了解解決方案。

在這里適應的最重要的概念是 Angular Life Cycle Hooks 發生的情況是,我們在第一次加載組件時調用 ngOnInit 並且這只會在 angular 應用程序啟動時觸發一次。 這類似於類構造函數,但它只觸發一次。 所以你不應該在這里做任何與 DOM 相關的修改。 你應該了解 Angular Life Cycle Hooks 來解決這個問題。 自過去 8 個月以來,我搬到了 Vuejs,因此我沒有一個可行的解決方案,但在一些空閑時間我會在這里發布更新。

請嘗試在employee組件中添加router事件。 這樣每次路由/employee url 狀態時,它都會獲取員工詳細信息。

員工.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);
           }
    });
}

作為一般規則,在路由時,角度路由器將盡可能重用組件的相同實例。

因此,例如,從/component/1導航到/component/2 ,其中 url 映射到相同的組件(但具有不同的參數)將導致路由器在導航到/component/1時實例化 Component 的實例,然后在導航到/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);    
}

編輯

我看到一段奇怪的代碼:

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']); }  
    );

  }
}

但總的來說,您是說如果您導航到您的員工組件,然后導航到您的表單組件,然后返回您的員工組件,當您第二次點擊員工組件時,您的員工列表不會刷新。

您可以使用console.log語句來確保在上面的屏幕流中多次調用ngOnInit嗎? 因為,根據您的路由器配置,當您導航到員工列表以形成並返回時,您的員工組件應該重新初始化(通過再次調用ngOnInit

我認為發生的情況是您的路由調用在 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']));
       }  
     );
}

在EmployeesComponent中添加以下行

ionViewWillEnter(){
  this.ngOnInit();
}

它會在重定向后手動調用 ngOnInit

當您的組件與路由鏈接時,最好在訂閱 ActivatedRoute 參數並強制更改檢測的構造函數中添加您的代碼,例如:

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

如果你降級 @angular/router@4.1.3 似乎在 routerLink 上工作,如果你導航它會觸發 ngOnInit

確保在 app.component.html 中有<route-outlet></route-outlet> 這應該適用於最新版本的 Angular 5。

1.導入要導航的組件

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

2.將組件添加到要導航的constructor

constructor( private Comp: SampleComponent){}

3.在需要導航的地方添加此代碼

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

eg.員​​工插入后重定向到員工列表頁面

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM