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.
Related
I'm new in Angular but I came from various frameworks that are relevant to the Backend such as Django, I note that Angular has the same nature as Django routing a bit regardless that it belongs to client-side so, so I'm familiar with routing confused around how Angular handles routing and use router-link in the template in Angular.
there is my problem:
export const routes: Routes = [
{path: 'login', component: LoginComponent, outlet: "login"},
{path: 'signup', component: RegisterComponent, outlet: "register"},
]
when I'm trying to move to the login page by the following statement:
<a [routerLink]="['', {outlets: {login: ['login']}}]" ariaCurrentWhenActive="page" routerLinkActive="active">Signin?</a>
what is happening is that the link looks like this link when it displaying it in the inspect element:
/app/(login:login//register:signup)
my current page is /app/(register:signup) and all I want to do is to move to: /app/(login:login)
first of all, I want to know how to move to my target.
second: I want to understand the router link nature in angular and how it works if it is possible.
We have a vanilla Vue/Vite setup and I'm receiving TypeError: Failed to fetch dynamically imported module on sentry logs.
It seems like the errors are correlated in time with new deployment to prod, although I don't have enough data to confirm. It doesn't happen on local and appears only on deployed code.
I've seen some similar questions for react's setups, but none with a satisfactory response.
I've also found a similar question regarding dynamically imported svgs, but our errors happen for full components.
The only place where we use dynamic imported components is on routing:
export const router = createRouter({
history: routerHistory,
strict: true,
routes: [
{
path: '/',
name: routes.homepage.name,
component: () => import('#/views/Home.vue'),
children: [
{
path: '/overview',
name: routes.overview.name,
component: () => import('#/views/Overview.vue'),
},
// other similar routes
],
},
],
});
Our deps versions:
"vue": "^3.0.9",
"vue-router": "^4.0.5",
"vite": "^2.0.5",
Any additional information on this issue and how to debug it would be much appreciated!
When you dynamically import a route/component, during build it creates a separate chunk. By default, chunk filenames are hashed according to their content – Overview.abc123.js. If you don't change the component code, the hash remains the same. If the component code changes, the hash changes too - Overview.32ab1c.js. This is great for caching.
Now this is what happens when you get this error:
You deploy the application
Your Home chunk has a link to /overview route, which would load Overview.abc123.js
Client visits your site
You make changes in your code, not necessarily to the Overview component itself, but maybe to some children components that Overview imports.
You deploy changes, and Overview is built with a different hash now - Overview.32ab1c.js
Client clicks on /overview link - gets the Failed to fetch dynamically imported module error, because Overview.abc123.js no longer exists
That is why the errors correlate with deployments. One way to fix it is to not use lazy loaded routes, but that's not a great solution when you have many heavy routes - it will make your main bundle large
In my case the error was caused by not adding .vue extension to module name.
import MyComponent from 'components/MyComponent'
It worked in webpack setup, but with Vite file extension is required:
import MyComponent from 'components/MyComponent.vue'
I had the exact same issue. In my case some routes worked and some didn't. The solution was relatively easy. I just restarted the dev server.
The accepted answer correctly explains when this error is triggered but does not really provide a good solution.
The way I fixed this is by using an error handler on the router. This error handler makes sure that when this error occurs (so thus when a new version of the app is deployed), the next route change triggers a hard reload of the page instead of dynamically loading the modules. The code looks like this:
router.onError((error, to) => {
if (error.message.includes('Failed to fetch dynamically imported module')) {
window.location = to.fullPath
}
})
Where router is your vue-router instance.
My situation was similar.
I found that my Quasar setup works fine on the initial page but not page that are loaded dynamically through an import('../pages/page.vue');.
Short response:
I replaced import('../pages/TestPage.vue') in the middle of the route file by import TestPage from '../pages/TestPage.vue' at the top.
More detailed response:
In my situation I don't expect to have much pages, a single bundle with no dynamic loading is fine with me.
The solution is to import statically every page I need.
In my routes.ts I import all the pages I need.
import IndexPage from '../pages/IndexPage.vue';
import TestPage from '../pages/TestPage.vue';
Then I serve them statically in my routes :
const routes: RouteRecordRaw[] = [
{
path: '/',
component: () => import('layouts/MainLayout.vue'),
children: [
{ path: 'test', component: () => TestPage },
{ path: '', component: () => IndexPage }
],
},
// Always leave this as last one,
// but you can also remove it
{
path: '/:catchAll(.*)*',
component: () => import('pages/ErrorNotFound.vue'),
},
];
I recently expriencied this. The error was caused by an empty href inside an a tag: <a href="" #click="goToRoute">. You can either remove the href or change the a tag to something else, ie. button. Let me know if this helps.
I had the same problem. I found that I had not started my project.
With Angular 2, I could make a child route render "over" its parent by defining an empty path and creating an essentially empty base component. I am trying to accomplish something similar with the new Angular router (version 4.3.1), but have hit a roadblock.
To reproduce my problem, here's a Plunker. The routes are defined as:
[{
path: '',
redirectTo: "/master",
pathMatch: "full"
}, {
path: 'master',
component: MasterComponent,
children: [{
path: 'detail/:value',
component: DetailComponent,
children: [{
path: 'subdetail',
component: SubDetailComponent
}]
}]
}]
When I navigate to a detail page, the master page is still visible because I have added a <router-outlet></router-outlet> to MasterComponent. What I need is to replace the master view with the detail. I can accomplish this by making detail/:value a sibling of master rather than a child, but this isn't logically correct in my application and breaks my breadcrumbs.
Is there any proper way to handle this kind of pattern, or will I have to pick a workaround, such as showing and hiding the intended route or manually specifying a dedicated "main" outlet for every link?
The only existing solution that comes close is to define a dummy parent component, but this only works one-level down. If my detail page has another sub-detail page that should also replace master, it gets very messy.
Is there any route-level flag I can set or design pattern to implement to elegantly accomplish this? I am an Angular 2 beginner, but I feel as though something like this should be simple.
First, there is no "new" router in 4.3.1. It's the same router from 2.x.
Second, there were a few changes I needed to make to your plunker to make it work appropriately. The key change was this in the master.component.ts:
<a [routerLink]="['/detail', 5]">
I added a slash. Without the slash it was looking for a route named master/detail/5
The route definition is now flat, so everything will appear "under" your main header.
export const routes: Routes = [
{
path: '',
redirectTo: 'master',
pathMatch: 'full'
},
{
path: 'master',
component: MasterComponent
},
{
path: 'detail/:value',
component: DetailComponent
}
];
The updated plunker is here: https://plnkr.co/edit/EHehUR6qSi248vQPDntt?p=preview
I have the following routes variable defined in my app-routing.module.ts:
const routes: Routes =
[
{ path: '', redirectTo: '/users', pathMatch: 'full' },
{ path: 'users', component: UsersComponent },
{ path: 'dashboard', component: DashboardComponent }
];
With this current configuration, when I submit http://localhost:3000/users, the browser redirects to http://localhost:3000/users/users and then displays the user list binding in the html as expected.
However, something seems off kilter for the browser to redirect from /users to /users/users. If I remove the th first route config with the redirectTo attribute then the browser stays on /users without redirecting to /users/users. However, in this scenario, the user list binding doesn't display as expected.
Any idea what might be causing the redirect to /users/users? Any idea how I can keep the browser on /users and get the user list binding to properly display at this uri?
Option 1: Setting base tag
In order to get the router working properly a base href needs to be defined somehow for the app. The docs recommend adding a base element to the head of your index.html file, such as:
<base href="/">
Option 2: Setting a provider
This can be a bit dangerous however as it has (potentially unexpected) side effects on anchor tags, empty href tags, etc, etc. It also breaks inline svg sprites... which was a major part of our app's UI. If you want to make the router work but not break a lot of things you can actually define the base href elsewhere, like so:
// ... other imports
import { APP_BASE_HREF } from '#angular/common';
#NgModule({
// ... other pieces of ngModule
providers: [
{provide: APP_BASE_HREF, useValue : '/' }
],
// ... other pieces of ngModule
})
export class AppModule {
constructor() {}
}
As a basic example. It's a bit hard to find in the documentation but is a good workaround to get things going without messing with everything else.
When trying to use the Angular 2 Component Router (Angular 2 RC 4) with the upgrade adapter I got the following error:
Bootstrap at least one component before injecting Router. at
setupRouter
This is my main.ts file:
angular.module(moduleName).directive('odetteSecureApp', upgradeAdapter.downgradeNg2Component(OdetteSecureAppComponent));
upgradeAdapter.addProvider(APP_ROUTER_PROVIDERS);
upgradeAdapter.bootstrap(document.body, [moduleName]);
I google the problem and found the following links, but they all correspond to the router deprecated module as the Angular team changed how the router works since RC4:
https://github.com/angular/angular/issues/7147?_pjax=%23js-repo-pjax-container
Any ideas?
To use the RC3 (3.0.0-alpha.*) router, you need to do a couple of things differently from how the router was set up in previous versions.
You need to define a RouterConfig like this:
import {provideRouter, RouterConfig} from '#angular/router';
export const APP_ROUTES : RouterConfig = [
{path: '', component: AppComponent},
// more paths
];
export const APP_ROUTE_PROVIDERS = [
provideRouter(APP_ROUTES)
];
then in your main.ts
upgradeAdapter.addProvider(APP_ROUTER_PROVIDERS);
Resolved by the following official post:
https://github.com/angular/angular/issues/9870