Vtree

Vtree is a small library, which helps to build great front-end architectures.
Your question will be: "Why I need this? I have lots of frameworks. Isn't it just another one?"
I can't give simple answer. Vtree is not a framework, it is just a library, which helps you to initialize javascript code on your html. It is your responsibility to think of how you are going to do this. You can initialize Backbone views, or you can render some parts of your application with custom renderer, like React.js. When using Vtree, you are not tightened with framework limitations.
The main goal of Vtree is to give you an instrument, which will help you to make your javascript code modular, reusable and scalable.
Let's say we have such HTML:
<html>
<body data-view="page#body">
<header data-view="page#header"></header>
<section data-component="page#items_list">
<article data-view="item"></article>
<article data-view="item"></article>
<article data-view="item"></article>
</section>
<footer data-view="page#footer"></footer>
</body>
</html>
As you see, some DOM-elements are marked with ``
data-view
` and
`data-component
`` attributes. Those elements are important nodes. Those may be wrapper nodes for different kinds of widgets, or for sets of widgets (we call such sets of widgets "components").With Vtree you can easily initialize, for example, Backbone views, based on those data-attributes.
Page = {}
Page.Views = {}
Page.Views.Body = class extends Backbone.View
Page.Views.Header = class extends Backbone.View
Page.Views.Footer = class extends Backbone.View
Page.ItemsList = {}
Page.ItemsList.Views = {}
Page.ItemsList.Views.Index = class extends Backbone.View
Page.ItemsList.Views.Item = class extends Backbone.View
Vtree.onNodeInit (node) ->
NodeNamespace = window[node.namespaceName]
ViewConstructor =
if node.isStandAlone
NodeNamespace.Views[node.nodeName]
else
NodeNamespace[node.componentName].Views[node.nodeName]
view = new ViewConstructor($el: node.$el)
node.setData('view', view)
Vtree.onNodeUnload (node) ->
view = node.getData('view')
view.unload?()
$ ->
Vtree.initNodes()
Here we have created a simple front-end architecture in few lines of code. Elements with ``
data-view
` specify nodes, which are main elements for Backbone views. You should specify a namespace before
`#
`` sign, and then you can initialize those views from this namespace.But as you see above, some nodes don't have namespace specified, and here is where Vtree magic comes in. When namespace is not specified, Vtree thinks, that this node is here not for a stand-alone independent view (or widget, you can call it as you wish), but this node is a part of some complicated component. And Vtree automatically finds matching component, based on it position in DOM. As you see here, ``
data-view="item"
` elements are located under **page#items_list** component, and **Vtree** node will have this reference. And you'll be able to initialize this view from a right namespace. In our example it is
`Page.ItemsList.Views.Item
`. The main component node, which we call **component index node**, is also can have related Backbone view. As you'll see later, associated view
`Page.ItemsList.Views.Index
`` will be initialized for this node.But that is not the only magic. All nodes, which are child nodes for a component, share a unique componentId. And you can share some data between all of those nodes, based on this componentId. I won't describe what exact data you can share, but this is a good way to share interface state (viewModel), or some data models, common to all parts of the component.
Other advantage of Vtree, is that it works great with DOM manipulations. Let's say you've removed element from DOM. If this element is a Vtree node, then, ``
onNodeUnload
` hook will be triggered. At this moment, you can get access to data, which you've previously saved to this node. In our example it is reference to Backbone view. Here, we can perform some unloading logic. We just need to specify
`.unload
`` method in bb-view, and it'll be called automatically whenever related DOM-element will be removed.Also, Vtree gives you more methods for dealing with DOM. You can manipulate DOM with them, and be sure, that all your views will be initialized automatically. So, you receive some HTML from server. You paste it into DOM. You don't need to do anything else. All Backbone views, associated with this html, will be initialized automatically.
I'll describe Vtree API below, and won't write anything more. If you are interested, you can create really great apps, based on it. If not, it'll also work for very simple applications.
In general, the main idea of this library — I don't want to know what I need to initialize. I want to get pure html from server, insert it into DOM, and all other work, related to initialization of corresponding JS — should be made automatically.
Vtree hooks
We can get access to ``data-view
` and
`data-component
` nodes on DOM ready or whenever those nodes are being added to or removed from DOM. We should call
`Vtree.initNodes()
` on DOM ready to initialize all initial nodes. When node initialized or removed from DOM, hook functions will be called. We can add any number of those hooks with
`Vtree.onNodeInit
` and
`Vtree.onNodeUnload
`` methods. When those hooks are called, very important argument is passed to them.This argument is an instance of NodeData class, which will be described next.
NodeData class
Each Vtree node has NodeData instance, associated with it. This object contains some very important information and few methods. Here are they.isComponentIndex
true|falseIf DOM-element has ``
data-component
` specified, then this element is a wrapper for set of
`data-view
` elements. If you think of this set of views as of complicated component, than, the wrapper element for this set of views is an index element of the whole component. So, if **Vtree** node is a component index node, than this property will be
`true
``.isComponentPart
true/falseAs you see, we have different kinds of nodes. Some of them are parts of components, i.e. they don't make much sense alone.
But we can specify nodes, which are not parts of components, but are nodes for stand-alone views. And we can put them under any namespace. We can do it like this:
````html ````
Here ``
data-view
`` value is something, which consists of two parts. The first part is a namespace, and the second is an actual view name. What is namespace? It's just a place, where we can put all such independent views. (We should also put all components in namespaces.) In this case, such nodes won't be component parts, because we can use them in any part of our project, it doesn't matter under which component they are located. And such nodes will have isComponentPart equal to false.isStandAlone
true/falseSo, views, which we have described above, are not parts of components, but stand-alone views. Or independent views. For example, we can have UI namespace, which will have a number of different widgets, which can be used anywhere in our application. Such nodes will have isStandAlone equal to true.
componentId
IntegerIf current node is a component part, then, nodes, located under different component index nodes, will have different componentId's. Let's say we have such html:
````html
As you see, we have two component nodes here, which points to the same namespace. It's a problem, because, for example, we want to share different states between component views. componentId will help us, because nodes positioned under different component index nodes will have different componentId.
Stand-alone views will have componentId equal to null.
componentIndexNode
NodeDataIf current node is a component part, then, reference to this component's index node will be returned. In all other cases (i.e. if node is a component index node or a node is a stand-alone node), null will be returned.
nodeName
StringThis is just camelized name of the node:
````html
<!-- nodeName is 'AnotherWidget' -->
componentName
StringThe same as nodeName, but for component name (is null if it is stand-alone node):
````html
<!-- applicationName is 'MySimpleComponent' -->
namespaceName
StringNamespace name. For stand-alone nodes it will be namespace, specified in ``
data-view
` attribute before
`#
` sign. For component index nodes it will be the same — namespace, specified in
`data-component
` attribute before
`#
`` sign. For component child nodes it will be component's namespace:````html
<!-- namespaceName is 'App' -->
nodeNameUnderscored
StringThe same as nodeName, but in underscored form.
componentNameUnderscored
StringThe same as componentName, but in underscored form.
namespaceNameUnderscored
StringThe same as namespaceName, but in underscored form.