web-dev-qa-db-fra.com

Angular 4 ngOnInit non appelé après router.navigate

J'ai 3 onglets dans lesquels un onglet affiche un tableau avec la liste des employés. Fonctionne bien lorsqu'il est chargé la première fois.ngOnInit Récupère les données du serveur à l'aide de http get. Après cela, lorsque je clique sur Ajouter un nouvel employé pour ouvrir un formulaire, qui prend l'entrée de l'utilisateur et lorsque cette soumission est cliquée, j'appelle une fonction qui appelle le service de publication http pour publier ces données sur mon serveur où il insère les enregistrements, puis après cela il est redirigé vers le composant employé, mais maintenant que le composant employé était déjà chargé, je ne peux pas voir le nouvel enregistrement que j'ai inséré dans le tableau, sauf si je recompile mon code.

employee.component.ts (qui charge la table des employés)

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 { }

Le problème est que j'appelle mon API à partir de ngOnInit qui se charge parfaitement la première fois que le composant se charge. Lorsque je soumets le formulaire, il va à mon API, puis il est redirigé vers le composant employé, mais les données ne sont pas mises à jour comme il se doit.

P.S: Je suis désolé pour ce petit message. Je suis un peu nouveau sur ce site.

Mise à jour :

Cela fait plus d'un an maintenant que j'ai posté ce fil et je vois que beaucoup de gens en bénéficient ou peut-être pas. Cependant, je voudrais souligner que j'ai déjà compris la cause de l'erreur et je vais maintenant essayer de vous faire comprendre la solution.

Le concept le plus important à adapter ici est le Angular Life Cycle Hooks . Ce qui se passe, c'est que nous appelons ngOnInit la première fois qu'un composant est chargé et cela ne se déclenchera qu'une seule fois lorsque l'application angular est amorcée. Ceci est similaire à un constructeur de classe mais il ne se déclenche qu'une seule fois. Vous ne devez donc pas mettre ici de modifications liées au DOM. Vous devez comprendre Angular Life Cycle Hooks pour résoudre ce problème. Je n'ai pas de solution de travail avec moi car j'ai déménagé à Vuejs depuis 8 mois mais dans un certain temps libre je posterai une mise à jour ici.

16
Viral Patel

Veuillez essayer d'ajouter l'événement router dans le composant employee. Pour que chaque fois que /employee l'état url est routé, il récupérera les détails de l'employé.

composant 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

En règle générale, lors du routage, le routeur angular réutilisera la même instance d'un composant s'il le peut.

Ainsi, par exemple, la navigation à partir de /component/1 à /component/2, où l'url est mappée au même composant (mais avec des paramètres différents), le routeur instanciera une instance de Component lorsque vous accédez à /component/1, puis réutilisez cette même instance lorsque vous accédez à /component/2. D'après ce que vous décrivez (où ngOnInit n'est appelé qu'une seule fois), il semble que c'est ce que vous rencontrez. C'est difficile à dire avec certitude, sans voir vos modèles et la configuration de votre itinéraire. Je sais que vous dites que votre URL passe de /employees à /form, mais cela peut ne pas avoir d'importance, selon la configuration de vos modèles et de la configuration de l'itinéraire. Vous pouvez publier ce code (vos modèles et la configuration du routeur) ici pour examen si vous le souhaitez.

Sauf cela, une autre option est que le routeur expose tous ses événements sous forme de flux. Ainsi, vous pouvez vous abonner à ce flux et agir en conséquence, plutôt que de simplement compter sur ngOnInit.

Dans votre employé.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);    
}

MODIFIER

Je vois un morceau de code bizarre:

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

  }
}

Mais dans l'ensemble, vous dites que si vous accédez à votre composant employé, puis à votre composant de formulaire, puis à votre composant employé, lorsque vous appuyez sur le composant employé la deuxième fois, votre liste d'employés n'est pas actualisée.

Peux tu utiliser console.log instructions pour vous assurer que ngOnInit est appelé plusieurs fois dans votre flux d'écran ci-dessus? Parce que, en fonction de la configuration de votre routeur, lorsque vous accédez à la liste des employés à former et inverser, votre composant employé doit être réinitialisé (en appelant à nouveau ngOnInit)

3
snorkpete

Lorsque votre composant est lié à une route, mieux vaut ajouter votre code dans le constructeur en vous abonnant aux paramètres ActivatedRoute et en forçant la détection des changements, par exemple:

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

Assurez-vous que vous avez <route-outlet></route-outlet> dans app.component.html. Cela devrait très bien fonctionner avec la dernière version de Angular 5.

1
Nizar B.

Ce que je pense que cela se produit, c'est que votre appel d'itinéraire est en dehors du cycle de vie Angular parce que vous effectuez un appel asynchrone correctement?

Vérifiez d'abord si votre journal affiche quelque chose comme ceci:

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

Si c'est le cas, la solution est vraiment simple, vous devez dire à Angular d'appeler votre directive de routage à l'intérieur de leur cycle de vie.

Le code suivant devrait résoudre votre problème:

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

Si vous rétrogradez @ angular/router @ 4.1.3 semble fonctionner où sur routerLink si vous naviguez, cela déclenchera ngOnInit

1
Rey Ramos

1. composant d'importation à parcourir

par exemple. import { SampleComponent} from './Sample.component';

2.Ajouter un composant au constructeur à naviguer

constructor( private Comp: SampleComponent){}

3.Ajouter ce code où vous devez naviguer

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

ex. Après l'employé Insérez-le redirige vers la page de liste des employés

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