[英]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.