Angular 4 ngOnInit не вызывается после router.navigate

У меня есть 3 вкладки, в одной из которых отображается таблица со списком сотрудников. Хорошо работает при первой загрузке .ngOnInit Получает данные с сервера, используя http get. После этого, когда я нажимаю добавить нового сотрудника, чтобы открыть форму, которая принимает ввод от пользователя, и когда эта отправка нажата, я вызываю функцию, которая вызывает почтовую службу http для публикации этих данных на моем сервере, где он вставляет записи, а затем после этого он перенаправляется обратно в компонент сотрудника, но теперь этот компонент сотрудника уже загружен, я не вижу новую запись, которую я вставил в таблицу, если я не перекомпилирую свой код.

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

}
}

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

Проблема в том, что я вызываю свой API из ngOnInit, который отлично загружается при первой загрузке компонента. Когда я отправляю форму, она попадает в мой API, а затем перенаправляется обратно в компонент сотрудника, но данные не обновляются должным образом.

P.S: Прошу прощения за такой небольшой пост. Я новичок на этом сайте.

Обновлять :

Прошло больше года с тех пор, как я разместил эту ветку, и я вижу, что многие люди получили от нее пользу, а может и нет. Однако я хотел бы отметить, что я уже понял, что вызвало ошибку, и теперь я постараюсь объяснить вам решение.

Самая важная концепция, которую нужно адаптировать, - это крючки жизненного цикла Angular. Что происходит, мы вызываем ngOnInit при первой загрузке компонента, и это сработает только один раз при загрузке приложения angular. Это похоже на конструктор класса, но срабатывает только один раз. Поэтому вам не следует размещать здесь какие-либо модификации, связанные с DOM. Вы должны понимать крючки жизненного цикла Angular, чтобы решить эту проблему. У меня нет рабочего решения, так как я перешел на Vuejs за последние 8 месяцев, но в свободное время я опубликую здесь обновление.


person Viral Patel    schedule 02.06.2017    source источник
comment
Мне понадобится код, братан   -  person Daniel Cooke    schedule 02.06.2017
comment
было бы здорово, если бы вы могли разместить здесь какой-нибудь плункер с демонстрацией этого поведения   -  person happyZZR1400    schedule 02.06.2017
comment
Я добавил код братан. Прошу прощения за то, что не сделал этого в первый раз. @DanielCooke   -  person Viral Patel    schedule 02.06.2017
comment
У меня похожая проблема. Конструктор тоже недоступен. Angular 5   -  person Bigeyes    schedule 13.06.2019


Ответы (8)


Попробуйте добавить событие 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);
           }
    });
}
person Amit Chigadani    schedule 02.06.2017
comment
return this.http.post('MY_API',empform) сам по себе не принесет вам результатов. Вы должны сопоставить результаты. angular.io/docs/ts/latest/guide/server-communication. html Обновите вопрос, если вы уже это сделали. - person Amit Chigadani; 02.06.2017
comment
Я сделал это, сэр. По-прежнему я не могу обновить компонент сотрудника. - person Viral Patel; 02.06.2017
comment
Да, сэр, именно так. Нет. Как мне показать вам мои файлы шаблонов? - person Viral Patel; 02.06.2017
comment
Обратите внимание: если ваш URL-адрес не изменится, пока ваш form компонент загружен, то employee компонент не будет обновлен, даже если вы сделаете router.navigate. - person Amit Chigadani; 02.06.2017
comment
Сэр, URL-адрес меняется с localhost: 4200 / employee на localhost: 4200 / form, а затем он снова меняется на localhost: 4200 / employee, когда я отправляю форму. - person Viral Patel; 02.06.2017
comment
Я пробовал использовать обновленный ответ, но вот что у меня получилось: prntscr.com/ffohfk - person Viral Patel; 04.06.2017
comment
Я добавил другой класс, теперь добавленный в соответствии с вашими рекомендациями, и теперь я получаю эту ошибку: Ошибка: Неподготовлено (в обещании): Ошибка: Нет поставщика для EmployeeService! Ошибка: нет провайдера для EmployeeService! Вот изображение: prntscr.com/ffovc0 - person Viral Patel; 04.06.2017
comment
Я сделал это, сэр, но теперь он не получает данные из созданного мной API. Вы хотите, чтобы я выложил все скриншоты файлов, сэр? - person Viral Patel; 04.06.2017
comment
Я больше не получаю никаких ошибок, сэр, но данные не обновляются, когда я перенаправляю их обратно из формы addemployee в компонент сотрудников с помощью router.navigate. - person Viral Patel; 04.06.2017
comment
Я получаю данные из API, сэр. Проблема в том, что когда я впервые открываю компонент сотрудников, который содержит весь список сотрудников, которые я добавил в базу данных, он показывает идеальный результат. Теперь, не выходя из приложения, я нажимаю кнопку «Добавить сотрудника», которая открывает страницу с формой, которая отправляет данные в другой мой API, который хранится в базе данных, а затем я перенаправляю их обратно в компонент сотрудника, но компонент сотрудника не отображает только что добавленный данные. Это главная проблема, сэр. - person Viral Patel; 04.06.2017
comment
Этот код работает ... но 'this.router.events.subscribe ((res: any) = ›{' вызывается несколько раз при изменении состояния. - person Anil Kumar; 16.01.2019
comment
Вам придется отказаться от подписки в течение ngOnDestroy() жизненного цикла. Так что когда компонент будет уничтожен, подписка будет убита - person Amit Chigadani; 16.01.2019
comment
Вы можете мне помочь ... Я пробовал это ngOnDestroy () {this.router.events.unsubscribe (); } .. но для типа Observable ‹Event›, показывающего свойство «Отказ от подписки», не существует. Вы имели в виду «подписаться»? ».. и при отладке ngOnDestroy () не вызывалась после изменений состояния - person Anil Kumar; 16.01.2019
comment
Это не способ отмены подписки на события маршрутизатора. Назначьте ему переменную подписки, скажем this.subRouter = this.router.events.subscribe(...), а затем выполните this.subRouter.unsubscribe() - person Amit Chigadani; 16.01.2019

Как правило, при маршрутизации угловой маршрутизатор будет повторно использовать один и тот же экземпляр компонента, если это возможно.

Так, например, переход от /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)

person snorkpete    schedule 03.06.2017
comment
Сэр, это решение тоже не работает. Показать выкладываю скриншоты всех файлов? - person Viral Patel; 04.06.2017
comment
Вы можете выложить код файлов. Какую ошибку вы получаете? - person snorkpete; 04.06.2017
comment
Да, сэр, вот скриншоты: Компонент сотрудника из таблицы загружен и получает данные из API: prntscr.com/ffzznd Компонент формы, который используется для вставки данных в базу данных с помощью API: prntscr.com/ffzzxs Служба файл, чтобы сделать http-сообщение и получить запрос к моему API: prntscr.com/fg006t - person Viral Patel; 05.06.2017
comment
Что-нибудь, сэр? Все еще не могу найти решения - person Viral Patel; 09.06.2017
comment
Еще раз, в чем ошибка? Кроме того, как правило, размещайте фактический код, а не снимки экрана. я не могу копировать, вставлять и настраивать примеры кода со снимка экрана, что очень затрудняет решение проблем в вашем коде - person snorkpete; 09.06.2017
comment
Кроме того, не могли бы вы опубликовать код для конфигурации вашего маршрутизатора? - person snorkpete; 09.06.2017
comment
Я добавлю весь код, сэр. Мне очень жаль, что я этого не сделал. - person Viral Patel; 09.06.2017
comment
Сэр, я обновил основную ветку. Спасибо за помощь, сэр. - person Viral Patel; 13.06.2017

Я думаю, что это происходит, когда ваш маршрутный вызов находится за пределами жизненного цикла 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']));
       }  
     );
}

person Carlos Verdes    schedule 30.03.2019
comment
Ты спасатель. У меня были проблемы с маршрутизатором, и я не заметил журнала предупреждений об Angular Zone. - person Alécio Gomes; 29.05.2019
comment
Я перешел на Ractive, Angular делает все действительно сложным и трудоемким, как если бы разработчики боролись против фреймворка. - person Carlos Verdes; 07.06.2019

добавьте следующую строку в EmployeesComponent

ionViewWillEnter(){
  this.ngOnInit();
}

он будет вручную вызывать ngOnInit после перенаправления

person Prasanth M P    schedule 19.11.2019

Когда ваш компонент связан с маршрутом, лучше добавить свой код в конструктор, подписавшись на параметры ActivatedRoute и принудительно обнаружив изменения, например:

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

Если вы переходите на более раннюю версию @ angular / router @ 4.1.3, похоже, работает там, где на routerLink, если вы перейдете, он вызовет ngOnInit

person Rey Ramos    schedule 20.11.2017

Убедитесь, что у вас есть <route-outlet></route-outlet> внутри app.component.html. Это должно нормально работать с последней версией Angular 5.

person Nizar B.    schedule 07.02.2018

1. импортировать компонент, по которому нужно перемещаться

eg. import { SampleComponent} from './Sample.component';

2.Добавьте компонент в конструктор для навигации

constructor( private Comp: SampleComponent){}

3. Добавьте этот код туда, где вам нужно перемещаться

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

например, после вставки сотрудника перенаправляет на страницу со списком сотрудников.

 this.service.postData(Obj)
          .subscribe(data => {
            (alert("Inserted Successfully"));
            this.Comp.ngOnInit();
            this._router.navigate(['/SampleComponent']);
          },
            error => {
              alert(error);
          });
person Mali    schedule 11.07.2019
comment
Требуется правильный отступ. - person surajs1n; 11.07.2019