I'm working with an SPA that will have many different areas, each with several pages. My boss really doesn't want dozens of views and viewmodels folders with a few items in each one. How do I configure Durandal to use something like this:
/App/Areas/Login/
login.html
login.js
/App/Areas/Here/
subpage1.html
subpage1.js
subpage2.html
subpage2.js
subpage3.html
subpage3.js
/App/Areas/There/
subpage1.html
subpage1.js
subpage2.html
subpage2.js
subpage3.html
subpage3.js
I've looked at other similar questions about Areas, but don't quite know how to start. Thanks.
You can have any folder structure your heart desires. Durandal does not impose any folder structure on your application but it does have a default convention which is completely overridable.
If you are using Durandals router then you will want to look into how to configure it to find modules. There are many ways of doing this, I prefer to create my own convention by overriding the router.autoConvertRouteToModuleId
.
If you are not using the router plugin then you will have to manage the uris for your modules yourself and this is done by following requirejs' convention and using this convention along w/ durandals composition module.
Also, you can override how it finds the views to bind to your modules by overriding the viewlocators convention. Durandal provides an very simplistic way of structuring small applications right out of the box but if you need to build larger applications then it is recommended you create your own conventions.
The 'samples' project that ships with Durandal 2.0 is an example of how to accomplish what you want without having to customize the router. The example below is from that project (and also shows how to use a 'child' router). Notice how moduleId parameters in the call to 'makeRelative' and route config combine to give you whatever folder structure you want.
app/ko/index.js
define(['plugins/router', 'knockout'], function(router, ko) {
var childRouter = router.createChildRouter()
.makeRelative({
moduleId:'ko',
fromParent:true
}).map([
{ route: '', moduleId: 'helloWorld/index', title: 'Hello World', type: 'intro' },
{ route: 'helloWorld', moduleId: 'helloWorld/index', title: 'Hello World', type: 'intro', nav: 5},
{ route: 'clickCounter', moduleId: 'clickCounter/index', title: 'Click Counter', type: 'intro', nav: 4},
{ route: 'simpleList', moduleId: 'simpleList/index', title: 'Simple List', type: 'intro', nav: 3 },
{ route: 'betterList', moduleId: 'betterList/index', title: 'Better List', type: 'intro', nav: 2},
{ route: 'controlTypes', moduleId: 'controlTypes/index', title: 'Control Types', type: 'intro', nav: 1 },
{ route: 'collections', moduleId: 'collections/index', title: 'Collection', type: 'intro' , nav: 99 },
{ route: 'pagedGrid', moduleId: 'pagedGrid/index', title: 'Paged Grid', type: 'intro', nav: 98 },
{ route: 'animatedTrans', moduleId: 'animatedTrans/index', title: 'Animated Transition', type: 'intro', nav: true },
{ route: 'contactsEditor', moduleId: 'contactsEditor/index', title: 'Contacts Editor', type: 'detailed', nav: true },
{ route: 'gridEditor', moduleId: 'gridEditor/index', title: 'Grid Editor', type: 'detailed', nav: true },
{ route: 'shoppingCart', moduleId: 'shoppingCart/index', title: 'Shopping Cart', type: 'detailed', nav: true },
{ route: 'twitterClient', moduleId: 'twitterClient/index', title: 'Twitter Client', type: 'detailed', nav: 1}
])
.buildNavigationModel();
return {
router: childRouter,
introSamples: ko.computed(function() {
return ko.utils.arrayFilter(childRouter.navigationModel(), function(route) {
return route.type == 'intro';
});
}),
detailedSamples: ko.computed(function() {
return ko.utils.arrayFilter(childRouter.navigationModel(), function(route) {
return route.type == 'detailed';
});
})
};
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With