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