A lightweight MVC framework inspired by AngularJS (not Angular 2).
This is mostly a trimmed-down version of AngularJS with a few important differences that make it more usable. It is also more efficient because it relies on Proxy objects to detect changes rather than evaluating the entire model every time.
Import the latest build and initialize mvc.js by adding the mvc-app
attribute
to an element of your choice (typically the document body):
<html>
<head>
...
<script src="mvc.min.js"></script>
</head>
<body mvc-app>
...
</body>
</html>
Much like in AngularJS, you can use mvc-cloak
to prevent showing template DOM before mvc.js has a chance to render it, but you'll have to style it on your own (mvc.js only removes the mvc-cloak
attribute or CSS class after rendering).
<html>
<head>
...
<style>
[mvc-cloak] {
display: none !important;
}
</style>
<script src="mvc.min.js"></script>
</head>
<body mvc-app mvc-cloak>
...
</body>
</html>
Much like AngularJS, mvc.js has directives that affect the HTML elements to which they're attached and can be specified as HTML attributes (e.g. mvc-if
) or elements (e.g. mvc-include
).
When a DOM tree is bound to a model (either explicitly with MVC.bind()
or implicitly using mvc-app
) the tree is walked depth-first and for each node, each registered directive decides whether or not it can attach itself to the node. When a directive attaches itself to a node it takes responsibility for any changes performed on the node while keeping in mind that the next directives in the chain may also decide to attach themselves to the same node and perform other changes. Possible changes include even eliminating the node from the tree (cfr. mvc-if
) or replicating it many times (cfr. mvc-for
).
The order in which existing directives are executed on each node is well defined and it's very important to determine how each element works, e.g. what fields can be fecthed from the model by each directive. Built-in directives are executed in the following order:
This means, for example, that mvc-if
can access fields that are added to the model by mvc-for
, such as the iteration variable, the $index
variable, and so on, because mvc-if
runs after mvc-for
.
mvc.js supports the double curly bracket syntax for HTML attributes and text elements. They get updated automatically as the model changes. Example:
<p mvc-controller="MyController" class="first-class {{secondClass}} third-class">
The quick brown {{jumper}} jumps over the lazy {{jumpee}}.
</p>
MVC.Controllers.register(function MyController(model) {
model.secondClass = 'second-class';
model.jumper = 'fox';
model.jumpee = 'dog';
});
In the above we used mvc-controller
to change the secondClass
, jumper
, and jumpee
variables in the model.
TBD
mvc-include
elements are automatically replaced with the HTML code of the specified template. Templates are identified by unique names and can be either provided to the JavaScript API or as HTML5 <template>
elements.
The following:
<body mvc-app>
<mvc-include template="template1"></mvc-include>
<mvc-include template="template2"></mvc-include>
<template id="template2">
<p>Paragraph 2.</p>
</template>
</body>
MVC.Templates.registerFromString('template1', `
<p>Paragraph 1</p>
`);
is equivalent to the following:
<body>
<p>Paragraph 1.</p>
<p>Paragraph 2.</p>
</body>
Templates may contain other directives. The following:
<body mvc-app>
<mvc-include template="paragraphs"></mvc-include>
<template id="paragraphs">
<p mvc-for="i in [1, 2, 3]">Paragraph {{i}}.</p>
</template>
</body>
is equivalent to:
<body>
<p>Paragraph 1.</p>
<p>Paragraph 2.</p>
<p>Paragraph 3.</p>
</body>
The content of an mvc-include
element itself is transcluded in the template if the template has one or more transclusion points. Transclusion points are marked by the <mvc-transclude>
element. For example:
<body mvc-app>
<mvc-include template="dialog">
<p>The quick brown fox jumps over the lazy dog.</p>
</mvc-include>
<template id="dialog">
<dialog open>
<mvc-transclude></mvc-transclude>
</dialog>
</template>
</body>
is equivalent to:
<body>
<dialog open>
<p>The quick brown fox jumps over the lazy dog.</p>
</dialog>
</body>
TBD
Adds or removes a DOM node conditionally based on an expression.
Example:
<body mvc-app>
...
<div mvc-if="var1 && var2">
...
</div>
...
</body>
The <div>
element and its content are kept in the DOM iff both model fields var1
and var2
are true
(or other non-falsey JS values).
TBD
TBD
TBD