How to make Angular 2 render the HTML template after the promise in the component is resolved?

In my ItemDetailComponent app, ItemDetailComponent information will be displayed. I have a service that retrieves all items using a promise. I use ActivatedRoute to retrieve the item id from the url, then start the service, get all the items, then find the item with the id obtained above and assign it to the selectedItem variable.

Here is the item-detail.component.ts :

 export class ItemDetailComponent implements OnInit { private title = 'Item Details' private selectedItem: object constructor( private route: ActivatedRoute, private itemService: ItemService ) {} ngOnInit() { const selectedItemId = this.route.snapshot.params.itemId return this.itemService.getAllItems() .then((items) => { return _.find(items, item => item.itemId === selectedItemId) }) .then((selectedItem) => { this.selectedItem = selectedItem console.log('Inside promise', this.selectedItem) }) console.log('Outside promise', this.selectedItem) } } 

And here is the item-detail.component.html template so that I can display my element, just an example:

 <div> <h1>{{title}}</h1> <div *ngIf="selectedItem"> <div><label>Item ID: </label>{{selectedItem.itemId}}</div> </div> </div> 

The application does not return anything except the name. Then I added two console.log() commands and found out that outside the promise, as well as the html template are displayed before the promise is fulfilled, and at the time there is no selectedItem . How to make the application fulfill them only after the promise is resolved to show the selectedItem for display?

EDIT . I added a new line to the html template for further study:

 <div> <h1>{{title}}</h1> <div><label>Item ID 1: </label>{{selectedItem.itemId}}</div> <div *ngIf="selectedItem"> <div><label>Item ID 2: </label>{{selectedItem.itemId}}</div> </div> </div> 

The application displays the label "Item ID 1:", but without the actual identifier. The console shows me an error saying that "It is not possible to read the" itemId "property from undefined, again confirming that the entire template is rendered before the promise is resolved and is not re-displayed after the data has been loaded. So strange.

+5
source share
4 answers
+2
source

Add a boolean variable to your class, e.g.

personal data is available: boolean = false;

and in a promise subscription to make it true when data is available

 then((selectedItem) => { this.selectedItem = selectedItem; this.dataAvailable=true; console.log('Inside promise', this.selectedItem) }) 

and in template visualization when data is available

 <div> <h1>{{title}}</h1> <div *ngIf="dataAvailable"> <div><label>Item ID: </label>{{selectedItem.itemId}}</div> </div> </div> 

He has to do the trick.

0
source

Update

ngOnInit() seems to be just an event handler handler - returning something will not affect anything. So my old answer will not work.

There are other ways: * ngIf or put it in routes, etc., but I'm sorry that there was something like resolvePromise(): Promise hook, which would set the resolution condition before rendering.

This is instead of developers installing a template in each component.

Old answer

Most likely, this is because in the second then the return statement is missing.

then((selectedItem) => { this.selectedItem = selectedItem console.log(): return selectedItem;// }

0
source

Is it possible that the ChangeDetection parameter is set to OnPush somewhere up the component tree? If so, the template is not automatically overwritten, because nothing triggers ChangeDetection for this component.

Look at the component with the changeDetection: ChangeDetectionStrategy.OnPush setting changeDetection: ChangeDetectionStrategy.OnPush

 @Component({ selector: 'example', template: `...`, styles: [`...`], changeDetection: ChangeDetectionStrategy.OnPush }) 

You already have a valid solution using Resolver , you can check if this helps:

 export class ItemDetailComponent implements OnInit { private title = 'Item Details' private selectedItem: object constructor( private route: ActivatedRoute, private itemService: ItemService, // the reference to the components changeDetector is needed. private changeDetectorRef: ChangeDetectorRef ) {} ngOnInit() { const selectedItemId = this.route.snapshot.params.itemId return this.itemService.getAllItems() .then((items) => { return _.find(items, item => item.itemId === selectedItemId) }) .then((selectedItem) => { this.selectedItem = selectedItem // this triggers the changedetection and the template should be rerendered; this.changeDetectorRef.detectChanges(); console.log('Inside promise', this.selectedItem) }); console.log('Outside promise', this.selectedItem) } } 

Here is a great article on Angulars ChangeDetection: https://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html

0
source

Source: https://habr.com/ru/post/1270955/


All Articles