Multiple levels of routing in Durandal - javascript

I am looking at the Durandal samples trying to understand how routing works.
The shell.js specifies these routes:
{ route: ['', 'knockout-samples*details'], moduleId: 'ko/index', title: 'Details...', nav: true, hash: '#knockout-samples' },
{ route: 'view-composition',moduleId: 'viewComposition/index', title: ...
under knockout-samples:
{ route: '', moduleId: 'helloWorld/index', title: 'Hello World', type: 'intro' },
{ route: 'helloWorld', moduleId: 'helloWorld/index', title: 'Hello World', type: intro', nav: true},
What I am trying to achieve is having another hierarchy under helloWorld. Something like this:
I tried this but no luck:
{ route: '', moduleId: 'helloWorld/index', title: 'Hello World', type: 'intro' },
{ route: 'helloWorld*details', moduleId: 'helloWorld/index', title: 'Hello World', type: 'intro', nav: true, hash:'#knockout-samples/helloWorld'}
However, this is not working.
Does Durandal routing not support this level of navigation?

When creating a 'grandchild' or 'great grandchild' or deeper child router, the trick is to reference the relative parent router, not the root router. To get a reference to the parent router, add the module that contains the parent router as a dependency to your 'grandchild' module. You can nest routers like this indefinitely. For example:
myModuleWithChildRouter.js
define(['plugins/router'], //reference to durandal root router
function(router) {
var _childRouter = router.createChildRouter();
return { myNewChildRouter: _childRouter}
}
myModuleWithGrandchildRouter.js
define(['myModuleWithChildRouter'], //reference to module with child router
function(childRouterModule) {
var _grandChildRouter = childRouterModule.myNewChildRouter.createChildRouter();
.....
}
Hope that helps!

To get more than one navigation level I'm doing this:
The only accesible router is the root router so to have acces to the child routers, everytime that I'm creating a child router, i store it on a module.
Then, when i want to create another level, I get the child router from the module and call createChildRouter.
define([], function () {
return {
root: null,
level1: null,
level2: null
};
});
define(['plugins/router', 'routers'], function (router, routerContainer) {
var childRouter = router.createChildRouter()
.makeRelative({
moduleId: 'viewmodels/companyplussplat',
//fromParent: true
route: 'company'
}).map([
{ route: 'order/:orderID', moduleId: 'orderdetail', title: 'Order', nav: false },
{ route: 'order/:orderID*details', moduleId: 'orderdetailplussplat', title: 'Order plus splat', nav: false }
]).buildNavigationModel();
routerContainer.level1 = childRouter;
return {
activate: function () {
console.log("Activating company plus splat");
},
deactivate: function () {
console.log("Deactivating company plus splat");
},
router: childRouter
};
});
define(['plugins/router', 'routers'], function (router, routerContainer) {
//debugger;
var childRouter = routerContainer.level1.createChildRouter()
.makeRelative({
moduleId: 'orderteailplussplat',
//fromParent: true
route: 'company/order/:orderID'
}).map([
{ route: 'orderline/:orderlineID', moduleId: 'orderlinedetail', title: 'Order line detail', nav: false },
]).buildNavigationModel();
routerContainer.level2 = childRouter;
return {
activate: function (orderID) {
console.log('Activating order detail for: '+ orderID +' plus splat');
},
deactivate: function () {
console.log('Deactivating order detail plus splat');
},
router: childRouter
};
});
I hope this will help you.

I added the child as a reference to the parent router itself. Maybe a bit sneaky, but working happily:
Top level router
define(["plugins/router"], function (router) {
// create the constructor
var ctor = function() {
};
ko.utils.extend(ctor.prototype, {
activate: function () {
//var self = this;
var map = router.makeRelative({ moduleId: "viewmodels" }).map([
{ route: "", moduleId: "index", title: "Overview", nav: true, hash: "#/", enabled: true },
{ route: "data*details", moduleId: "data/shell", title: "Data Loading", nav: true, hash: "#/data", enabled: false },
{ route: "reporting*details", moduleId: "reporting/shell", title: "Reporting", nav: true, hash: "#/reporting", enabled: true },
{ route: "query*details", moduleId: "query/shell", title: "Query", nav: true, hash: "#/query", enabled: true },
{ route: "login", moduleId: "login", title: "Login", hash: "#/login", state: "out" }
]);
return map.buildNavigationModel()
.mapUnknownRoutes("404")
.activate();
});
});
return ctor;
});
Child router
define(["plugins/router"], function (router) {
var childRouter = router.createChildRouter()
.makeRelative({
moduleId: "viewmodels/reporting",
fromParent: true
}).map([
{ route: "", moduleId: "index", title: "Reporting", nav: false, hash: "#/reporting" },
{ route: "standard", moduleId: "standard", title: "Standard Reports", nav: true, hash: "#/reporting/standard" },
{ route: "alert*details", moduleId: "alert/shell", title: "Alerts", nav: true, hash: "#/reporting/alert" }
]).buildNavigationModel();
// for alerts
router.child = childRouter;
var vm = {
router: childRouter
};
return vm;
});
Grandchild router
define(["plugins/router"], function (router) {
var grandchildRouter = router.child.createChildRouter()
.makeRelative({
moduleId: "viewmodels/reporting/alert",
fromParent: true
}).map([
{ route: "", moduleId: "index", title: "Alerts", hash: "#/reporting/alert" },
{ route: ":id", moduleId: "case", title: "Alert Details", hash: "#/reporting/alert" }
]).buildNavigationModel();
var vm = {
router: grandchildRouter
};
return vm;
});
Hope that helps.

If you are using durandal 2.0 you can set up the child router. This will allow you to create a new router under the hello world that you can chain on additional info for for sub views in your view. You can look these up on the docs but make sure you set up that router within the view so when you hit a route like
#helloworld/subview
you have already activated helloworld

Related

Unknown variable dynamic import : ../views/Admin/Home.vue Vue3-vue-router4

Using Vue3 - Vuerouter4 - Vite
I try to import the components and routes in vue router but I face this error (only for the route that has children in my paths):
my router code:
import { createRouter, createWebHistory } from "vue-router";
import paths from "./path";
import { TokenService } from "#/services/storage.services.js";
function route(options) {
let path = options.path;
let view = options.view;
let name = options.name;
let meta = options.meta ? options.meta : "";
let children = options.children ? options.children : null;
let redirect = options.redirect ? options.redirect : null;
let currentRoute = {
name: name || view,
path,
meta,
component: (resolve) => import(`#/views/${view}.vue`).then(resolve),
};
if (children && Array.isArray(children)) {
children = children.map((path) => {
path.view = view + "/" + path.view;
return path;
});
currentRoute["children"] = children.map((path) => route(path));
}
if (redirect) {
currentRoute["redirect"] = redirect;
}
return currentRoute;
}
// Create a new router
const router = createRouter({
history: createWebHistory(),
routes: paths
.map((path) => route(path))
.concat([{ path: "/:pathMatch(.*)", redirect: "admin/home" }]),
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition;
}
if (to.hash) {
return { selector: to.hash };
}
return { left: 0, top: 0 };
},
});
export default router;
my paths that are in paths.js:
export default [
{
path: "/admin",
name: "Admin",
view: "Admin",
redirect: "Admin/Home",
children: [
{
path: "Home",
name: "Home",
view: "Home",
meta: {
auth: true,
title: "داشبورد",
},
},
{
path: "TRANSACTION",
name: "TRANSACTION",
view: "Transaction",
meta: {
auth: true,
title: "تراکنش ها",
},
},
{
path: "SMS-MANAGEMENT",
name: "SMSManagement",
view: "SMSManagement",
meta: {
auth: true,
title: "مدیریت پیامک ها",
},
},
{
path: "CAR-LIST",
name: "CAR-LIST",
view: "Car-List",
meta: {
auth: true,
title: "لیست خودرو های اجاره ای",
},
},
{
path: "ADDRENTCAR",
name: "ADDRENTCAR",
view: "AddRentCar",
meta: {
auth: false,
title: "افزودن خودرو اجاره ای",
},
},
{
path: "EDITRENTCAR",
name: "EDITRENTCAR",
view: "AddRentCar",
meta: {
auth: false,
title: "ویرایش خودرو اجاره ای",
},
},
{
path: "USERS",
name: "USERS",
view: "Users",
meta: {
auth: true,
title: "لیست کاربران",
},
},
{
path: "CARS",
name: "CARS",
view: "Cars",
meta: {
auth: true,
title: "لیست خودرو ها",
},
},
{
path: "REQUESTS",
name: "REQUESTS",
view: "REQUESTS",
meta: {
auth: true,
title: "لیست درخواست ها",
},
},
],
},
{
path: "",
name: "MAIN-HOME",
view: "main-home",
meta: {
auth: true,
title: "صفحه اصلی",
public: true,
},
},
{
path: "/PROFILE",
name: "PROFILE",
view: "PROFILE",
meta: {
auth: true,
title: "پروفایل من",
},
},
{
path: "/LOGIN",
name: "LOGIN",
view: "Login",
meta: {
auth: true,
title: "ورود",
},
},
{
path: "/ALLCARS",
name: "ALLCARS",
view: "ALLCARS",
meta: {
public: true,
auth: true,
title: "لیست تمام خودرو ها",
},
},
{
path: "/ABOUTUS",
name: "ABOUTUS",
view: "ABOUTUS",
meta: {
public: true,
auth: true,
title: "درباره ما",
},
},
];
Any ideas what causes the error specifically for my admin route that has children??!!
........................................................................................................................................................................................................................................................................................................................................................................................................................................................................
I changed the "../views/" to "/src/views/" and problem solved.
Seems like using '..' wouldn't make it to the src folder!!!!!
Thank you #Mohammad Masoudi

Vue.js - Dynamic buttons with dynamic v-if

I'm generating some menu buttons dynamically (not sure if that's best practice)
script
items: [
{ title: 'Dashboard', icon: 'mdi-view-dashboard', route: '/' },
{ title: 'Register', icon: 'mdi-image', route: '/register' },
{ title: 'Login', icon: 'mdi-help-box', route: '/login' },
],
html
<v-list-item v-for="(item, i) in items" :key="i" link :to="{path: item.route}">
But what I want to do is hide the dashboard button until they have signed in. The user signed in value is kept in store.
$store.state.user.signedIn // true/false
How can I programmatically hide buttons depending on signed in value? I was trying to do this
{ title: 'Dashboard', icon: 'mdi-view-dashboard', route: '/', reqAuth: true }
But not sure how to get it working smoothly in the html. I'd also like to do the reverse later on the login/register buttons, if the user IS signed in then these should hide and a Logout button will come into play.
You have two options:
A) have separate menu arrays and display one or the other based on isLoggedIn. If you have any items showing in both cases, you'll need to place them in a third array and concat one of the first two with the third
B) have a boolean property on each menu item stating whether it should show when isLoggedIn or not. If you have menu items showing on both, you'll need either two props on each item (showWhenLoggedIn, showWhenLoggedOut - change them if too long) or, alternatively, you could make the show an array of booleans: show: [true, false] - first bool controlling whether it's shown when logged out, second when logged in).
Solution A) example (separate arrays):
Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
el: '#app',
data: () => ({
loggedInMenuItems: [
{ title: 'Dashboard', icon: 'mdi-view-dashboard', route: '/', show: [false, true] },
],
loggedOutMenuItems: [
{ title: 'Register', icon: 'mdi-image', route: '/register', show: [true, false] },
{ title: 'Login', icon: 'mdi-help-box', route: '/login', show: [true, false] },
],
permanentMenuItems: [
{ title: 'Terms and Conditions', icon: 'mdi-whatever', route: '/terms', show: [true, true] }
],
isLoggedIn: false
}),
computed: {
menuItems() {
return (this.isLoggedIn
? this.loggedInMenuItems
: this.loggedOutMenuItems
).concat(this.permanentMenuItems)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<label><input v-model="isLoggedIn" type="checkbox"> Is logged in</label>
<pre v-html="menuItems.map(m => m.title)"></pre>
</div>
Solution B) example:
Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
el: '#app',
data: () => ({
items: [
{ title: 'Dashboard', icon: 'mdi-view-dashboard', route: '/', show: [false, true] },
{ title: 'Register', icon: 'mdi-image', route: '/register', show: [true, false] },
{ title: 'Login', icon: 'mdi-help-box', route: '/login', show: [true, false] },
{ title: 'Terms and Conditions', icon: 'mdi-whatever', route: '/terms', show: [true, true] }
],
isLoggedIn: false
}),
computed: {
menuItems() {
return this.items.filter(item => item.show[Number(!!this.isLoggedIn)])
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<label><input v-model="isLoggedIn" type="checkbox"> Is logged in</label>
<pre v-html="menuItems.map(m => m.title)"></pre>
</div>
I personally prefer the second one, for brevity. I also find it a tad more elegant.
However, in large teams or in projects where code complexity needs to be kept to a minimum and code readability to a maximum, the first solution is often times preferred.
Lastly, second solution allows more flexibility for menu items order, although it's not a real issue (implementing an order attribute to each item would be trivial).
Note: obviously, isLoggedIn should come from state, not from component data fn. I placed it in data so you could easily test it here.
Your items property should be defined as computed property and add shown field in each item of items and use state value as its value in dashboard link :
computed :{
items(){
const signedIn=$store.state.user.signedIn;
return [
{ title: 'Dashboard', icon: 'mdi-view-dashboard', route: '/', shown:signedIn },
{ title: 'Register', icon: 'mdi-image', route: '/register',shown:!signedIn},
{ title: 'Login', icon: 'mdi-help-box', route: '/login' , shown:!signedIn},
]
}
}
in template add
<v-list-item v-for="(item, i) in items" :key="i" link v-if="item.shown" :to="{path: item.route}">

How do I create reusuable external functions in Vue?

As my project is growing, I've noticed a lot of repetitions. I'm starting with the navigations buttons, as they can appear in multiple places (side menu, navbar).
I'd like to centralize them and let the component import them as needed. So I've tried creating this file to hold all my menu items:
// menuItems.js
export default {
data() {
return {
items: [
{ title: 'Profile', icon: 'mdi-account-circle', reqAuth: true, hideOnAuth: false},
{ title: 'Dashboard', icon: 'mdi-view-dashboard', reqAuth: true, hideOnAuth: false },
{ title: 'Settings', icon: 'mdi-cog', reqAuth: true, hideOnAuth: false },
{ title: 'Signup', icon: 'mdi-account-circle-outline', reqAuth: false, hideOnAuth: true},
{ title: 'Login', icon: 'mdi-login', reqAuth: false, hideOnAuth: true },
{ title: 'Logout', icon: 'mdi-logout', reqAuth: true, hideOnAuth: false},
]
}
},
methods: {
menuItems: function(authenticated) {
if (!authenticated) {
// Gets items that do and don't require Auth, except for ones that should hide on Auth
return this.items.filter(o => o.reqAuth || !o.reqAuth && !o.hideOnAuth)
}
// Gets items that don't require Auth
return this.items.filter(o => !o.reqAuth)
}
}
}
Buttons can require authentication to be visible, and they can also be hidden once authenticated (eg. The login button).
Now lets assume I have a vue component for my nav bar, how do I import in the method that returns the filtered items?
// NavBarComponent.vue
<template>
<div>
<v-btn v-for="(item, i) in menuItems(authenticated)">
{{ item.title }}
</v-btn>
</div>
</template>
<script>
export default {
name: "NavBarComponent",
data() {
return {
authenticated: true,
}
},
methods: {
}
}
</script>
In this case, how do i make menuItems in the component reference the external file that will do the work of filtering?
You can create a mixin file and put your methods in that mixin and apply the mixin your component.
https://v2.vuejs.org/v2/guide/mixins.html
Your mixin would look like this:
// /mixins/menuItemsMixin.js
const menuItemsMixin= {
data() {
return {
items: [
{ title: 'Profile', icon: 'mdi-account-circle', reqAuth: true, hideOnAuth: false},
{ title: 'Dashboard', icon: 'mdi-view-dashboard', reqAuth: true, hideOnAuth: false },
{ title: 'Settings', icon: 'mdi-cog', reqAuth: true, hideOnAuth: false },
{ title: 'Signup', icon: 'mdi-account-circle-outline', reqAuth: false, hideOnAuth: true},
{ title: 'Login', icon: 'mdi-login', reqAuth: false, hideOnAuth: true },
{ title: 'Logout', icon: 'mdi-logout', reqAuth: true, hideOnAuth: false},
]
}
},
methods: {
menuItems: function(authenticated) {
if (!authenticated) {
// Gets items that do and don't require Auth, except for ones that should hide on Auth
return this.items.filter(o => o.reqAuth || !o.reqAuth && !o.hideOnAuth)
}
// Gets items that don't require Auth
return this.items.filter(o => !o.reqAuth)
}
}
};
export default menuItemsMixin
And in your component:
// NavBarComponent.vue
<script>
import menuItemsMixin from './mixins/menuItemsMixin.js'
export default {
mixins:[menuItemsMixin]
}
</script>
You can import this mixin in multiple components and you can also add more mixins in this component where the unique methods will be added.
I ended up creating a javascript file:
// views.js
export const views = [
{title: 'Dashboard'},
{title: 'Profile'},
{title: 'Login/Signup'},
]
then in my navbar component I imported it like so:
import {mapGetters} from "vuex";
import {views} from "../../common/views";
export default {
data: () => ({
items: views
}),
computed: {
...mapGetters(['isAuthenticated',])
menuItems: function (){
if (this.isAuthenticated) {
// do this
} else {
// do this
}
},
}
}
Then I did the same for the filtering function, but I could also just re-code it as needed if required in each component. I determined authentication state using Vuex's store, and retrieve it with mapgetters.
<componentA v-if='isAuthenticated'>
<navItem v-for='item in menuItems'>
</componentA>

Vuejs route redirect on refresh

When i use refresh button in my browser or hit f5 on keyboard instead of refreshing my page it redirects to home page.
Code
router.js
import Vue from "vue";
import VueRouter from 'vue-router';
import store from './store';
Vue.use(VueRouter);
import NotFoundComponent from './components/NotFoundComponent.vue';
const router = new VueRouter({
mode: "history",
routes: [
{
path: '*',
name: 'notFound',
component: NotFoundComponent,
meta: {
breadCrumb: 'Not Found'
}
},
//rest of routes...
]
});
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
if (!store.getters.isLoggedIn) {
next({
name: 'login'
})
} else {
next()
}
}
if (to.matched.some(record => record.meta.admin)) {
if (store.getters.loggedUser.type !== 'admin') {
next({
name: 'home'
})
} else {
next()
}
}
next()
});
router.afterEach((to, from) => {
Vue.nextTick(() => {
document.title = to.pageTitle || 'Test App';
});
});
export default router;
For instance if i am in this URL
https://example.com/products
after refresh i will redirect to
https://example.com
Any idea?
Update
route.js full code
import Vue from "vue";
import VueRouter from 'vue-router';
import store from './store';
Vue.use(VueRouter);
//admins
import pageHome from './components/HomePage.vue';
import Dashboard from './components/admin/Dashboard.vue';
import AdminProducts from './components/admin/Products/Products.vue';
import AddProducts from './components/admin/Products/Add.vue';
import CurrencySettings from './components/admin/Settings/Currencies/Currency.vue';
import AddCurrencies from './components/admin/Settings/Currencies/Add.vue';
import editCurrencies from './components/admin/Settings/Currencies/Edit.vue';
import SlideSettings from './components/admin/Settings/Slides/Slide.vue';
import addSlides from './components/admin/Settings/Slides/Add.vue';
import editSlides from './components/admin/Settings/Slides/Edit.vue';
import categoriesSettings from './components/admin/Categories/Categories.vue';
import addCategories from './components/admin/Categories/Add.vue';
import editCategories from './components/admin/Categories/Edit.vue';
import tagsSettings from './components/admin/Tags/Tags.vue';
import addTags from './components/admin/Tags/Add.vue';
import editTags from './components/admin/Tags/Edit.vue';
import brandsSettings from './components/admin/Brands/Brands.vue';
import addBrands from './components/admin/Brands/Add.vue';
import editBrands from './components/admin/Brands/Edit.vue';
import usersSettings from './components/admin/Users/Users.vue';
import addUsers from './components/admin/Users/Add.vue';
import editUsers from './components/admin/Users/Edit.vue';
import reviewsSettings from './components/admin/Reviews/Reviews.vue';
import editReviews from './components/admin/Reviews/Edit.vue';
// users
import Register from './components/auth/Register.vue';
import Login from './components/auth/Login.vue';
import Profile from './components/auth/Profile.vue';
import SingleProduct from './components/Front/SingleProduct.vue';
import NotFoundComponent from './components/NotFoundComponent.vue';
const router = new VueRouter({
mode: "history",
routes: [
{
path: '*',
name: 'notFound',
component: NotFoundComponent,
meta: {
breadCrumb: 'Not Found'
}
},
// ADMIN ROUTES
{
path: '/dashboard',
name: 'dashboard',
component: Dashboard,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
name: 'dashboard',
breadCrumb: 'Dashboard'
}
},
{
path: '/dashboard/products',
name: 'adminProducts',
component: AdminProducts,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Products'
}
},
{
path: '/dashboard/products/add',
name: 'addProducts',
component: AddProducts,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Add Product'
}
},
{
path: '/dashboard/currencies',
name: 'CurrencySettings',
component: CurrencySettings,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Currencies'
}
},
{
path: '/dashboard/currencies/add',
name: 'addCurrencies',
component: AddCurrencies,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Add Currency'
}
},
{
path: '/dashboard/currencies/:id/edit',
name: 'editCurrencies',
component: editCurrencies,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Edit Currency'
}
},
{
path: '/dashboard/slides',
name: 'SlideSettings',
component: SlideSettings,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Slides'
}
},
{
path: '/dashboard/slides/add',
name: 'addSlides',
component: addSlides,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Add Slide'
}
},
{
path: '/dashboard/slides/:id/edit',
name: 'editSlides',
component: editSlides,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Edit Slider'
}
},
{
path: '/dashboard/categories',
name: 'categoriesSettings',
component: categoriesSettings,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Categories'
}
},
{
path: '/dashboard/categories/add',
name: 'addCategories',
component: addCategories,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Add Category'
}
},
{
path: '/dashboard/categories/:id/edit',
name: 'editCategories',
component: editCategories,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Edit Category'
}
},
{
path: '/dashboard/tags',
name: 'tagsSettings',
component: tagsSettings,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Tags'
}
},
{
path: '/dashboard/tags/add',
name: 'addTags',
component: addTags,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Add Tag'
}
},
{
path: '/dashboard/tags/:id/edit',
name: 'editTags',
component: editTags,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Edit Tag'
}
},
{
path: '/dashboard/brands',
name: 'brandsSettings',
component: brandsSettings,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Brands'
}
},
{
path: '/dashboard/brands/add',
name: 'addBrands',
component: addBrands,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Add Brand'
}
},
{
path: '/dashboard/brands/:id/edit',
name: 'editBrands',
component: editBrands,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Edit Brand'
}
},
{
path: '/dashboard/users',
name: 'usersSettings',
component: usersSettings,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Users'
}
},
{
path: '/dashboard/users/add',
name: 'addUsers',
component: addUsers,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Add User'
}
},
{
path: '/dashboard/users/:id/edit',
name: 'editUsers',
component: editUsers,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Edit User'
}
},
{
path: '/dashboard/reviews',
name: 'reviewsSettings',
component: reviewsSettings,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Reviews'
}
},
{
path: '/dashboard/reviews/:id/edit',
name: 'editReviews',
component: editReviews,
meta: {
requiresAuth: true,
admin: true,
layout: 'admin',
breadCrumb: 'Edit Review'
}
},
// public routes
{
path: "/",
name: 'home',
component: pageHome,
meta: {
breadCrumb: 'Home Page'
}
},
{
path: "/products/:slug",
name: 'SingleProduct',
component: SingleProduct,
meta: {
breadCrumb: 'Product'
}
},
// auth
{
path: '/profile',
name: 'profile',
component: Profile,
meta: {
requiresAuth: true,
breadCrumb: 'Profile'
}
},
{
path: '/register',
name: 'register',
component: Register,
meta: {
breadCrumb: 'Register'
}
},
{
path: '/login',
name: 'login',
component: Login,
meta: {
breadCrumb: 'Login'
}
}
]
});
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
if (!store.getters.isLoggedIn) {
next({
name: 'login'
})
} else {
next()
}
}
if (to.matched.some(record => record.meta.admin)) {
if (store.getters.loggedUser.type !== 'admin') {
next({
name: 'home'
})
} else {
next()
}
}
next()
});
router.afterEach((to, from) => {
Vue.nextTick(() => {
document.title = to.pageTitle || 'Test App';
});
});
export default router;
Solved
working code
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!store.getters.isLoggedIn) {
next({
name: 'login'
})
} else {
next()
}
}
if (to.matched.some(record => record.meta.requiresAdmin)) {
// this route requires auth, check if logged in
// if not, redirect to home page.
if (!store.getters.loggedUser.type == 'admin') {
next({
name: 'home'
})
} else {
next()
}
}
else {
next() // make sure to always call next()!
}
})
Hope it help others.

Durandal subnavigation with Parameters

once again a Durandal question ^^ I'd like to make a subnavigation menu.
The subpage is called per url
<a class="btn btn-primary" data-bind="attr: { href: '#customer/'+ id }">Open</a>
The shell.js routes this to the customers/shell2.js (the child router) that you can see here:
define(['plugins/router', 'knockout', 'utility', 'logger', 'datacontext'], function (router, ko, utility, logger, datacontext) {
var displayName = 'Customer';
var cId = ko.observable(0);
var childRouter = router.createChildRouter()
.makeRelative({ moduleId: 'viewmodels/customers' , route: 'customer/:id/'});
return {
router: childRouter,
cId: cId,
displayName: displayName,
activate: activate
};
function activate() {
cId(parseInt(router.activeInstruction().params[0]));
childRouter.map([
{
route: ['', 'overview'],
moduleId: 'overview',
name: 'Overview',
hash: '#customer/' + cId() + '/overview',
nav: false,
settings: {}
},
{
route: 'sessions',
moduleId: 'sessions',
name: 'Sitzungen',
hash: '#customer/' + cId() + '/sessions',
nav: false,
settings: {}
}
]).buildNavigationModel();
}
});
In short: I want the link to be like #customer/17/overview with 17 being the route parameter for calling the subnavigation.
When i call the url #customer/17, the content of the route is displayed, but not the subnavigation. Moreover the urls #customer/17/overview and #customer/17/session don't work...
Has someone a working example where the subnav is built with parameters?
EDIT:
shell.js
define(['plugins/router', 'knockout' ,'session', 'toastr','logger', 'durandal/app']
, function (router, ko, session, toastr, logger, app) {
var routes= [
{ route: '',
moduleId: 'login',
name: 'Login',
hash: '',
nav: false,
settings: {}
},
{ route: 'dashboard',
moduleId: 'dashboard/dashboard',
name: 'Dashboard',
hash: '#dashboard',
nav: true,
settings: {}
},
{ route: 'customers',
moduleId: 'customers/customers',
name: 'Customers',
hash: '#customers',
nav: true,
settings: {}
},
{ route: 'customer/:id',
moduleId: 'customers/shell2',
name: 'customer',
hash: '',
nav: false,
settings: {}
},
{ route: 'logout',
moduleId: 'logout',
name: 'Logout',
hash: '',
nav: true,
settings: {}
}];
return {
activate: activate,
router: router,
session: session,
app: app
};
function activate() {
router.makeRelative({moduleId:'viewmodels'})
.map(routes)
.buildNavigationModel() // Finds all nav routes and makes them ready
.mapUnknownRoutes('notfound', 'notfound');
router.activate();
}
});
I guess the problem was really in the parent shell.js. I changed the route to the child shell this way:
{
// add *details for splat route, even when there is nothing named 'details'
route: 'customer/:id*details',
moduleId: 'customer/shell2',
name: 'Customer',
nav: true
}
The childrouter shell2.js looks like this:
define(['plugins/router', 'knockout'], function (router, ko) {
var displayName = 'Customer';
var customerId = ko.observable(0);
var childRouter = router.createChildRouter();
return {
router: childRouter,
customerId: customerId,
displayName: displayName,
activate: activate
};
function activate(newCustomerId) {
customerId(newCustomerId);
// resetting, otherwise every activation adds elements
childRouter.reset();
// individual mapping on each activation, so the id is updated in the hashes
childRouter.makeRelative({ moduleId: 'viewmodels/customers' , route: 'customer/:id/'})
.map([
{
route: '',
moduleId: 'overview',
name: 'overview',
hash: '#customer/'+ v6Id(),
nav: true,
},
{
route: 'sessions',
moduleId: 'sessions',
name: 'Sessions',
hash: '#customer/'+ v6Id() + '/sessions',
nav: true,
}
])
.buildNavigationModel();
}
});
P.S.: Don't forget to set 'nav' to true, that was the reason why my navigation didn't show up.
P.S.2: Perhaps you should add properties to each route to differ in the view between main-nav and sub-nav.

Categories

Resources