У меня возникает очень странная проблема с маршрутизацией Angular 2 туда, где мой ngOnInit
в компоненте, к которому я направляюсь, вызывается дважды, а маршрут в браузере получает reset к оригиналу маршрут.
У меня есть NotificationListComponent
и a NotificationEditComponent
в MaintenanceModule
.
В моем корневом AppModule
я настраиваю RouterModule
для перенаправления любых немаршрутизированных маршрутов на /maintenance/list
.
app.module.ts
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpModule,
RouterModule.forRoot([
{path: "", redirectTo: "maintenance/list", pathMatch: "full"},
{path: "**", redirectTo: "maintenance/list", pathMatch: "full"}
], {useHash: true}),
CoreModule.forRoot({notificationUrl: "http://localhost:8080/notification-service/notifications"}),
MaintenanceModule
],
providers: [NotificationService],
bootstrap: [AppComponent]
})
export class AppModule { }
И у меня есть маршрут /maintenance/list
, определенный в моем MaintenanceModule
, который указывает на мой NotificationListComponent
, а также маршрут /maintenance/edit/:id
, который указывает на мой NotificationEditComponent
.
maintenance.module.ts
@NgModule({
imports: [
CommonModule,
RouterModule.forChild([
{path: "maintenance/list", component: NotificationListComponent, pathMatch: 'full'},
{path: "maintenance/edit/:id", component: NotificationEditComponent, pathMatch: 'full'}
]),
FormsModule
],
declarations: [
NotificationListComponent,
NotificationEditComponent
]
})
export class MaintenanceModule {}
Когда мое приложение загружается, оно правильно следует по маршруту /maintenance/list
, и я могу видеть все мои уведомления в списке. Для каждого уведомления в списке есть значок редактирования, который имеет событие click
, связанное с методом edit(id: number)
в моем NotificationListComponent
уведомление-list.component.ts
@Component({
templateUrl: 'notification-list.component.html'
})
export class NotificationListComponent implements OnInit {
notifications: Notification[];
errorMessage: string;
constructor(private _notificationService: NotificationService,
private _router: Router) {}
ngOnInit(): void {
this._notificationService.getNotifications()
.subscribe(
notifications => this.notifications = notifications,
error => this.errorMessage = <any>error);
}
clearError(): void {
this.errorMessage = null;
}
}
уведомительный list.component.html
<div class="row">
<h1>Notification Maintenance</h1>
<div *ngIf="errorMessage" class="alert-box alert">
<span>{{errorMessage}}</span>
<a class="right" (click)="clearError()">×</a>
</div>
<p-dataTable [value]="notifications" [sortField]="'code'" [responsive]="true" [sortOrder]="1" [rows]="10" [paginator]="true" [rowsPerPageOptions]="[10,50,100]">
<p-header>Available Notifications</p-header>
<p-column [field]="'code'" [header]="'Code'" [sortable]="true" [style]="{'width':'10%'}"></p-column>
<p-column [field]="'name'" [header]="'Name'" [sortable]="true" [style]="{'width':'40%'}"></p-column>
<p-column [field]="'roles'" [header]="'Roles'" [style]="{'width':'40%'}"></p-column>
<p-column [field]="'notificationId'" [header]="'Edit'" [style]="{'width':'10%'}">
<template let-row="rowData" pTemplate="body">
<a [routerLink]="'/maintenance/edit/' + row['notificationId']"><span class="fa fa-pencil fa-2x"></span></a>
</template>
</p-column>
</p-dataTable>
</div>
Как вы можете видеть, метод edit(id: number)
должен перейти к маршруту /maintenance/edit/:id
. Когда я нажимаю значок, чтобы перейти к этому маршруту, браузер мигает правильным маршрутом в адресной строке (например, localhost:4200/#/maintenance/edit/2
), но затем маршрут в адресной строке немедленно возвращается обратно к localhost:4200/#/maintenance/list
. Даже если маршрут был возвращен в /maintenance/list
в адресной строке, мой NotificationEditComponent
все еще отображается в фактическом приложении. Тем не менее, я вижу, что метод ngOnInit
вызывается дважды в моем NotificationEditComponent
, потому что id
дважды записывается в консоль, и если я помещаю точку останова в функцию ngOnInit
, она попадает в эту точку останова в два раза.
уведомление-edit.component.ts
@Component({
templateUrl: "notification-edit.component.html"
})
export class NotificationEditComponent implements OnInit{
notification: Notification;
errorMessage: string;
constructor(private _notificationService: NotificationService,
private _route: ActivatedRoute,
private _router: Router) {
}
ngOnInit(): void {
let id = +this._route.snapshot.params['id'];
console.log(id);
this._notificationService.getNotification(id)
.subscribe(
notification => this.notification = notification,
error => this.errorMessage = <any>error
);
}
}
Это также вызывает другие проблемы, поскольку при попытке привязать значения input
к значениям в моем NotificationEditComponent
, используя, например, [(ngModel)]="notification.notificationId"
, значение не отображается на экране, хотя я могу см. с расширением Augury chrome, а также регистрацию объекта на консоли, чтобы значение было заполнено компонентом.
уведомительный edit.component.html
<div class="row">
<h1>Notification Maintenance</h1>
<div *ngIf="errorMessage" class="alert-box alert">
<span>{{errorMessage}}</span>
<a class="right" (click)="clearError()">×</a>
</div>
<p-fieldset [legend]="'Edit Notification'">
<label for="notificationId">ID:
<input id="notificationId" type="number" disabled [(ngModel)]="notification.notificationId"/>
</label>
</p-fieldset>
</div>
Кто-нибудь знает, почему это происходит?
Update:
Я удалил свои вызовы на NotificationService
и заменил их только некоторыми макетными данными, а затем маршрутизация начала работать! Но как только я добавляю вызовы к моему сервису, я получаю ту же самую проблему, которую я описал выше. Я даже удалил CoreModule
и просто добавил службу непосредственно к моему MaintenanceModule
и по-прежнему получал ту же проблему, когда я использую фактическую услугу, а не только макет данных.
notification.service.ts
@Injectable()
export class NotificationService {
private _notificationUrl : string = environment.servicePath;
constructor(private _http: Http) {
}
getNotifications(): Observable<Notification[]> {
return this._http.get(this._notificationUrl)
.map((response: Response) => <Notification[]>response.json())
.catch(this.handleGetError);
}
getNotification(id: number): Observable<Notification> {
return this._http.get(this._notificationUrl + "/" + id)
.map((response: Response) => <Notification>response.json())
.catch(this.handleGetError);
}
postNotification(notification: Notification): Observable<number> {
let id = notification.notificationId;
let requestUrl = this._notificationUrl + (id ? "/" + id : "");
return this._http.post(requestUrl, notification)
.map((response: Response) => <number>response.json())
.catch(this.handlePostError);
}
private handleGetError(error: Response) {
console.error(error);
return Observable.throw('Error retrieving existing notification(s)!');
}
private handlePostError(error: Response) {
console.error(error);
return Observable.throw('Error while attempting to save notification!');
}
}
И сервис работает нормально - я вижу, что конечная точка успешно возвращает данные, и я вижу, что данные выглядят корректно, когда я смотрю на мой NotificationEditComponent
с расширением Chrome. Но данные не отображаются в шаблоне, а маршрут в URL-адресе возвращается к /maintenance/list
, хотя шаблон для маршрута /maintenance/edit/:id
все еще отображается.
Обновление 2:
Как было предложено @user3249448, я добавил следующее в мой AppComponent
для некоторой отладки:
constructor(private _router: Router) {
this._router.events.pairwise().subscribe((event) => {
console.log(event);
});
}
Вот результат этого, когда я нажимаю на одну из ссылок "edit":