23

我有 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());
}
}

应用模块.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 时,我没有一个可行的解决方案,但在一些空闲时间我会在这里发布更新。

4

8 回答 8

11

请尝试在组件中添加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);
           }
    });
}
于 2017-06-02T14:47:15.950 回答
5

作为一般规则,在路由时,角度路由器将尽可能重用组件的相同实例。

因此,例如,从 导航/component/1/component/2,其中 url 映射到相同的组件(但具有不同的参数)将导致路由器在导航到时实例化 Component 的实例,/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);    
}

编辑

我看到一段奇怪的代码:

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再次调用)

于 2017-06-03T10:50:54.267 回答
4

当您的组件与路由链接时,最好在构造函数中添加您的代码以订阅 ActivatedRoute 参数并强制更改检测,例如:

constructor(private route: ActivatedRoute, private changeDetector: ChangeDetectorRef) {
    super();
    this.route.params.subscribe((data) => {
    */update model here/*
    this.changeDetector.detectChanges();
   } 
}
于 2018-01-18T07:41:18.957 回答
4

我认为发生的情况是您的路由调用在 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']));
       }  
     );
}

于 2019-03-30T18:12:44.113 回答
4

在EmployeesComponent 中添加以下行

ionViewWillEnter(){
  this.ngOnInit();
}

重定向后会手动调用ngOnInit

于 2019-11-19T06:48:33.500 回答
1

如果您降级 @angular/router@4.1.3 似乎在 routerLink 上工作,如果您导航它将触发 ngOnInit

于 2017-11-20T01:09:40.263 回答
1

确保你<route-outlet></route-outlet>在 app.component.html 里面。这应该适用于最新版本的 Angular 5。

于 2018-02-07T22:27:59.923 回答
0

1.导入要导航的组件

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

2.将组件添加到要导航的构造函数中

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);
          });
于 2019-07-11T06:59:08.910 回答