In my Aurelia view-model, I am trying to check some precondition, in canActivate()
, and based on that it is decided whether navigate to a different view or not.
export class ThisView{
canActivate() {
const self = this;
const promise = self.services.get(url)
.then((items: any) => {
if (items) {
self.items= items;
if (self.items.length === 1) {
this.router.navigate("some/other/view");
//return false;
}
//return true;
} else {
self.logger.error("No item found");
//return false;
}
});
return promise;
}
}
Now even though I am navigating to some/other/view
if there is only one item found, view of ThisView
still gets activated (ie can be seen in browser).
Is there a way, to avoid that? There couple of things I tried for this.
true
, or false
from promise
to accept, or reject activation of this view. But as this view is kind of landing page of my application, if rejected (returned false) it tries to restore the previous location, which is not available, and throws an error. And restoring a previous location is also not desired by the application for this specific case.next.cancel(new Redirect("some/other/view"))
, where we can instruct to cancel the current navigation instruction with a new one. But I am not sure how to do the same from a view-model.Please suggest.
Workaround: I have finally used a simple trick of using if.bind
on view of ThisView
. However, it could have been more interesting, if we can somehow cancel the current instruction (from page lifecycle) with a new one.
instead of this.router.navigate("some/other/view) can you not import redirect and add the redirect in there, ie
import {Redirect} from 'aurelia-router';
export class ThisView{
canActivate() {
const self = this;
var items = self.services.get(url);
if(items){
self.items= items;
if (self.items.length === 1) {
return new Redirect("some/other/view");
}
return true;
}
else {
self.logger.error("No item found");
return new Redirect("not-found-view");
}
}
}
I've made a basic GistRun showing how this works - I haven't used a promise, but I believe the concept is the same.
You can use activate()
event to process router navigation. Throw error to stop navigation or goto/redirect to another location. Example:
import {Router} from 'aurelia-router';
export class SampleModel {
static inject() { return [Router] };
constructor(router) {
this.router = router;
}
activate(){
if(this.somedata === null){
// stop navigation or goto start location
if(this.router.history.previousLocation){
// stop from navigation
throw new Error('Wrong data');
}else{
// return to start page
this.router.navigate('start');
}
}
}
}
You could also inject some middleware in the router pipeline the same way authorization steps are done.
You would then call your service in a particular step and route to a different view depending on the result.
Some code snippets on how steps are added to the router pipeline can be found here: Aurelia: During a Router's Pipeline Step, how do I bind a variable to that router?
I figured out another way to handle navigation in canActive()
canActivate(params, routeConfig, navigationInstruction) {
return new Promise((resolve, reject) => {
this.api.request(params.id).then(result => {
if (result) {
resolve(true);
} else {
toastr.error('Invalid URL');
reject(navigationInstruction.router.navigate('/xxx'));
}
}).catch(error => {
toastr.error('Request error');
resolve(false);
});
});
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.