📜 ⬆️ ⬇️

RainyJs - as Angular, only for Ajax

I am not a fan of bicycles. Before starting to develop my own solution of a trivial task in my opinion, I always spend a lot of time looking for existing libraries or modules. And not because my code will obviously be worse than third-party. Just why invent something that has already been created, tested and debugged. It is much better to spend time on creating something new, non-invented until now. However, this time I still had to get behind the development myself. The article focuses on a convenient js-library that allows you to "link" data.

What started it all or what is missing Angular


First of all, I will list the tasks that I had to face and which could not be solved by existing libraries. Examples will be given for Angular, but the same fully applies to Angular Light, and to many other libraries. So let's go ...

01) One-way data binding


This is strange, but I could not understand how to implement one-way data binding. In my work, I mainly use the Yii2 framework, and here is the simplest task for you: to generate an input field (input) and associate it with a block (div). It would seem simple-simple, en-no: when generating inputa, although it has its value set, angular does not take this value into account and takes the value of the “model”, which is empty when the page is loaded.

Alternatively, one could use the "ng-init" directive (or "al-init" for Angular Light), and for the simplest cases, the problem will indeed be solved. But there is one thing: if you use dynamic data update components (such as Editable), you get the following: you change the value, save it => you need to update the binding => and when you update the binding, the value from “ng-init” is taken again, which is not relevant. The trouble is ...
')

02) Model-View-Controller


Now stones will fly into me, but I am against using the MVC scheme when displaying html pages.

For large and large projects with a complex structure - yes, for projects related to the display of graphics, where several types may be required for one element - yes, but why use this mechanism when displaying the simplest pages? After all, the result is the following: the html-code of the element is in one place, the template for its display in another, and the controller is generally somewhere in the scripts at the top of the page. As a result, instead of a simple visual structure, something cumbersome and unwieldy is obtained, where in order to copy any element for reuse in another project, you have to shovel the whole page, to penetrate into the whole logic of its functioning.

In my humble opinion, if you have, say, cool watches on the page, then all the logic of this element, including scripts and styles, should be in one place. Then, if you wish, you can easily select / copy / paste it - and voila, it also works in your other project, without any yaw through the scripts and controllers.

03) Dynamic content loading


It is this problem that became the decisive factor for starting the development of your own solution. In fact, the previous points, in principle, can be solved through crutches and piles of unnecessary code. But with the update links after downloading the contents of all sad.

Data binding in Angular, as you know, is performed only when the page loads. But what to do if the content is dynamically generated or loaded via ajax requests, i.e. if you want to bind after the initial download? The only way that was discovered was to use $ scope. $ Apply () in the controller. It would seem that a solution is found? By no means. The fact is that in the content that came from the server and uploaded to the page, there may also be (and will be) elements that require data binding. How to be in this case? Do not push all possible site algorithms into one big mega-controller.
Or another example: what to do when there are blocks in the loaded content, the contents of which are also loaded or dynamically generated? I am far from special in Angular, and perhaps there are ways to accomplish these tasks. But most likely it will be far from easy and very cumbersome.

RainyJs - installation and quick start


The library is fully autonomous and weighs only about 7Kb in compressed form.

To use, simply download the rainy.js file and connect it to your page.
The initial data binding, as in Angular, is performed automatically when the page is finished loading. But data binding is also performed during ajax-loading of content, and in this case only the directly loaded page fragment is processed.

For a “direct” update of links (for example, after dynamically creating an element), you can call the rainy (elem) function, where you can pass a selector, a dom element, or even a jQuery object as a parameter. If you call this function without parameters, it will update the links on the entire page.

Basic data binding directives


Now the library contains only 12 directives, which makes it fairly easy to learn.

The main directives are "rxname" and "rxdata" . The first is set to the source element and sets the name of the variable, the second is set to the receiving element and indicates the name of the variable from which you want to take data. If data is to be obtained from several sources, then the list of variable names separated by spaces is placed in the "rxdata".

An example of use is shown below:

<label> :</label><br> <input rxname="var01" value="World"><br> Hello, <span rxdata="var01"></span>! 

[Edit]

Prefixes and postfixes in the mapping


Quite often, webmasters need to slightly correct the resulting display (for example, add the “rub.” Postfix for the entered amount). For such formatting, you can use the "rxview" directive, inside which you can use the following templates (the templates are written in double curly braces):


An example of use is shown below:

  <label>  :</label><br> <input rxname="var02" style="width:150px;" type="range"> <div rxdata="var02" rxview=" : {{value}}%"></div> 

[Edit]

Display / Hide a data block


Another common task is to display / hide a text block by a flag or by some condition. For these purposes, a separate directive "rxshow" . As its value, you can place either the name of the variable or the js-code of the trigger condition.

An example of use is shown below:

  <input rxname="var03" type="checkbox"> <label>    </label><br> <div rxdata="var03" rxshow="value">        . </div> 

[Edit]

Execution of any code on the element


The next directive to be discussed is “rxcode” . It is designed for more complex data binding options and is a js code that will be executed in the receiver element before updating its contents. Here you can either override the set value, just returning a new one, and cancel the change altogether, returning undefined .

Also, this directive is used to execute absolutely any code on an element. For example, you can change the class of an element or make it inaccessible through it. I know, I know, in angular for this purpose separate directives are set aside and for changing the class it is enough just to set the attribute value. I admit, and I also had thoughts about this, but in the end I decided not to produce unnecessary parameters, because simplicity is the key to success.

The following variables are available inside rxcode:


An example of use is shown below:

  <label>     :</label><br /> <input rxname="var05" value="2" type="number"><br> <div rxdata="var05" rxcode=" if(value < 0){ self.classList.add('red'); } else { self.classList.remove('red'); } return ' : ' + (value||0); "></div> 

[Edit]

Ajax load element content


And finally, we came to the most important thing, for which, in fact, the library was created. There are also only two directives that can be installed in the receiver: "rxajax" and "rxload" .

In [rxajax] you should specify the path to the script that returns the new content, i.e. request template. This request is sent using the GET method, and the JSONP format is used for data transfer. In the query text, you can use the same wildcard patterns as in the "rxview" directive.

The “rxload” directive may contain js code that will be executed after loading new content into the element. It should be noted that this directive can be used not only for ajax-loading of content, but also for any other elements. This can be very useful, for example, when using jQuery plug-ins, since most of them “connect themselves to the elements” only during the initial page load.

An example of using "rxajax" is shown below:

  <select rxname="var06"> <option disabled=""> ...</option> <option selected="" value="1">Mozilla Firefox</option> <option value="2">Google Chrome</option> <option value="3">Internet Explorer</option> <option value="4">Opera ReMix</option> </select> <div class="bold" rxdata="var06" rxajax="http://x-rainy.org/getajax.php?select=browser&value={{value}}" rxview="..."> </div> 

[Edit]

Some more examples of using


This library is designed for one-way data binding, but organizing two-way binding is also not a particular problem:

    :<br /> <input rxname="var51a" rxdata="var51b" /><br /> <input rxname="var51b" rxdata="var51a" /><br /> 

[Edit]

Sometimes the checkbox "Select all" is simply necessary. Now it's easier than ever:

  <input type="checkbox" rxname="var44">  <br /> <input type="checkbox" rxdata="var44">  â„–1<br /> <input type="checkbox" rxdata="var44">  â„–2<br /> <input type="checkbox" rxdata="var44">  â„–3<br /> 

[Edit]

And another quite interesting example: when the price or quantity changes, the amount is automatically recalculated, and when the amount changes, the price is automatically set:

  <div><label>-: </label><input type="number" rxname="m_count" value="0" /></div> <div><label>: </label><input type="number" rxname="m_price" value="0" rxdata="m_count m_summa" rxcode=" if(rxname.toLowerCase() !== 'm_summa')return undefined; return ((values['m_count']||0) != 0) ? (values['m_summa']||0) / values['m_count'] : 0; "/> </div> <div><label>: </label><input type="number" rxname="m_summa" value="0" rxdata="m_count m_price" rxcode="return (values['m_count']||0) * (values['m_price']||0);"/> </div> 

[Edit]

Instead of conclusion


I am a supporter of dynamically developing projects, so I will welcome any tips and suggestions for improving the code. The only thing to consider is that the costs must be commensurate with the added features. For example, writing a bunch of lines of code to support IE6 makes no special sense. Just because if a potential client still uses such old stuff - this is definitely not our client.

Links to external resources


x-rainy.org - official library website

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


All Articles