What do I want to achieve
I want to update my current view based on an Id. So say that I have side navigation with the following tabs:
Customer A
Customer B
Customer C
What I want is that the user can click on Customer A and that the current customer view gets updated based on the Customer Id.
What is my problem achieving this
I thought the best way to solve this issue was to navigate to the page and provide the Id directly as follows:
router.navigateToRoute("customer", { currentCustomerId });
Then on the Customer page I am receiving the Id in the activate method as following:
public activate(params) {
this.currrentCustomerId = params.currentCustomerId;
}
Actually, this is working the first time you navigate to a customer. But when I am clicking on another Customer page, the view does not get updated because the activate method does not get triggered for a second time. It is only working if I navigate to another page (not customer page) and go back or simply refresh the whole page.
So what can I use to achieve what I want? I reckon that I have to use something else than activate()?
I appreciate it if someone could give me some insight into this issue.
Regards.
This is due to the default activation strategy wherein, if the URL only changes in terms of a parameter value, the component is reused and hooks are not invoked.
To obtain the desired behavior, you can customize the this behavior at the component level or the route level.
At the component level:
import {activationStrategy} from 'aurelia-router';
export class CustomerComponent {
determineActivationStrategy() {
return activationStrategy.replace;
}
activate(params: {currrentCustomerId: string}) {
this.currentCustomerId = params.currentCustomerId;
}
}
At the route level:
import {Router, RouterConfiguration} from 'aurelia-router';
export class App {
configureRouter(config: RouterConfiguration, router: Router) {
config.map([{
name: 'customer',
moduleId: './customer',
route: 'customer/:currentCustomerId',
activationStrategy: 'replace'
}]);
this.router = router;
}
}
Related
I have a "settings" page in my react app. The page has several tabs rendering different parts of settings.
It would be better UX if a user can share urls with other users.
What I want is (inside "settings" page):
user A clicks a tab
url changes with a #tabname appended
user A send that url to user B, and user B open that url
user B sees the same tab as user A
But with react router, the whole page re-renders if the url changed:
import { withRouter } from "react-router-dom"
const MyComp = (props) => {
...
const onTabChange = () => {
// append #tabname here
props.history.replace(...); // or `push`
...
}
...
export default withRouter(MyComp)
}
After a lot of searches, I found a solution to use window.history:
const onTabChange = () => {
window.history.pushState(null, null, "#tabname");
...
}
This does the trick, but little information and explanation, and I'd love to know the consequences of using this trick.
Is this a valid solution (for a react app)? Will this cause any problem?
(PS. I know how to parse a url)
More details:
To be more specific, there is a AuthChecker wrapper for all pages. When react router's location changes, it checks for the route's allowed auths and current user's auth.
I've tried /path/:id and everything but all change location, so auth checked and page rerendered.
And I've given up a solution in react router and just want to know: is it safe to change url with window.history in a react app using react router to manage routes?
this question is already answerd at this post.
so it says window has a property called history and there is a method on history which helps you update the history state without react-router-dom understanding it.
like this:
window.history.replaceState(null, 'New Page Title', '/new_url');
For some pages of my app I have navigateRoot which redirects users based on conditions but the problem of that is when user redirects to destination pages they'll lose ability of using back button.
Example
If I use route links/buttons in my views I can use routerDirection="forward" in order to activate back button for users but in this case I'm not sure how I can use route direction
Code
const addToko = this.addToko.value;
this.storeService.store(
addToko.name,
).subscribe(
data => {
this.alertService.presentToast(data['message']);
this.navCtrl.navigateRoot('/toko'); <-- redirect user here
},
error => {
this.alertService.presentToast(error['message']);
}
);
Now as this redirects are condition based I prefer to have static route for back button, sample logic below:
1- if user no have store, redirect to intro page
2- (here intro no have back button - based on sample code above)
3- if user used back button in intro page go to profile page.
any idea?
well...
Going Root means that all existing pages in the stack will be removed...
so... If u don't want that u can use the regular router from '#angular/router' and setDirection as shown in that image
first u need to import { Router } from '#angular/router';
constructor (private router: Router) {}
and use it. like that:
const addToko = this.addToko.value;
this.storeService.store(
addToko.name,
).subscribe(
data => {
this.alertService.presentToast(data['message']);
this.navCtrl.setDirection('root');
this.router.navigate('/toko'); // this should be the same without delete all ... i hope it helped,
},
error => {
this.alertService.presentToast(error['message']);
}
);
IF ur using ionic version 4 follow this method
Normal page redirect
your page is parent.ts u gonna redirect to child page
this.router.navigate(['\child'])
If u pass data with redirect use this method
parent.ts
let navigationExtras: NavigationExtras = {
state: {
user: this.user
}
};
this.router.navigate(['child'], navigationExtras);
}
child.ts
data: any;
constructor(private route: ActivatedRoute, private router: Router) {
this.route.queryParams.subscribe(params => {
if (this.router.getCurrentNavigation().extras.state) {
this.data = this.router.getCurrentNavigation().extras.state.user;
}
});
}
I have a page that has a form that checks if the user has unsaved changes before navigating away from it.
The problem is that even with a preventDefault() and return false, the user is still able to click away from the component.
Is there a way to prevent the ngOnDestroy or click event from happening?
Note: User is not going to a different route, just another tab from the same component.
ngOnDestroy() {
if (this.myForm.dirty) {
let save = confirm('You are about to leave the page with unsaved changes. Do you want to continue?');
if (!save) {
window.event.preventDefault();
return false;
}
}
}
You would wanna use CanDeactivate guard.
Here is an example:
1. Create a guard service/provider.
import { Injectable } from '#angular/core';
import { CanDeactivate } from '#angular/router';
import { Observable } from 'rxjs/Observable';
export interface CanComponentDeactivate {
canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;
}
#Injectable()
export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> {
canDeactivate(component: CanComponentDeactivate) {
return component.canDeactivate ? component.canDeactivate() : true;
}
}
2. Add your guard service (CanDeactivateGuard) in your app.module providers
providers: [
CanDeactivateGuard,
]
3. Update your routing, to something like this:
{
path: "pipeline/:id",
component: OnePipelineComponent,
canDeactivate: [CanDeactivateGuard],
},
4. Implement canDeactivate method in your component where you want to prevent ngOnDestroy. In my case, it was OnePipelineComponent as mentioned in the route above.
canDeactivate() {
console.log('i am navigating away');
// you logic goes here, whatever that may be
// and it must return either True or False
if (this.user.name !== this.editName) {
return window.confirm('Discard changes?');
}
return true;
}
Note: Follow steps 1 & 2 only once, obviously, & just repeat steps 3 & 4 for every other component where you want the same behaviour, meaning, to
prevent ngOnDestroy or to do something before a
component can be destroyed).
Check out these articles for code sample & an explanation for the code written above. CanDeactivate & CanDeactivate Guard Example
You are mixing two concepts - navigating away means to a new route. The correct angular solution to this is implementing a CanDeactivateGuard. The docs on that are here.
A stack overflow question with answers is here.
In your situation the user is not navigating to a new page (ie. the route does not change). They are simply clicking on a new tab.
Without seeing more code, it's hard to know if both tabs are part of the same form or in two different forms.
But regardless, you need a click handler on the other tab button and in THAT click handler you need to check if the data for the current tab is unsaved (ie. if that tab is one single form, is that form dirty?).
So basically move the code you posted from ngOnDestroy and into that click handler.
I have a situation in Angular 4.0.3 where I have two <router-outlet>'s on a page.
<router-outlet></router-outlet>
<router-outlet name="nav"></router-outlet>
The first outlet will accept routes for content, and the second will accept routes for navigation. I achieve the navigation using this;
router.navigate(['', {outlets: { nav: [route] } }],{skipLocationChange: true });
This changes the outlet's contents without updating the URL - since I don't want any url that look like .. (nav:user).
The problem is the remaining outlet. I do want the URL to update when those are clicked, for instance ...
.../user/profile
Functionally, I can get both outlets to have the proper content, but it keeps appending the nav outlet's route to the url, like this ...
.../user/profile(nav:user)
Is there any way I can stop it from adding the (nav:user) part?
Unless there is some trick I'm not aware of ... I don't think you can. The address bar is what maintains the route state. So without the secondary outlet information in the address bar, the router won't know how to keep the correct routed component in the secondary outlet.
You could try overriding the navigateByUrl method as shown here: http://plnkr.co/edit/78Hp5OcEzN1jj2N20XHT?p=preview
export class AppModule { constructor(router: Router) {
const navigateByUrl = router.navigateByUrl;
router.navigateByUrl = function(url: string|UrlTree, extras: NavigationExtras = {skipLocationChange: false}): Promise<boolean> {
return navigateByUrl.call(router, url, { ...extras, skipLocationChange: true });
} } }
You could potentially add logic here then to check which routes you need to do this on.
Use Case
The user can access certain parts of my site without being logged in. If they click a download button and are logged in, the download starts automatically. However, if they click the download button and are not logged in, I'd like to prompt them to login. Once they're logged in, I'd like them to be sent straight back to the route they were previously on.
How I'm trying to accomplish it
When an "anonymous" user clicks a download button, they're given a modal with a prompt to login. If they decide to login, I'll stash some object in local storage (was thinking an ActivatedRouterSnapshot would do?). After login, I'll check to see if there's an object stored under stashedRoute in local storage. If there is, I'll use it to navigate them back to their original route!
What I want to do
Given:
import { Router } from '#angular/router';
and
private someRoute: ActivatedRouterSnapshot;
constructor(private _router: Router) {}
I want to:
this._router.navigate(someRoute)
The question
What is the syntax for either doing the above, or getting the same functionality for storing a route and re-navigating to it?
i think you need some thing like a history for going back in routes
you can use code below as described here
import {Component} from '#angular/core';
import {Location} from '#angular/common';
#Component(...)
class AppCmp {
constructor(private _location: Location) {
}
backClicked() {
this._location.back();
}
}
I had a similar issue and solved it by the following. flatten is from lodash and route is your ActivatedRoute. It's not great, but it works for now. You might want to use flattenDeep instead to accommodate for deeply nested routes.
const route = flatten(route.pathFromRoot.map(r => r.url)).map(s => s.path);
this.router.navigate(route);