Reputation: 24450
I have these two route definitions, product list and product detail:
{
name: "product",
url: "/product",
component: ProductListComponent,
resolve: [
{
token: "Products",
deps: [ApiService],
resolveFn: (api: ApiService) => api.getProducts().toPromise()
}
]
},
{
name: "product.detail",
url: "/:productcode",
component: ProductDetailComponent,
resolve: [
{
token: "Product",
deps: [Transition, ApiService],
resolveFn: (transition: Transition, api: ApiService) =>
api.getProduct(transition.params().productcode).toPromise()
}
]
}
Inside the product list component I have a set of radio buttons to indicate which product is selected, while the ui-view displays the product detail component:
<div *ngFor="let product of Products" class="radio">
<label>
<input [(ngModel)]="SelectedProduct"
[value]="product"
(change)="RefreshDetail()"
name="selectedProduct"
type="radio">
{{product.Name}} {{product.Code}}
</label>
</div>
<ui-view></ui-view>
When the user clicks the radio button, the URL, the product detail component, and the radio button are synchronized correctly.
But when the user goes directly to a certain product URL, the URL and product detail component display the correct product, but the radio button doesn't. What I mean by going directly to a certain product URL is the user inputs the URL to the browser address bar and press enter.
I tried to get the value of :productcode
from the Transition object in ngOnInit:
ngOnInit() {
let prodcode = this.transition.params().productcode;
this.SelectedProduct = !!prodcode
? this.Products.find(product => product.Code == prodcode)
: null;
}
It works for browser refresh, the right product is selected in the radio button. But doesn't work on browser back button, no radio buttons are selected. (maybe because this parent state is not reinitialized?)
Anyway I'm not sure that this is the idiomatic way to get the parameter values of a child state.
What is the proper way to set component property value based on child state parameter value?
Upvotes: 0
Views: 433
Reputation: 8216
UI-Router Rx extensions provide a stream of transitions and parameters. In your component, subscribe to the param stream and update the SelectedProduct
@Component({})
class {
private sub;
constructor(router: UIRouter) {
this.sub = router.globals.params$.subscribe(params => {
this.SelectedProduct = params.productcode;
});
}
ngOnDestroy() {
this.sub.unsubscribe();
}
}
The Rx Extensions are already included in @uirouter/angular
Upvotes: 2
Reputation: 77
You need to implements the Resolver
. You can have a look here :
https://angular.io/api/router/Resolve
The Resolve perform route data retrieval before route activation. So you can assign & manage your data before anything else happen.
This is mine resolver when certain actions are called :
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<something> {
return this.myService.getTitle(route.params[something.property])
.do(result => {
if (result && !!Object.keys(result).length) {
//action to update what you want
} else {
this.notificationsService.addNotification(<Notification>{
text: this.localizationKeys.deletedOrNotExisting,
type: MessageColorType.warning
});
this.router.navigate([...])]);
// tell the router where to go if there is any error
}
});
}
You can Inject a service in your component that keeps track about every change and use it to get access to your child parameter. As the resolver's logic is called even if you don't do a refresh, you can add few line of code to 'save' your current state.
Upvotes: -1