Angular Routing: Instance Creation vs Instance Activation - javascript

The Angular Routing docs mention component instance creation, component instance activation, and route activation.
The docs do not explain the differences of these concepts, and when each creation/activation occurs.
Questions
What is the difference between instance creation and instance activation?
What is the difference between instance activation and route activation?
Does instance activation always occur at the same time as instance creation?
In summary: It is not clear what is really meant by component instance activation and route activation, and how that relates to component instance creation (particularly timing wise).
Known Information
Instance Creation
Component instances are created by Angular when navigating between components of different types
When navigating between instances of the same component, the instances are re-used by default
Instance Activation
When browser's location URL changes to match a path segment (e.g /crisis-center), Router activates an instance of corresponding component (e.g CrisisListComponent) and displays its view
When app requests navigation to a path (e.g /crisis-center), Router activates instance of corresponding component (e.g CrisisListComponent), displays its view, and updates browser's address location and history with URL for that path
Route Activation
Mentioned a few places throughout the docs. See below
Angular Doc References
Here are some mentions of the above three concepts, in the Angular docs:
Instance Creation
By default, the router re-uses a component instance when it
re-navigates to the same component type without visiting a different
component first.
...
This application won't re-use the HeroDetailComponent. The user always
returns to the hero list to select another hero to view. There's no
way to navigate from one hero detail to another hero detail without
visiting the list component in between. Therefore, the router creates
a new HeroDetailComponent instance every time.
Link
Instance Activation
When the browser's location URL changes to match the path segment
/crisis-center, then the router activates an instance of the
CrisisListComponent and displays its view.
Link
When the application requests navigation to the path /crisis-center,
the router activates an instance of CrisisListComponent, displays its
view, and updates the browser's address location and history with the
URL for that path.
Link
Route Activation
The data property in the third route is a place to store arbitrary
data associated with this specific route. The data property is
accessible within each activated route.
Link
You can also protect child routes with the CanActivateChild guard. The
CanActivateChild guard is similar to the CanActivate guard. The key
difference is that it runs before any child route is activated.
Link
In the Hero Detail and Crisis Detail, the app waited until the route
was activated to fetch the respective hero or crisis.
Link
The ActivatedRouteSnapshot contains the future route that will be
activated and the RouterStateSnapshot contains the future RouterState
of the application, should you pass through the guard check.
Link

What is the difference between instance creation and instance
activation?
Instantiating means creating an instance of a route (ActivateRoute) or component. Activating of a route means attaching it to the router-outlet directive. Activating of a component means attaching it to the DOM. Routes and components are activated using activateWith function of a router-outlet directive.
Let's see some examples. Suppose you have the following routes:
{
path: 'a',
component: AComponent,
children: [
{ path: 'b', component: BComponent },
{ path: ':name', component: DComponent }
]
}
Now you navigate to a/b.
The router will:
instantiate { path: 'a', component: AComponent, children: [] } route
instantiate { path: 'b', component: BComponent } route
activate these routes by attaching them to the respective router-outlet locations
instantiate AComponent and BComponent using this approach
activate AComponent and BComponent by adding them to DOM
Now you navigate to a/n1.
The router will:
reuse route for a - { path: 'a', component: AComponent, children: [] } route (no instantiation or activation)
instantiate { path: ':name', component: DComponent } route
activate { path: ':name', component: DComponent } route
reuse AComponent instance (no instantiation or activation)
instantiate DComponent instance
activate DComponent by attaching it to the router-outlet in AComponent view
Now you navigate to a/n2.
The router will:
reuse route for a - { path: 'a', component: AComponent, children: [] } route (no instantiation or activation)
reuse route for n2 - { path: ':name', component: DComponent } route (no instantiation or activation)
update params for the n2 activated route
reuse DComponent instance (no instantiation or activation)

Related

How to reuse route on query params change, but not on path params change in Angular?

Say I have 2 routes '/users' and /users/:id. First one renders UserListComponent and second UserViewComponent.
I want to re-render component when navigating from /users/1 to /users/2. And of course if I navigate from /users to /users/1 and vice versa.
But I DON'T want to re-render component if I navigate from /users/1?tab=contacts to /users/1?tab=accounts.
Is there a way to configure router like this for entire application?
--
Update:
I'm importing RouterModule in AppRoutingModule like this:
RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })
I'm using Angular 12
The default behavior of the Angular router is to preserve the current component when the URL matches the current route.
This behavior can be changed by using the onSameUrlNavigation option:
Define what the router should do if it receives a navigation request
to the current URL. Default is ignore, which causes the router ignores
the navigation. This can disable features such as a "refresh" button.
Use this option to configure the behavior when navigating to the
current URL. Default is 'ignore'.
Unfortunately, this option is not fine-grained enough to allow reload for path params and ignore for query params.
So you have to subscribe both to the query params and the path params changes with something like this:
constructor(route: ActivatedRoute) { }
ngOnInit() {
this.renderLogic();
this.route.params.subscribe(() => this.renderLogic());
this.route.queryParams.subscribe(() => this.renderLogic());
}
renderLogic() {
// ...
}
As far as I know, #Guerric P is correct, you can't completely re-render the component selectively like this, at least not without some trickery like subscribing to each event and then possibly blocking it for one scenario and not the other. Feel free to try something like that, but below is an alternative if you make use of resolvers to fetch your data.
What you can do is use runGuardsAndResolvers in your route configuration like so:
const routes = [{
path: 'team/:id',
component: Team,
children: [{
path: 'user/:name',
component: User
}],
runGuardsAndResolvers: 'pathParamsChange',
resolvers: {...},
canActivate: [...]
}]
This will, as the name suggests, run your guard resolver logic again. If you fetch data using resolvers and pass it into your components, you can update what your component displays only when the path or params change.

How to write a router.navigate method to navigate to parent module from child module in angular6

I am able to navigate from parent module to child module , in the same way i want to navigate back to the parent module from child module. by using only typescript router.navigate method.
From html view able to navigate but its not working for typescript file.
for example like
this.router.navigate['../../',value1];
you can add in your routing module and object call data and pass the route you need for example
path: 'users',
loadChildren: 'some/route/here/here.module#HereModule',
data: { title: 'title view', urlParent: 'parentRoute' },
after you use in your child component with activatedRoute from #angular/router something like this (do not forget injection dependency of activatedRoute in your constructor)
this.urlParent = this.activatedRoute.snapshot.data.urlParent;
with that you can use your this.router.navigate[`${this.urlParent}`]

Refresh data on vue

This may have been asked but I have not be able to find a solution. I have a index page that loads a left nav vue. On that view is a typeahead input with names. When a name is selected a function is called and and a unique value is passed as the pmid_list
this.$router.push({ name: 'About', params: { pmid_list: item.PMID_Include } }
This works fine the first time because the About vue is loaded and the function is called with the pmid_list value. Every name works fine if I refresh the page between calls. If I don't refresh the correct pmid_list (parameter) is sent to the router but the router decides to send the old one if the vue component has not changed.
From what I have read it is a router issue but I can't figure out how to force it to refresh.
export default new Router({
mode: 'history',
routes: [
{
path: '/about/:pmid_list',
name: 'About',
component: About,
props: {default: true}
}
The About component is being cached.
One thing to note when using routes with params is that when the user navigates from /user/foo to /user/bar, the same component instance will be reused. Since both routes render the same component, this is more efficient than destroying the old instance and then creating a new one. However, this also means that the lifecycle hooks of the component will not be called.
Dynamic Route Matching
As shown in the documentation, you should use a watcher to react to parameter changes:
watch: {
'$route' (to, from) {
// react to route changes...
}
}
You can try to watch your route changes.
watch:{
'$route.params.pmid_list': function (pmid_list) {
//your logic here
}
},

Navigate between outlet modals in Angular 5?

I can't handle navigation from one modal window to another.
I have routing module:
{
path: 'modal1',
component: Modal1Component,
outlet: 'modal',
}, {
path: 'modal2',
component: Modal2Component,
outlet: 'modal',
}
Main component: MainComponent and in its template i have
<router-outlet name="modal"></router-outlet>
So i am clicking a button that triggers
this.router.navigate([this.router.url, { outlets: {modal: 'modal1'} }]);
And in Modal1Component that is rendered i have a button for modal2. So i want to call modal2 from modal1. How can i tell router to go to the parent route and then call:
this.router.navigate([/* what should be here? */, { outlets: {modal: 'modal2'} }]);
It looks like you're just changing the outlet in your router.navigate, but the route itself is not actually changing. And I don't think you actually require a named outlet to do what you're trying to achieve.
When you use router.navigate, you can specify if you want to navigate relatively from somewhere using the ActivatedRoute class. To do so, you have two options :
navigate relatively from you current component and indicate in the path that you want to "go up" one level. Example :
this.router.navigate(['../modal2'], { relativeTo: this.activatedRoute });
navigate directly from you parent. I would personaly use this one but both works. Example :
this.router.navigate(['modal2'], { relativeTo: this.activatedRoute.parent });
I created a mini repo with an example of what (I think) you're trying to achieve on : stackblitz.
Hope that helps
Some service can be useful in this case, like in doc:
https://angular.io/guide/component-interaction

angular's equivalent to angularjs states

In AngularJS, for routing purposes, we define states with children which makes it possible to switch between views with the result that each view is always rendered in one container:
$stateProvider.state("communication.create-message", {
url: ...,
templateUrl: ...,
menu: ...,
parent: "communication",
ncyBreadcrumb: {
label: "Create Message"
}
});
Whichever state we choose - the view is always rendered within one container that has ui-view attribute.
I'm trying to achieve the same in Angular 2 or above, but I have no idea of how to reproduce the above-stated functionality.
In app.component.ts we have router-outlet where component templates get rendered.
Say, we have many nested child routes - is it possible to render all of them within this outlet ?
What would the code in app-routing.module.ts look like in this case ?
Could anyone please give a working example of how to go about it ?
Step 1 : Import Routes from #angular/router
in app.module.ts .. import Routes. You have to write
import {Routes} from '#angular/core'
Step 2 :
Add all the routes you want to set up in an array pf type Routes like :
this is for informing angular all the routes in your app. Each route is a javascript object in this array.
const appRoutes : Routes = [
{path : 'communication-route'}
]
always you have to give path , this what you enter after your domain like "localhost :4200/communication-route".
Step 3: Add the action to route i.e what happens when this path is reached.
const appRoutes : Routes = [
{path : 'communication-route'} , component :communicationroutecomponent
]
here i have given the component name "communicationroutecomponent" , i.e this component will be loaded when the path "/communication-route" is reached
Step 4: Register your routes in your app
To do this you will have to do new import in app.module.ts
import {RouterModule} from '#angular/router'
Routermodule has special method forRoot() which registers our routes .
In our case we will have to write this piece of code in
imports :[
RouterModule.forRoot(appRoutes)
]
Our routes are now registered and angular knows our routes now.
Step 5 : Where to display the route content i.e the html content of you route page.
For this angular has directive .
We need to include where we want to load our content i.e in the html.
<a router-outlet="/communication-route"></a>
Navigating to routes :
angular gives a directive for this routerLink
so if we want to navigate to users component , you can give this in your html element:
routerLink="/communication-route"
I hope i was able to explain how this works.
Your code should be as follows
export const ComRoute: Routes = [
{
path: 'communication-route',
children: [
{ path: 'communication', component: communicationComponent },
{ path: ':child1', component: child1Component },
{ path: ':child1/field', component: child1Component}
]
}
];
First of all, states are not an official AngularJS concept. They come from ui-router, which began life as an alternate to the simplistic built in router.
Eventually, ui-router became the de facto standard for routing in AngularJS while the official ng-route module was extracted into a separate, optional library by the Angular team.
ui-router, is complex but exceptional and has earned what is in my view well deserved popularity and success. This success has led to its expansion to support additional platforms enabling the same powerful state based structure in applications written for frameworks such as React.
It is now available for Angular (formerly known as Angular 2).
You can read the documentation and see how to get started on https://ui-router.github.io/ng2
Here is a snippet from the src/app/app.states.ts module of the official example repository
export const loginState = {
parent: 'app',
name: 'login',
url: '/login',
component: LoginComponent,
resolve: [
{ token: 'returnTo', deps: [Transition], resolveFn: returnTo },
]
};
As we can see, there are compatible concepts available, including what looks like a nice evolution of the resolves API which allows function oriented injection which was generally simpler than class based injection in ui-router with AngularJS.
Note, I have not used it in an Angular project.

Categories