Angular 2:ngOnInit在尝试从id为的url开始渲染模板时被调用



我正在开发一个角度应用程序,该应用程序使用从AppComponent链接到多个组件的路由器。这里有一个关于plunker的简化版本来说明这个问题(出于某种原因,完全相同的代码在本地运行,但在plunker上没有。)

当应用程序从http://localhost:3000http://localhost:3000/home启动时,链接fruit1fruit2工作正常(单击会导致URL更改为带有描述文本的http://localhost:3000/fruit/1)。然而,问题是,当在这个url http://localhost:3000/fruit/1上启动时(键入这个url并点击回车),似乎对fruit-detail.component.tsngOnInit内的服务的调用是在尝试呈现其html组件后调用的,这导致了下面的堆栈跟踪:

EXCEPTION: TypeError: Cannot read property 'description' of null in [ desc: {{fruit.description}}  in FruitDetailComponent@1:6]
angular2.dev.js:23925 EXCEPTION: TypeError: Cannot read property 'description' of null in [ desc: {{fruit.description}}  in FruitDetailComponent@1:6]BrowserDomAdapter.logError @ angular2.dev.js:23925BrowserDomAdapter.logGroup @ angular2.dev.js:23936ExceptionHandler.call @ angular2.dev.js:1320(anonymous function) @ angular2.dev.js:12857schedulerFn @ angular2.dev.js:13264SafeSubscriber.__tryOrUnsub @ Rx.js:10775SafeSubscriber.next @ Rx.js:10730Subscriber._next @ Rx.js:10690Subscriber.next @ Rx.js:10667Subject._finalNext @ Rx.js:11191Subject._next @ Rx.js:11183Subject.next @ Rx.js:11142EventEmitter.emit @ angular2.dev.js:13245NgZone._zoneImpl.ng_zone_impl_1.NgZoneImpl.onError @ angular2.dev.js:13666NgZoneImpl.inner.inner.fork.onHandleError @ angular2.dev.js:2143ZoneDelegate.handleError @ angular2-polyfills.js:394Zone.runGuarded @ angular2-polyfills.js:300NgZoneImpl.runInner @ angular2.dev.js:2155NgZone.run @ angular2.dev.js:13749(anonymous function) @ angular2.dev.js:12956schedulerFn @ angular2.dev.js:13264SafeSubscriber.__tryOrUnsub @ Rx.js:10775SafeSubscriber.next @ Rx.js:10730Subscriber._next @ Rx.js:10690Subscriber.next @ Rx.js:10667Subject._finalNext @ Rx.js:11191Subject._next @ Rx.js:11183Subject.next @ Rx.js:11142EventEmitter.emit @ angular2.dev.js:13245NgZone._checkStable @ angular2.dev.js:13689NgZone._zoneImpl.ng_zone_impl_1.NgZoneImpl.setMicrotask @ angular2.dev.js:13660NgZoneImpl.inner.inner.fork.onHasTask @ angular2.dev.js:2135ZoneDelegate.hasTask @ angular2-polyfills.js:449ZoneDelegate._updateTaskCount @ angular2-polyfills.js:466ZoneDelegate.invokeTask @ angular2-polyfills.js:427Zone.runTask @ angular2-polyfills.js:320drainMicroTaskQueue @ angular2-polyfills.js:541ZoneTask.invoke @ angular2-polyfills.js:493
angular2.dev.js:23925 ORIGINAL EXCEPTION: TypeError: Cannot read property 'description' of nullBrowserDomAdapter.logError @ angular2.dev.js:23925ExceptionHandler.call @ angular2.dev.js:1329(anonymous function) @ angular2.dev.js:12857schedulerFn @ angular2.dev.js:13264SafeSubscriber.__tryOrUnsub @ Rx.js:10775SafeSubscriber.next @ Rx.js:10730Subscriber._next @ Rx.js:10690Subscriber.next @ Rx.js:10667Subject._finalNext @ Rx.js:11191Subject._next @ Rx.js:11183Subject.next @ Rx.js:11142EventEmitter.emit @ angular2.dev.js:13245NgZone._zoneImpl.ng_zone_impl_1.NgZoneImpl.onError @ angular2.dev.js:13666NgZoneImpl.inner.inner.fork.onHandleError @ angular2.dev.js:2143ZoneDelegate.handleError @ angular2-polyfills.js:394Zone.runGuarded @ angular2-polyfills.js:300NgZoneImpl.runInner @ angular2.dev.js:2155NgZone.run @ angular2.dev.js:13749(anonymous function) @ angular2.dev.js:12956schedulerFn @ angular2.dev.js:13264SafeSubscriber.__tryOrUnsub @ Rx.js:10775SafeSubscriber.next @ Rx.js:10730Subscriber._next @ Rx.js:10690Subscriber.next @ Rx.js:10667Subject._finalNext @ Rx.js:11191Subject._next @ Rx.js:11183Subject.next @ Rx.js:11142EventEmitter.emit @ angular2.dev.js:13245NgZone._checkStable @ angular2.dev.js:13689NgZone._zoneImpl.ng_zone_impl_1.NgZoneImpl.setMicrotask @ angular2.dev.js:13660NgZoneImpl.inner.inner.fork.onHasTask @ angular2.dev.js:2135ZoneDelegate.hasTask @ angular2-polyfills.js:449ZoneDelegate._updateTaskCount @ angular2-polyfills.js:466ZoneDelegate.invokeTask @ angular2-polyfills.js:427Zone.runTask @ angular2-polyfills.js:320drainMicroTaskQueue @ angular2-polyfills.js:541ZoneTask.invoke @ angular2-polyfills.js:493
angular2.dev.js:23925 ORIGINAL STACKTRACE:BrowserDomAdapter.logError @ angular2.dev.js:23925ExceptionHandler.call @ angular2.dev.js:1332(anonymous function) @ angular2.dev.js:12857schedulerFn @ angular2.dev.js:13264SafeSubscriber.__tryOrUnsub @ Rx.js:10775SafeSubscriber.next @ Rx.js:10730Subscriber._next @ Rx.js:10690Subscriber.next @ Rx.js:10667Subject._finalNext @ Rx.js:11191Subject._next @ Rx.js:11183Subject.next @ Rx.js:11142EventEmitter.emit @ angular2.dev.js:13245NgZone._zoneImpl.ng_zone_impl_1.NgZoneImpl.onError @ angular2.dev.js:13666NgZoneImpl.inner.inner.fork.onHandleError @ angular2.dev.js:2143ZoneDelegate.handleError @ angular2-polyfills.js:394Zone.runGuarded @ angular2-polyfills.js:300NgZoneImpl.runInner @ angular2.dev.js:2155NgZone.run @ angular2.dev.js:13749(anonymous function) @ angular2.dev.js:12956schedulerFn @ angular2.dev.js:13264SafeSubscriber.__tryOrUnsub @ Rx.js:10775SafeSubscriber.next @ Rx.js:10730Subscriber._next @ Rx.js:10690Subscriber.next @ Rx.js:10667Subject._finalNext @ Rx.js:11191Subject._next @ Rx.js:11183Subject.next @ Rx.js:11142EventEmitter.emit @ angular2.dev.js:13245NgZone._checkStable @ angular2.dev.js:13689NgZone._zoneImpl.ng_zone_impl_1.NgZoneImpl.setMicrotask @ angular2.dev.js:13660NgZoneImpl.inner.inner.fork.onHasTask @ angular2.dev.js:2135ZoneDelegate.hasTask @ angular2-polyfills.js:449ZoneDelegate._updateTaskCount @ angular2-polyfills.js:466ZoneDelegate.invokeTask @ angular2-polyfills.js:427Zone.runTask @ angular2-polyfills.js:320drainMicroTaskQueue @ angular2-polyfills.js:541ZoneTask.invoke @ angular2-polyfills.js:493
angular2.dev.js:23925 TypeError: Cannot read property 'description' of null
    at AbstractChangeDetector.ChangeDetector_FruitDetailComponent_0.detectChangesInRecordsInternal (viewFactory_FruitDetailComponent:30)
    at AbstractChangeDetector.detectChangesInRecords (angular2.dev.js:9689)
    at AbstractChangeDetector.runDetectChanges (angular2.dev.js:9672)
    at AbstractChangeDetector._detectChangesInViewChildren (angular2.dev.js:9751)
    at AbstractChangeDetector.runDetectChanges (angular2.dev.js:9676)
    at AbstractChangeDetector._detectChangesContentChildren (angular2.dev.js:9745)
    at AbstractChangeDetector.runDetectChanges (angular2.dev.js:9673)
    at AbstractChangeDetector._detectChangesInViewChildren (angular2.dev.js:9751)
    at AbstractChangeDetector.runDetectChanges (angular2.dev.js:9676)
    at AbstractChangeDetector.detectChanges (angular2.dev.js:9661)

之后,它会被记录到控制台,这就是为什么我怀疑ngOnInit在之后被调用的原因。那么,当直接从"水果/1"url加载时,如何拥有一个可用的应用程序呢?感谢您的帮助!谢谢

===== extract data called!!
fruit-detail.component.ts:25 got fruit inside fruitComponent !apple

您可以使用elvis运算符进行以下操作:

<h2> desc: {{fruit?.description}} </h2>

事实上,调用this._foodService.getData()是异步执行的,并且在ngOnInit方法返回后会得到结果。

由于您使用路由,我认为OnActivate接口及其routerOnActivate方法正是您想要的。如果在该方法中返回promise,则组件将等待promise得到解析,然后再更改路由。因此,当组件显示时,数据将在那里,您不会有这样的问题。

这是一个示例:

@Component({
  (...)
})
export class FruitDetailComponent implements OnInit, OnActivate {
  fruit = null;
  constructor(
    private _rbacService: FoodService,
    private _routeParams: RouteParams) {}
  routerOnActivate(next: ComponentInstruction,
                   prev: ComponentInstruction) {
    return new Promise(resolve => {
      let id = +this._routeParams.get('id');
      console.log('on init fruit component: id = '+id);
      //get read write roles
      this._rbacService.getData().subscribe(data =>{
        this.fruit = data['fruits'].filter(obj => obj.id === id)[0];
        console.log('got fruit inside fruitComponent '+this.fruit.description);
        resolve(null);
      })
    });
  }
}

有关更多详细信息,请参阅此链接:

  • https://angular.io/docs/ts/latest/api/router/OnActivate-interface.html

最新更新