📜 ⬆️ ⬇️

CornerJS, or “as in AngularJS” directives, only better

image

Constantly creating complex web projects from scratch, you begin to notice that about a third — and in some cases half or more — of the code is in fact autonomous, and is tied only to a specific DOM element.

In work projects, it can come down to something like
')
function pageChange(){ if ($('.element-carousel').length>0) {$('.element-carousel').initCarousel()} if ($('.element-scrollbox').length>0) {$('.element-scrollbox').initScrollbox()} … 


Or it may not be reduced, and in each conventional controller (callback to change a certain page) we call the code associated with certain elements.

Familiar? I think yes. Do you think this approach is wrong? If the first answer is yes, then I am sure that the second answer is also yes.

Want to know how to do it right, neat and beautiful?

Directives

In AngularJS there is, as they write, a unique feature - directives. But now she is not really unique.
A good article about them was already on Habré .
I will not retell the entire contents of the article, I will repeat just one sentence:
Directives can and should be used to increase the modularity of your application, to isolate separate functionality into components, including for reuse.

AngularJS directives essentially have only one big, fat minus: they cannot be used without AngularJS itself, you face the fact that you need to build an ng application with its inherent structure and markup.
Therefore, four months ago, the development of a solution began to allow one to create the same individual element-specific tasks.

How it works?

The implementation works on MutationObserver (for those who are not in the know - the browser’s native events to change the DOM tree) with a polyfill running on mutation events (DOMSubtreeModified and the like). Polyfill is really only needed for IE, since all other desktop browsers already support native MutationObserver.
Unfortunately, even with the polyfill, the native browser android 2.3 is not supported, which is really sad, but in 4.0 all tests pass steadily.
Theoretically, “manual” —calling the need for checking for directive updates — directive support is possible in almost any mobile and desktop browser, starting with IE6.

Start

The syntax was originally defined:

 directive('name', function(node){ alert("i'm alive!") }) 


At first it was supposed to make the target element this, but because of the large number of callbacks (before which you had to write var _this = this each time), it was decided to put it in the first argument.
Next, the syntax has been extended to another option:

 directive('name', { load: function(node){}, unload: function(node){} }) 


The load event is associated with the appearance of a directive (not an element), unload corresponds to its removal.
Why exactly with the advent of the directive? Because they can both be prescribed initially, and added and removed in the process of working with an element. A simple example - this directive will be called if the element changes from
 <div class="container something"> 

on
 <div class="container test something"> 


Useful this

So that callbacks could pass each other values ​​- they got the general this. So it is quite possible to do this:

 directive('name', { load: function(){ this.interval = setInterval(function(){}, 1000) }, unload: function(){ clearInterval(this.interval) } }) 


In some cases, it is convenient to create external methods for interacting with the content: for example, a presentation with the possibility of transition. Skop itself is available for this - it is one of the attributes of the node - so for the test directive it will be node.directiveTest.
As a result, the creation of public methods for directives becomes simple and convenient:

 directive('name', function(){ this.publicMethod = function(a){alert(a)} }) 


HTML syntax

Classes, attributes, and tags were set as targets for directives, and from the very beginning it was assumed that the 'data -' prefix could be used (in fact, the default configurator currently has one more prefix, 'directive-'. This is for readability of classes: div class = "directive-scrollbox" is much clearer than div class = "scrollbox").
Accordingly, such a directive will be executed in the following scenarios:

 <div class="name"/> <div class="data-name"/> <div name/> <div data-name="john"/> <name/> <data-name first-name="john" last-name="doe"> 


Work with attributes

The decision to transfer the data from the attributes requested by itself. For directives in attributes, an attribute value transfer script was set, for directive tags, an object is formed of all attributes. As a result, in the examples above, in the first case, 'john' will be transferred, in the second - {'First-name': 'john', 'last-name': 'doe'}.
For a more "smart" data transfer, support for the "short" syntax of the object has appeared: you can write the name = "first: 'john', jast: 'doe'". actually something like going on inside

 try {value = eval( '{' + value + '}' )} try {value = eval( value )} return value 


Attributes can change, and there is also a separate callback for changing them:

 directive('name', { alter: function(){} } 


In some cases - for example, for directives like

 directive('include', function(node, path){ $.get(path, function(data){node.innerHTML = data}) }) 


actions on loading and modifying an attribute are repeated. Therefore, if the action on the load is not specified, it is automatically taken from alter, which again reduces the amount of generated code.

As a result, we received a tool that allows you to completely abstract away from the element-specific things that we need to run.

Examples

Of the large directives that are already used in some projects, one of the most enjoyable is the scrollbox , an automatic “wrapper” for any element that places a custom scroll on the element.

JsFiddle example

This is a simple and convenient way to work with drag-n-drop files . Just drag the file to the gray square.
JsFiddle example
Yes, the code is a bit large, but if you add jQuery, it will be about 2 times shorter.

And here is a repetition of the published a couple of months ago on the habre solution for developers. In order to feel all the fascination of the solution, you will need to get into the web development panel and manually change the repeat value of any of the cloned elements. If you delete an attribute, the element becomes single, after which you can add the attribute again.
JsFiddle example

For those who want to try cornerJS in their projects - the minified and regular versions are here:
CornerJS repository on github

Source: https://habr.com/ru/post/192740/


All Articles