2017-03-09 21 views
11

Angular 2ルーティングで、私がルーティングしているコンポーネントのngOnInitが2度呼び出され、ブラウザのルートが元のルート。Angular2ルーティングの問題とngOnInitが2回呼び出されました

私はMaintenanceModuleNotificationListComponentNotificationEditComponentを持っています。

私のルートAppModuleには、マップされていないルートを/maintenance/listにリダイレクトするようにRouterModuleを設定しました。

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

そして私は私のNotificationListComponentで指して、私のMaintenanceModuleで定義されて/maintenance/listルート、だけでなく、私のNotificationEditComponentで指し示す/maintenance/edit/:idルートを持っています。

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ルートをたどる、と私はリストに私の通知のすべてを見ることができます。

@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; 
    } 
} 

通知リスト:リスト内の各通知について、私のNotificationListComponent

通知list.component.tsedit(id: number)メソッドにバインドされたそのclickイベントがあり、編集アイコンがあり、

<div class="row"> 
    <h1>Notification Maintenance</h1> 

    <div *ngIf="errorMessage" class="alert-box alert"> 
    <span>{{errorMessage}}</span> 
    <a class="right" (click)="clearError()">&times;</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)方法はに移動する必要があります .component.html /maintenance/edit/:idルート。アイコンをクリックしてそのルートに移動すると、ブラウザでアドレスバーの正しいルートが点滅します(例:localhost:4200/#/maintenance/edit/2)。アドレスバーのルートはすぐにlocalhost:4200/#/maintenance/listに戻ります。アドレスバーの/maintenance/listにルートが返されたにもかかわらず、私のNotificationEditComponentは実際のアプリケーションで引き続き表示されます。しかし、私はメソッドがNotificationEditComponentで2回呼び出されていることがわかります。idがコンソールに2回記録され、ngOnInit関数にブレークポイントを置くと、そのブレークポイントに2回ヒットします。

通知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 
    ); 
    } 
} 

これはまた、たとえば[(ngModel)]="notification.notificationId"のために、使用して私のNotificationEditComponentの値にinput値をバインドしようとしたときので、値を他の問題を引き起こしているように見えます私はAuguryクロム拡張で見ることができますが、コンソールにオブジェクトを記録するだけでなく、コンポーネントに値が入力されているにもかかわらず、画面に表示されません。

notification-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()">&times;</a> 
    </div> 

    <p-fieldset [legend]="'Edit Notification'"> 
    <label for="notificationId">ID: 
     <input id="notificationId" type="number" disabled [(ngModel)]="notification.notificationId"/> 
    </label> 
    </p-fieldset> 

</div> 

誰もこれが起きてしまう理由を任意のアイデアを持っていますか?

更新:

私は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!'); 
    } 
} 

そしてサービスが正常に動作しているようだ - 私は、エンドポイントが正常にデータを返し、私は私を見たときに、データが正しく表示されていることを見ることができることがわかりますにはAuguryクロムの拡張子が付きます。ただし、テンプレートにデータが表示されず、ルートのテンプレートが表示されていても、URLのルートは/maintenance/listに戻ります。

アップデート2:

@ user3249448によって示唆されるように、私はいくつかのデバッグのための私のAppComponentに次を追加しました:私は「編集のいずれかをクリックしたときにここで

constructor(private _router: Router) { 
    this._router.events.pairwise().subscribe((event) => { 
    console.log(event); 
    }); 
} 

は、その出力であります「リンク:

Route logging

+0

最新のAngular2バージョンを使用していますか?しばらく前にこの問題が発生しましたが、しばらく前にAFAIRで修正されました。 –

+0

ワイルドカードルートを削除して問題が解決するかどうかを確認してください。私はワイルドカードルートについて最後にリストに載っている必要があることを読んでいることを覚えています。 – wolfhoundjesse

+0

私は** 2.4.8 **と '@ angular/router'バージョン** 3.4.8 **を使用しています。ワイルドカードルートがなくても、問題は引き続き発生します。 –

答えて

5

@ user3249448からデバッグヘルプを入手した後で、最終的に問題を解決することができました。

私はエラーがコンソールにログインしていないされていたにもかかわらず、このNavigationErrorを得ていたが判明:私、だから、基本的に

TypeError: Cannot read property 'notificationId' of undefined 
    at CompiledTemplate.proxyViewClass.View_NotificationEditComponent0.detectChangesInternal (/MaintenanceModule/NotificationEditComponent/component.ngfactory.js:487:49) 
    at CompiledTemplate.proxyViewClass.AppView.detectChanges (http://localhost:4200/vendor.bundle.js:80125:14) 
    at CompiledTemplate.proxyViewClass.DebugAppView.detectChanges (http://localhost:4200/vendor.bundle.js:80320:44) 
    at CompiledTemplate.proxyViewClass.AppView.internalDetectChanges (http://localhost:4200/vendor.bundle.js:80110:18) 
    at CompiledTemplate.proxyViewClass.View_NotificationEditComponent_Host0.detectChangesInternal (/MaintenanceModule/NotificationEditComponent/host.ngfactory.js:29:19) 
    at CompiledTemplate.proxyViewClass.AppView.detectChanges (http://localhost:4200/vendor.bundle.js:80125:14) 
    at CompiledTemplate.proxyViewClass.DebugAppView.detectChanges (http://localhost:4200/vendor.bundle.js:80320:44) 
    at ViewRef_.detectChanges (http://localhost:4200/vendor.bundle.js:60319:20) 
    at RouterOutlet.activate (http://localhost:4200/vendor.bundle.js:65886:42) 
    at ActivateRoutes.placeComponentIntoOutlet (http://localhost:4200/vendor.bundle.js:24246:16) 
    at ActivateRoutes.activateRoutes (http://localhost:4200/vendor.bundle.js:24213:26) 
    at http://localhost:4200/vendor.bundle.js:24149:58 
    at Array.forEach (native) 
    at ActivateRoutes.activateChildRoutes (http://localhost:4200/vendor.bundle.js:24149:29) 
    at ActivateRoutes.activate (http://localhost:4200/vendor.bundle.js:24123:14) 

:ここ

enter image description here

は、完全なスタックトレースでしたテンプレートがレンダリングされる前に私のWebサービスへの呼び出しが返され、notificationundefinedだったのでテンプレートを正しくレンダリングできなかったので、私はこれを得ましたNavigationError、上記の動作が発生しました(AppComponentに追加のデバッグコードを追加しなくてもこのエラーがコンソールに記録されるようには見えません)。

この問題を解決するには、*ngIfをに追加し、notificationに関するすべての情報が含まれている必要があります。

<p-fieldset [legend]="'Edit Notification'" *ngIf="notification"> 

データがWebサービスから返されると、テンプレートが正しく読み込まれます。

+0

無料のヒント、elvis演算子を使用することもできますhttp://stackoverflow.com/questions/34833358/angular-2-typeerror-l-thing0-is-undefined-in-thing-title-in-appcomponent/34833436#34833436 –

+0

公式のドキュメントはこちら:https://angular.io/docs/ts/latest/guide/template-syntax.html#!#safe-navigation-operator –

0

私の推測では、あなたのブラウザは、実際のLiなど、あなたの編集リンクを解釈していることだろうあなたがしたいことをするのではなくこれは、フラッシュが見えるという事実に基づいています - ブラウザが問題のリンクを訪れようとしているように聞こえます。

通知リストでクリックした項目を変更して、アンカータグから簡単なスパンまたはdivに通知を編集してみてください。あなたがフラッシュを取得しない場合、あなたはあなたの問題だったことを知っている。

+0

いいえ、divに変更しても機能しませんでした。実際のページが点滅するわけではありません。ページは実際に(入力に正しくバインドされていないモデル以外の)編集テンプレートを正しくレンダリングします。実際のページに編集テンプレートが表示されたまま、正しい編集ルートに点滅してからリストルートに戻るのはアドレスバーだけです。 –

関連する問題