Is it possible to check access via URL or Click? - javascript

Is there some way to identify when some route is access by event (like Click) or URL?
I need to block access when it's called by URL.
Example: if I type "www.example.com/shop/:id" redirect to "www.example.com/shop", only pass if I'm clicking in some button on "www.example.com/shop" view
{
path: 'shop',
children: [
{path: '', component: ShopListComponent},
{path: ':id', component: ShopViewComponent}
]
}

If that's the feature you want to achieve, then in principle using URL and router to display individual items is wrong.
URL is supposed to be resource locator and should represent some application state.
URLs can be shared and bookmarked to return to the location you were before.
To not break this principle and user expectations you should simply load an item in your view without using router.
However, if you insist on using router and simply preventing opening URL via address bar, then you should implement Route Guard with CanActivate interface.
But how are you going to detect if user opened item via click?
One approach would be using service and tracking on which item user clicked on.
For example in your component
onClick(itemId) {
this.itemNavService.allowNavigatingToItem(itemId);
this.router.navigate(['/shop', itemId]);
}
Then in your Route Guard:
#Injectable()
class CanOpenItem implements CanActivate {
constructor(private itemNavService: ItemNavService) {}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean|UrlTree>|Promise<boolean|UrlTree>|boolean|UrlTree {
return this.itemNavService.canActivate(route.params.id);
}
}
and your service could be something like:
#Injectable()
class ItemNavService {
allowNavigatingTo = null;
allowNavigatingToItem(itemId) {
this.allowNavigatingTo = itemId;
}
canActivate(itemId) {
return this.allowNavigatingTo === itemId;
}
}

Related

Not able to push data to data layer on each page in angular 9

I am trying to add GTM snippet to my angular project. But on hard reload of page it's pushing data. On normal navigation it doesn't.
I have added GTM snippet provided by Google to index.html. what is the next step I need to do?
What I want is push dta to dataLayer on each page navigation or on Ngonit of each page?
there are a lot of implemented angular modules which are wrapping interaction with GTM and provide some tools, for instance this one https://www.npmjs.com/package/angular-google-tag-manager
here is how you can push event on each route change
class AppComponent implements OnInit {
constructor(
private router: Router,
private gtmService: GoogleTagManagerService,
) { }
ngOnInit() {
this.router.events.subscribe(event=> {
if (event instanceof NavigationEnd) {
const gtmTag = {
event: 'page',
pageName: event.url
};
this.gtmService.pushTag(gtmTag);
}
});
}
}
also, you can move this logic to Guard (do not forget in such case to add it for routing)

How to refresh a component declared in HTML everytime its parent component is visited using the same URL?

For example, I have 2 components, A and B.
In A.component.html there is code as follow
<B></B>
A is accessed via router, and I want B to be refreshed, by calling B's ngOnInit(), everytime A is visited, even with the same URL.
I have
set onSameUrlNavigation: 'reload' in RouterModule.forRoot
runGuardsAndResolvers: 'always' in A's path
subscribe to router.events in B's constructor as shown below
this.navigationSubscription = this.router.events.subscribe((e: any) => {
if (e instanceof NavigationEnd) {
this.ngOnInit();
}
});
But it doesn't work. B is not refreshed.
I guess that is because B is NOT accessed via router directly but as a child of A?
Then how to refresh B everytime A is visited?
Thanks in advance!
This can be done using onSameUrlNavigation.
you can Define what the router should do if it receives a navigation request to the current URL.
app.module.ts
#NgModule({
imports: [RouterModule.forRoot(routes, { onSameUrlNavigation: 'reload' })]
})
class MyNgModule {}
Now,Inject your router
app.component.ts
import { Router } from '#angular/router';
constructor(private router: Router) {
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
}
DEMO
More Detail
I don’t think onnginit is suppose to be called directly. Avoid that.
Would listening to this.router.events.subscribe inside B solve the problem?
If not, use a service to share data between them. Inside the service you could have a subject that B could subscribe to. On navigation in A you trigger the subject
It turned out that the problem is in the Apollo GraphQL library.
It was using cache so no request was made toward BE...

Aurelia/TS Activate does not update current view

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;
}
}

Ionic route navigator

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;
}
});
}

Angular 4 - update route without appending another outlet's route to URL

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.

Categories