Add Parameter to Angular 2 Route from Component without Navigating - javascript

With my current code I am attempting to do deep linking within my Accordion component.
By navigating to dev.local/#/accordion and then clicking on an accordion title, I want to update the route to look like:
dev.local/#/accordion/2
But I do not want to navigate to this path once it is set. Essentially, if someone were to hypothetically copy this URL it would return them to the exact accordion that was opened when they copied it.
The problem I'm running into is that I'm applying the following code to my accordion links to set the parameter:
<a [routerLink]="['Accordion',{tab:'4'}]"></a>
This works but it actually navigates and re-initializes the component. I need to be able to click this link, set the route to dev.local/#/accordion/4 without re-initializing the component by navigating to it.
Here are my current routes:
#RouteConfig([
{
path: '/accordion',
component: Accordion,
as: 'AccordionNew'
},
{
path: '/accordion/:tab',
component: Accordion,
as: 'Accordion'
}
]);

If the Aux Routes don't help, you can try my solution I used for a smiliar problem:
Build a RootAccordionComponent. Set a selector for your
AccordionComponent and use it as a tag in the RootAccordionComponent
template (e.g. ). Also place a somewhere in this template. For RootAccordionComponent you use "path: '/accordion/...'" RouteConfig.
(If not already done) build a AccordionService with a tabId attribute.
Build a TabIdAccordianComponent with an empty template. Use "path: '/accordion/:tab'" for it as RouteConfig. Now the only thing the component does, is to fetch the tabId from RouteParams and save it to the AccordionService.
When initializing your AccordianComponent, get the tabId from the AccordionService.
That way you can get the tabId when your AccordianComponent is initilized if someone goes directly to the url with an tabId, but it won't reload if the user clicks on an Accordian.
See this Plunker for a working example:
http://plnkr.co/edit/5HEgIUZGRP3Cfqh6LvzA?p=preview
If you launch the preview in a separate window you can also see the routes. E.g. if you load "http://run.plnkr.co/WOpQaPkFafJ7uU8Y/#/accordion/2" the selected Accordion will be set to 2.
Hope this helps, although it is not the cleanest solution.
RouteConfig to get to AccordionRoot:
#RouteConfig([
{path:'/accordion/...', name: 'AccordionRoot', component: AccordionRootComponent},
])
export class AppComponent { }
The actual AccordionRootComponent:
#Component({
template: `
<router-outlet></router-outlet>
<accordion-component></accordion-component>`,
directives: [ROUTER_DIRECTIVES, AccordionComponent]
})
#RouteConfig([
{ path: '/:tabId', name: 'AccordionTab', component: TabIdAccordionComponent, useAsDefault: true}
])
export class AccordionRootComponent { }
The TabIdAccordionComponent:
#Component({
template: ''
})
export class TabIdAccordionComponent {
constructor(private routeParams: RouteParams, private accordionService: AccordionService){
let tabId = +this.routeParams.get("tabId");
this.accordionService.tabId = tabId;
}
}
The AccordionComponent making use of the tabId from the service:
export class AccordionComponent implements OnInit {
constructor(private accordionService: AccordionService){}
selectedAccordionId: number;
ngOnInit(){
this.setSelectedAccordion(this.accordionService.tabId);
}
setSelectedAccordion(tabId: number){this.selectedAccordionId = tabId;}
}

Related

Angular component reloads when navigating

Routes for my Module:
const routes: Routes = [
{ path: ":level1/:level2/:level3", component: CategoriesComponent },
{ path: ":level1/:level2", component: CategoriesComponent},
{ path: ":level1", component: CategoriesComponent},
{ path: "", component: CategoriesComponent },
];
the Categories component Generates some links like so:
<a [routerLink]="['category1']" [relativeTo]="activatedRoute">My Link</a>
the ngOnInit & ngOnDestroy are called each time it navigates between those routes.
What I need is the component to stay mounted and not re-init each time.
Stackblitz link to illustrate the difference between using QueryParameters and RouteParameters: Angular example
NOTE: Dont suggest RouteReuseStrategy: that isn't the answer we are looking for. I have another angular application that doesn't reload the component between routes. And this is the official expected behaviour.
You need to dive into a RouteReuseStrategy and create your custom strategy with saving touched pages
Docs
RouteReuseStrategy allows you to tell Angular not to destroy a component, but in fact to save it for re-rendering at a later date. https://stackoverflow.com/a/41515648/15439733

Angular routing bug - this.router.navigateByUrl() and this.router.navigate()

I am creating angular application that will handle documentation for my GitHub apps, in more complex way than just readme files. I want to redirect user after clicking in topnav dropdown to selected route, but there's problem with router. (I need to redirect with some parameters, but it doesn't work even with simple path reditect). Those methods redirect to target route for like 1 seconds (like excepted), then user got redirected back to root page.
Code:
/* First element is project name, second is category/part of application name */
choices = ["typing_speed_test", "overview"]
json = json
constructor(private router: Router){}
onProjectClick($event){
this.choices[0] = $event.target.innerHTML.trim();
this.choices[1] = "overview";
this.redirect();
}
onCategoryClick($event){
this.choices[1] = $event.target.innerHTML.trim();
this.redirect();
}
redirect(){
this.router.navigateByUrl("404");
}
Routes:
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'project/:project_name/:category', component: SubpageComponent },
{ path: '404', component: NotFoundComponent },
//{ path: '**', redirectTo: '404', pathMatch: 'full' }
];
Link to gif with problem: https://imgur.com/a/x2mPxvh
Full code in github repo: https://github.com/Dolidodzik/DocsForMyApps (if you used code from here to answer this question, please point that in your answer)
I think I may did some stupid mistake, because I am pretty new in Angular, but I couldn't do it, because every google question showed me solves for ERRORS, when redirect doesn't work at all, not to bugs like in my situation.
You need to remove the href="#" from your anchor links in your navigation bar. It's causing the browser to reload:
<a class="dropdown-item" *ngFor="let item of categories() | keyvalue">
{{item.key}}
</a>
Also this is a bit weird solution:
this.choices[0] = $event.target.innerHTML.trim();
You better just send the item variable in your function call in your template, and you can then read this in your component event handler:
onProjectClick(item){
this.choices[0] = item.key;
this.choices[1] = "overview";
this.redirect();
}
the problem is your lins look like this:
link
default link behavior causes your app reload from the start. you should use [routerLink]="['someUrl']" instead of href. If you need that href in some cases, consider calling $event.preventDefault() to cancel the native browser navigation

Angular 7 children component route without parent route

I have a problem with routes in my Angular 7 application. I have a page frame, where I would like to switch to different components according to route without refreshing / changing main page frame.
In my page frame I have <router-outlet>.
My main route is http://localhost:4200/login.
When I go to this page, I would like to show component which is related to this route.
My second route which I would like to show is http://localhost:4200/forgot-password.
I would like to see on exactly the same page second component which is related to forgot password form.
I tried to achieve this with children and it works, but when I make a redirection it adds /forgot-password at the end of existing http://localhost:4200/login url. In this case I've always receive http://localhost:4200/login/forgot-password in url. What I'm trying to achieve is to show in url http://localhost:4200/forgot-password, without /login.
app.routes.ts
// Login Page
{
path: 'login',
component: LoginComponent,
canActivate: [ HTTPSGuard ],
children: [
{
path:'',
component: Login2ComponentComponent,
data: {
animation: 'Sign-In'
}
},
{
path: 'forgot-password',
component: ForgotPassword2Component,
data: {
animation: 'Forgot-Password'
}
}
]
}
In my login component I have a link:
<a [routerLink]="['/forgot-password']">Go to forgot</a>
But it adds me to the current /login route /forgot-password.
Maybe there is a router attribute which I can use in app.routes.ts to make this happened?
Thank you for help!

Redirecting in EmberJS

I'm relatively new to EmberJS, so any help is appreciated. I'm trying to do something I feel should be theoretically simple - I have a component and on one of the DOM elements, I want to have a click handler which redirects to a route, but I've been unable to figure out how to make that happen.
I have my component:
//components/sample-card-header.js
import Component from '#ember/component';
export default Component.extend({
actions: {
goToSamples() {
this.transitionTo('samples');
}
}
});
And my handlebars template:
//templates/components/sample-card-header.hbs
<div class="card_header" {{action "goToSamples" bubble=false}}>Samples</div>
I know I can just do:
<div class="card_header" onClick="window.location.href=('/samples')" > but I'd like to use the router paths.
Thanks in advance
The issue is that transitionTo is not available inside of components. You have two options. You could pass the action up to your route by modifying your code to be this.
1.) Create an action in your route to handle the transition and then pass the action up from the component. Follows the actions up, data down mentality of Ember.
component
import Component from '#ember/component';
export default Component.extend({
actions: {
goToSamples() {
//this passes the action to the components parent. It could be a route, other component, etc..
this.sendAction('transition');
}
}
});
route template.hbs with component
{{said-component transition='action-on-route'}}
route.js
...
actions: {
action-on-route: function(){
this.transitionTo('samples')
}
}
2.) You could inject the routing service to the component. This would make transitionTo available to the component through the routing service. I would still suggest option one as it makes the component more extensible.
Your new component code.
import Component from '#ember/component';
import { inject }from '#ember/service';
export default Component.extend({
router: inject(),
actions: {
goToSamples() {
this.get('router').transitionTo('samples');
}
}
});
Another Option
I just thought of this as I was editing. You could also use the Link-to helper if you simply need to do a transition. The link-to helper provides the ability to change the tagName. So you could render a div with a click event to transition the route using the link-to helper.
Example component.hbs
...
{{#link-to 'samples' class='card_header' tagName='div'}}
Some html
{{/link-to}}

Angular 2 routes resolve different component

Here is my use case:
When i load url /product/123 i want to load component ProductComponent
This is my setup:
RouterModule.forRoot([
{
path: 'product/:productId',
component: ProductComponent
},
{
path: '**', component: NotFoundComponent
},
]),
Now I have added a resolver to check if that product id exists, so my setup looks like this:
RouterModule.forRoot([
{
path: 'product/:productId',
component: ProductComponent,
resolver: {
productResolver: ProductResolver
}
},
{
path: '**', component: NotFoundComponent
},
]),
My resolver checks if that productId parameter exists via api call. The problem i have is that when productId is not found I want to load NotFoundComponent rather than redirecting to different page (i dont want to change url like angular 2 documentation suggests).
Anyone knows how to do that? if not productId found via resolver load NotFoundComponent without changing url/navigate?
I think all you want to do is skip the location change when you navigate to your NotFoundComponent. I'm assuming you've injected the Router into your resolver and are doing something like this when the ID does not exist:
router.navigate(['someUrl']);
Or you might be using the navigateByUrl method. Either way, you can tell the router not to change the URL:
router.navigate(['someUrl'], {skipLocationChange: true});
Don't see why you'd need to load your component via router settings, I'd put it inside the Component that tries to fetch it from the service, and then if it doesn't get a result back toggle some boolean that controls whether the NotFoundComponent gets shown. Some pseudo-ish code below:
ngOnInit(){
if (this.route.snapshot.params && this.route.snapshot.params['id']){
myService.getTheThingById((success)=>{
this.isFound = true;
},(err)=> {
this.isFound = false;
});
}
Then assuming your NotFoundComponent has a selector in it like 'not-found-component' throw it in the template for the component that's calling the service.
<not-found-component *ngIf='!isFound'></not-found-component>
I once faced this problem.
What I did was, in the component, to create 2 other components (in your case, you have ProductComponent, NotFoundComponent, and the other one you want to navigate to, let's say ArticleComponent)
Then I inserted 2 of the components in the main one :
product.component.html
<app-notFound></app-notFound>
<app-article></app-article>
After that, in your ngOnInit, you see if the parameter is there. If he is, then you log it in a property, let's say isParam = true.
Your template becomes
<app-notFound *ngIf="!isParam"></app-notFound>
<app-article *ngIf="isParam"></app-article>
It may not be the best solution out there, but it worked for me !

Categories

Resources