Skip to content

Instantly share code, notes, and snippets.

@danielwertheim
Last active Mar 21, 2017
Embed
What would you like to do?
Super simple SPA foundation thingie.
(function (exports) {
var app = exports.app = {
bindingContext: {
domnode: null,
model: null,
loadTemplate: function (templateName) {
return document.getElementById(templateName).innerHTML;
},
bind: function (templateName, vm) {
this.domnode.innerHTML = this.loadTemplate(templateName);
ko.applyBindings(vm, this.domnode);
this.model = vm;
},
clear: function () {
if(this.domnode !== null) this.domnode.innerHTML = null;
this.model = null;
}
},
modules: {},
router: {
registerModule: function (moduleName, module) {
if (!module.route) module.route = moduleName.toLowerCase();
if (!module.templateName) module.templateName = moduleName.toLowerCase() + '.tmpl';
Path.map('#/' + module.route).to(function () {
app.bindingContext.bind(module.templateName, new module.vm({args: this.params}));
});
},
register: function (path, handler) {
Path.map('#/' + path).to(function () {
app.bindingContext.clear();
handler({path: this.path, args: this.params});
});
},
setDefault: function (path) {
Path.root('#/' + path);
},
start: function () {
Path.listen();
}
},
init: function (bindingCtxNode) {
this.bindingContext.domnode = bindingCtxNode;
for(var moduleName in app.modules) {
this.router.registerModule(moduleName, app.modules[moduleName]);
}
this.router.start();
}
};
})(window)
(function () {
var module = app.modules.Hello = {
route: 'hello/:msg',
vm: function (req) {
this.message = ko.observable(req.args['msg']);
}
};
})();
(function () {
var module = app.modules.Bye = {
route: 'bye/:msg',
vm: function (req) {
this.message = ko.observable(req.args['msg']);
}
};
})();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Super simple SPA template</title>
</head>
<body>
<!--
This template will be mapped by convention to the Hello module.
The Hello module picks the message to display via the URL:
index.html#/hello/:msg
You could easily fetch the template via a cached ASP.Net Controller,
using AJAX.
-->
<script id="hello.tmpl" type="text/html">
<p>Hello <span data-bind="text: message"></span>!</p>
</script>
<script id="bye.tmpl" type="text/html">
<p>Bye <span data-bind="text: message"></span>!</p>
</script>
<!-- Just some fake menu -->
<a href="#/hello/sire">Hello</a>
<a href="#/bye/sire">Bye</a>
<!--
This is where the template will be loaded and where the Knockout
magic will take place.
-->
<div id="bindingContext"></div>
<script type="text/javascript" src="js/head.js"></script>
<script type="text/javascript">
head
.js('js/knockout.js')
.js('js/path.js')
.js('js/app.js', 'js/app.modules.js');
head.ready(function () {
/*
If you like you could have custom non viewmodel routes mapped.
E.g reguest for index.html#/users
app.router.register('users', function (req) {
console.log(req);
});
E.g reguest for index.html#/users/daniel
app.router.register('users/:name', function (req) {
console.log(req);
});
*/
//You need to tell what root element to use for as the main
//binding context. This is into where the HTML-template
//will be loaded before the viewmodel is bound with knockout to it.
app.init(document.getElementById('bindingContext'));
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment