Vue3 router: How to make an active menu item when on a sub route? - vuejs3

So, it looks I am doing something wrong.
From the docs, if I have a <router-link to="/articles">Articles</router-link> if the current routes are either /articles, /articles/1, /articles/2, articles/2/foo should always get at least router-link-active class... and when it is "root" like /articles it should also get a router-link-exact-active
but mine doesn't... I only get both (router-link-active and router-link-exact-active) when on /articles... but when on /articles/1 (or any other sub route) I get nothing.
this is my router main
const routes = [
{
path: "/",
name: "Landing",
component: LandingPage,
},
{
path: "/articles",
name: "ArticlesList",
component: ArticlesListPage,
},
{
path: "/articles/:id",
name: "ArticleDetails",
component: ArticleDetailsPage,
}, ...
]
const router = createRouter({
history: createWebHistory(),
routes,
});
I would get it right, if the path "/articles/:id" would be a part of "/articles" children, but then I would need a nested router-view, which I don't want

Related

Apply different css files between 2 sub roots

I have an angular app, which consists of a website and system.
so I have made 2 sub roots under app root, websiteMaster, and systemMaster.
CSS files of the website don't have to be loaded when I'm logged in.
CSS files of the systems don't have to be loaded when I'm logged out.
so I need to load CSS files in websiteMaster only for website sub root components and to load CSS files in systemMaster only for system sub root components.
Is there a way to apply that using Angular 8?
Thanks in advance
You've to manually load/unload css files in a main/root(whatever you want to call it) component in one of your subroot module.
Let suppose websiteMaster module has following structure
Routes:
// Wrapping all routes in a parent component
const routes: Routes = [
{ path: '', component: WebsiteMasterRootComponent, children: [
{ path: 'any-path', component: AnyComponent },
{ path: 'any-other-path', component: AnyOtherComponent },
]
}];
WebsiteMasterRootComponent: which will load and unload css files related to this module
export class WebsiteMasterRootComponent implements OnInit, OnDestroy {
// css files required for current module
private styles = [
{ id: 'css-file-1', path: 'assets/css/css-file-1.css' },
{ id: 'css-file-2', path: 'assets/css/css-file-2.css' },
{ id: 'css-file-3', path: 'assets/css/css-file-3.css' },
];
constructor() {}
ngOnInit() {
this.styles.forEach(style => this.loadCss(style));
}
ngOnDestroy() {
// remove css files from DOM when component is getting destroying
this.styles.forEach(style => {
let element = document.getElementById(style.id);
element.parentNode.removeChild(element);
});
}
// append css file to DOM dynamically when current module is loaded
private loadCss(style: any) {
let head = document.getElementsByTagName('head')[0];
let link = document.createElement('link');
link.id = style.id;
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = style.path;
head.appendChild(link);
}}

Angular 2 - How to add permalink?

I try to add permalinks to my angular 2 app, but I didn't find a way yet.
My app-routing.module.ts:
const routes: Routes = [
{ path: '', pathMatch: 'full', component: TagelerComponent },
{ path: 'tageler', component: TagelerListComponent },
{ path: 'tageler-details/:id', component: TagelerDetailsComponent },
{ path: 'group/:id', component: GroupDetailsComponent },
{ path: 'tageler/admin', component: AdminComponent },
];
#NgModule({
imports: [ RouterModule.forRoot(routes) ],
exports: [ RouterModule ]
})
export class AppRoutingModule {}
And my code looks like this:
<div *ngFor="let group of groups | groupTypeFilter: 'Trupp' ">
<a routerLink="/group/{{group._id}}">
<li class="list-group-item">
{{group.name}}
</li>
</a>
</div>
In this example the URL is something like: http://localhost:4200/group/5910c2282249261cc61d0a7e
Instead of the group id, I would like to display the name of the group (e.g. dogs) without changing the routing, so the URL changes to: 'http://localhost:4200/group/dogs'.
I'm new to Angular 2, so I don't really know whether this is actually possible.
I would be glad if someone could help me!
The answer is you can not replace the id with the name in the routerLink, and then query the group by id, assume a user opened a new tab and entered the URL
http://localhost:4200/group/dogs
The app will load and the only reference you have is dogs, where will the id come from? unless you have already defined a dictionary that returns the id of the given group name, or by using some black magic
However in case you only let the user to access the detail page through its parent, then you can pass the group instance by using a shared service and set the router link to group.name.
<div *ngFor="let group of groups | groupTypeFilter: 'Trupp' ">
<a [routerLink]="shared.setGroupLink(group)">
<li class="list-group-item">
{{group.name}}
</li>
</a>
</div>
constructor(public shared: SharedService) { }
in SharedService
export class SharedService{
currGroupId: number;
constructor() { }
setGroupLink(group) {
// you can pass the object as a whole but I'll use `group.id` in this example
// this.currGroup = group;
this.currGroupId = group.id;
return '/group/' + group.name;
}
}
In GroupDetailsComponent
groupId: number;
constructor(public shared: SharedService) { }
ngOnInit() {
this.groupId = this.shared.currGroupId;
}
NOTE: this approach will not work if the user entered http://localhost:4200/group/dogs because groupId is undefined
by the way, avoid prefixing your variables' names with the underscore _, check Angular Style Guide

Aurelia How do I use a Child Router and dynamics child routes

Trying to use a child route in Aurelia. Can't seem to get my head around the workings of nested routes. Are all routes derived from the root of the app or relative to location of the current router?
Why wont my route-href work in this example? I have a route in this router named screen and it does have an :id parameter
screens/list.ts
#inject(Router)
export class ScreensList {
heading;
router;
screens: any[];
constructor(router){
this.heading = 'Child Router';
this.router = router;
this.screens = [
{
id: 1,
name: 'my screen'
},
{
id: 2,
name: 'my other screen'
}
]
router.configure(config => {
config.map([
// dynamic routes need a href, such as href: screen
{ route: 'screen/:id', moduleId: 'screens/screen/display', name: 'screen', title: 'Screen #1' }
]);
});
}
}
List View
screens/list.html
<li repeat.for="screen of screens">
<a route-href="route: 'screen', params: { id: screen.id }"/>Screen #${screen.id}</a>
</li>
I then have a dummy VM/V at screens/screen/display.
Do I really have to specify the full filepath for a module in a nested child router. I thought it would be routes relative to the location of the parent router or at least the name (root) of the parent?
vendor-bundle.js:11582 ERROR [route-href] Error: A route with name ''screen', params: { id: screen.id }' could not be found.
Check that `name: ''screen', params: { id: screen.id }'` was specified in the route's config.
In your example, you are injecting the router, which is the router configured in app.js, and then calling its configure method. Aurelia is Convention-Over-Configuration. So, use the convention and you will be fine. The configureRouter method will do the tricks for you. For instance:
export class ScreensList {
configureRouter(config, router) {
config.map([
{ route: 'screen/:id', moduleId: 'screens/screen/display', name: 'screen', title: 'Screen #1' }
]);
this.router = router;
}
}
Remember that ScreensList must be a screen of your router. It will not work if it is a custom element.
Take a look at the skeleton-navigation examples https://github.com/aurelia/skeleton-navigation. There are good examples, including child routing.

angular2 router 3.0.0 multiple levels

Based on the latest Angular 2 Router (3.0.0-alpha.7) with the recent published documentation here: https://angular.io/docs/ts/latest/guide/router.html
I tried to add more levels of routing navigation without any success like this:
export const CustomerRoutes: RouterConfig = [
{
path: 'customer/:id',
component: CustomerComponent,
children: [
{
path: 'account',
component: CustomerAccountComponent,
children:
[
{ path: 'info', component: CustomerInfoComponent },
{ path: 'billing', component: CustomerBillingComponent }
]
},
{
path: 'idocs',
component: CustomerIDocsComponent,
children:
[
{ path: 'ic', component: CustomerICComponent },
{ path: 'iprop', component: CustomerIPropComponent }
]
}
]
}
];
But I get the error: Uncaught (in promise): Error: Cannot match any routes: 'customer/123'
I want to have a customer detail page with two independent areas, which one has their router-outlet to load respective components without changing the content of the other router-outlet on same level and visible on page.
app
/ \
/ \
(...) customer
/ \
/ \
account (both visible) idocs
/ \ / \
info billing iprop ic
So I can navigate to levels like this:
/customer/123/account/info
/customer/123/account/billing
/customer/123/idocs/ic
/customer/123/idocs/ic/123
/customer/123/idocs/iprop
/customer/123/idocs/iprop/123
But when I am at customer page, I want to see the account and idocs section at both time.
Anyone knows how to achieve this? I have the plunker example here: http://plnkr.co/edit/TotsM3wv64u16GuUkoLF?p=preview

Durandal Routing - routing to a resource with a particular id?

I'm trying to configure my routing so that navigating to #/my displays the contents for #/folder/62 (or some id stored in a variable) - and navigating to #/public displays the contents for #/folder/1 (same concept).
Additionally, I'd like the application to navigate to one of these routes upon loading, depending on whether or not the user is authenticated. The authentication stuff is done, but once the above routes have been configured, I'd like to activate on one of them.
Here's what I have:
activate: function () {
router.useConvention();
router.handleInvalidRoute = function (route, params) {
//debugger;
logger.logError("Invalid route", route, null, true);
};
router.map([
{ url: 'home', moduleId: 'viewmodels/home', name: 'Home', visible: false },
{ url: 'my', moduleId: 'viewmodels/folder', name: 'My Content', visible: false }, // Should display contents of /folder/2
{ url: 'public', moduleId: 'viewmodels/folder', name: 'Public Content', visible: false }, // Should display contents of /folder/3
{ url: 'set/:id', moduleId: 'viewmodels/set', name: 'Set', visible: false },
{ url: 'folder/:id', moduleId: 'viewmodels/folder', name: 'Folder', visible: false }
]);
if (auth.isAuthenticated)
return router.activate('my'); // should show details page of a particular folder
else {
return router.activate('public'); // should show details page of a particular folder
}
}
app.setRoot as described in https://groups.google.com/forum/#!searchin/durandaljs/app.setRoot/durandaljs/t1hrLfOh1oM/RtCekmY0bDAJ could be used to show different views for authenticated/non-authenticated users.
If only authenticated users should be allowed to see content of "folder/specialID" in the example then you might consider not to expose these via router. Use standard compose functionality in #my to load the specialID view/view model instead.

Resources