📜 ⬆️ ⬇️

Translation of RivetsJS documentation

Little about motives


Good day, dear habrovchane. Some time ago, I met the RivetsJS library. I liked it, although it contains only tools for data-binding. I just want to say that I am not even going to argue, there are wonderful AngularJS and other frameworks for these things, but personally I don’t see any reason to connect such a powerful tool as Angular if I need only a small amount of its capabilities. Therefore, for these purposes, I chose RivetsJS. And so, inspired by the idea of ​​translating his documentation into Russian, I am writing this article. The motive is simple - to tell about this library, and I have not found anything better than just translating its documentation, which, perhaps only in my opinion, is written in a bit of “broken” English. So let's go.

PS Immediately ask for forgiveness, this is my first translation, maybe I'm not a super-duper translator. If something seems ridiculous to you or you find a mistake, please report it to me, I will correct it immediately. Thank you in advance.

RivetsJS Documentation


')

Hyde





Directory





Hyde


Installation

You can download the latest stable version on GitHub , or install using the package manager of your choice. We currently support releases on at npm, component, jam, bower (recommended).

bower install rivets 


Rivets has a close relationship with Sightglass . If you want to connect the Sightglass separately, make sure to connect it first.

 <script src="bower_components/sightglass/index.js"></script> <script src="bower_components/rivets/dist/rivets.min.js"></script> 


Alternatively, you can plug in the Rivets package, which contains both libraries.

 <script src="bower_components/rivets/dist/rivets.bundled.min.js"></script> 


Note: The CommonJS module and AMD script loaders such as RequireJS and almond are fully supported if you need it.

Using

Templates

The template forms your UI in plain HTML. You can define them directly in the document using template elements, or store and load them the way you like. Just use a convenient way to output data to the template.

 <section id="auction"> <h3>{ auction.product.name }</h3> <p> : { auction.currentBid | money }</p> <aside rv-if="auction.timeLeft | lt 120"> !     { auction.timeLeft | time }. </aside> </section> 


Important elements in this example are the addition of an attribute with the prefix “rv-” , as well as the selection and wrapping of sections in "{...}" . These elements are a binding declaration, and this is a way to transfer your data to templates. All ads use short and expressive syntax.

(keypath | ) [...]


Keypaths receive observation data and revise the binding when changes occur. Primitives can be string, number, boolean, null or undefined.
More details about the formatters, their properties and capabilities will be discussed in the relevant chapter.

Binding

Just call rivets.bind on the element in the template and pass it the data that you want to display.

 rivets.bind($('#auction'), {auction: auction}) 


Each time rivets.bind is called, the full data set is returned. Use view.unbind () to stop the binding event.

Configuration

Use rivets.configure to set preferences for the application. Note that if required, all settings can be replaced locally on a specific view.

 rivets.configure({ //     prefix: 'rv', //     -. preloadData: true, // Root sightglass interface for keypaths rootInterface: '.', //       templateDelimiters: ['{', '}'], //    on-* binder handler: function(target, event, binding) { this.call(target, event, binding.view.models) } }) 


Binders

Binders are sets of instructions that tell Rivets.js how to update the DOM when the observed properties change. Rivets.js comes bundled with frequently used Binders for your convenience. See the “Handbook” to learn how to use the built-in binders that come “in the box” with Rivets.js.
At first, you can perform basic UI tasks with built-in binders, but it is strongly recommended to extend Rivets.js with your own binders that are specific to the execution of your application tasks.

Single sided binders

One-sided binders update the DOM when the model properties change (only the model-view). Let's say we just need a binder that updates the color of the element when the properties of the model change. Here we can define a one-way binder by a simple closure. The function accepts the element and the current value of the model property, which we will use to update the element property.

 rivets.binders.src = function(el, value) { var href = "/my/path/to/image/" + value el.setAttribute("src ", src); } rivets.binders.alt = function(el, value) { var alt = value el.setAttribute("alt", alt); } 


With the specific binders above, you can use “ rv-src ” and “ rv-alt ” in your template.

 <img rv-src="data.image" rv-alt=”data.title” /> 


Bilateral Binders

Bilateral binders, as well as one-sided, can update the DOM when the model property changes (model-view), but can also update the model when the user interacts with the DOM (model-view), such as updating the personal account, entering the data for authorization and clicking submit, or interaction with third-party widgets.
In order to update the model when the user interacts with the DOM, you have to tell Rivets.js how to bind and unpin this DOM element to set the value in this model. Instead of declaring a binder as a simple closure function, two-way binders are declared as objects containing several additional functions.

 rivets.binders.toggle = { bind: function(el) { adapter = this.config.adapters[this.key.interface] model = this.model keypath = this.keypath this.callback = function() { value = adapter.read(model, keypath) adapter.publish(model, keypath, !value) } $(el).on('click', this.callback) }, unbind: function(el) { $(el).off('click', this.callback) }, routine: function(el, value) { $(el)[value ? 'addClass' : 'removeClass']('enabled') } } 


API

binder.bind
This function is called to initialize view.bind (). Use it to store the initial state of the binding, or to assign event listeners to the element.

binder.unbind
This function is called to initialize view.unbind (). Use it to reset any element state that binder.routine would modify, or unlink any event listeners to the element that you set in the binder.bind function.

binder.routine
The template function is called when the observed attribute of the model changes and is used to update the DOM. When a one-way binding is declared as a simple closure function, it is in fact a routine function (routine function) that you define.

binder.publishes
Set the value to true if you want to call view.publish () and publish these binding.

Formatters

Formatters are functions that modify incoming and / or outgoing values ​​of binding. You can use them to format dates, numbers, currencies, etc. Formatters are very useful when you need to process the output, and in order not to load the server, you can load the client. For example, you get a date from the server in timestamp format. With the help of a formatter, you can convert the timestamp directly to the date format by writing just one function and use it throughout your binding.

One-sided formatters

These are by far the most common and practical ways to use formatting — simple modifications of read-only values. In the example below, we can determine the formatter of the number of days remaining until the end of any event. Suppose that until the end of the event there are 3 days left.

 rivets.formatters.remain = function(value){ value = parseInt(value / 86400); return value; } 

Formatters are used when declaring a binding, the symbol "|" used as a delimiter.

 <span rv-text="event.endDate | remain"></span> 


Bilateral formatters

Bilateral formatters are useful when you want to store values ​​in a specific format, such as the value in dollars, but at the same time allow the user to enter data in another format, such as rubles.
Instead of declaring the formatter as a simple closure function, you can declare it as an object containing the read and publish functions. When the formatter is declared as a simple closure, Rivets assumes that it will be read-only, but when the formatter is declared as an object, Rivets uses the read and publish functions to efficiently serialize and reverse the conversion of values.
Let's say we want to store the monetary value in dollars, but let the user enter this value in rubles, and the formatter automatically converts these values ​​at the value in the foreign exchange market (we omit the moment this value is loaded there) when entering this value into the model. Just for this purpose, we will use a two-way currency formatter.

 rivets.formatters.currency = { read: function(value) { return (value / 50) }, publish: function(value) { return Math.round(parseInt(value) * 50) } } 


Now you can make a binding, using a formatter with any type of binding - one-sided or two-sided.

 <input rv-value="item.price | currency"> 


Please note that you can also bind bidirectional formatters with any other, and in any order. They are read from left to right, and are published from right to left, skipping any read-only formatters when they publish (insert) data back into the model.

Arguments Formatters

Formatters can take any number of arguments in the form of keypaths and primites.
Formatters can separate values ​​using the "|" character.
Formatter arguments can be keypaths and primitives. Keypaths as arguments of the formatter inherit all the properties and capabilities of ordinary keypaths .
(Formatters) [keypath | Primitive...]

 <span>{ alarm.time | time user.timezone 'hh:mm' }</span> 


The value of each argument in the binding declaration will be evaluated and passed to the formatting function as an additional argument.

 rivets.formatters.time = function(value, timezone, format) { return moment(value).tz(timezone).format(format) } 


Components

Components allow you to define reusable types that can be used in any of your templates. This is useful where components need to be embedded in your template in connection with binders; Binders define your own attributes, while components are defined as own elements.
The component object must be defined as a template function that returns a template for the component (it can be an HTML string, or another necessary element). It should also define an initialize function that returns a special scope object for binding to a template (this function has some similarity with MVC).

 rivets.components['todo-item'] = { //    . template: function() { return JST['todos/todo-item'] }, //          // (  rivets.init      . initialize: function(el, data) { return new ItemController({ item: data.item }) } } 


To use a component within a template, simply use an element with the same tag name as in the component key. All element attributes will be interpreted as keypaths before inserting an initialize component into a function.

 <todo-item item="myItem"></todo-item> 


Additionally, if you want a certain attribute to be static, instead of a keypath, you can give it a static property.

 rivets.components['todo-item'] = { static: ['list-style'], … } 


 <todo-item item="myItem" list-style="condensed"></todo-item> 


Components can also be initialized by themselves outside the template. This is useful when you want to insert a new view into your DOM yourself, for example, as a modal window that appears when you first open your application. This API is similar to rivets.bind, except that instead of transferring the current template \ element, you only pass the name of the component and its class \ identifier \ tag of the parent element in which you want to render this component template.

 rivets.init('my-app', $('body'), {user: user}) rivets.init('todo-item', $('#modal-content'), {item: myItem}) 


Adapters

Rivets.js is agnostic with respect to objects and their description. This makes it very flexible, and it can adapt and adapt for development along with other libraries and frameworks, but it also means that you have to tell Rivet.js how it should describe certain objects. This feature is managed by the Sightglass library.
Each adapter is defined as a unique interface (single character) that is used to separate keys and keypaths. The interfaces used in keypaths determine which adapter to use for each intermediate key.

user.address:city


In the example above, the keypath uses the adapter "." to access the address key of the user object, and the adapter ":" to access the city's key of the address object. Imagine for a second that the address is normal, a property of the user object pointing to the Backbone model, but the city is actually an attribute of the Backbone model, you can see how this type of designation is actually concise and expressive.

Built-in adapter

Rivets.js comes with an adapter "." describing the properties of simple javascipt objects. This adapter is already implemented in ES5 (ECMAScript 5), using the example of Object.defineProperty. In the future, this adapter will be implemented using Object.observe exclusively, as soon as browsers start supporting it.
If you need to use browsers without ES5 support (<IE 9), you can replace this adapter with polyfiles or third-party libraries supported by the browser you need. If you plan on using Chrome for example, try using Object.observe now and see the result.

Creating an adapter.

Adapters are defined using rivets.adapters with interfaces as the property name and an adapter object as the value.
The following ":" adapter works for both Backbone.js models and Stapes.js modules.

 rivets.adapters[':'] = { observe: function(obj, keypath, callback) { obj.on('change:' + keypath, callback) }, unobserve: function(obj, keypath, callback) { obj.off('change:' + keypath, callback) }, get: function(obj, keypath) { return obj.get(keypath) }, set: function(obj, keypath, value) { obj.set(keypath, value) } } 


Calculated properties

Calculated properties are functions that receive data on revaluation in the case when one or more dependent properties change. The design properties are declared in Rivets.js quite simply, just separate the function from its dependency with the help of the "<" sign. The following example of binding will be re-evaluated using event.duration () when the start or end attributes change.

 <span rv-text="event.duration < start end"></span> 


Note that the dependent keypath is taken from the target object, and not from the context of the model. So for the example above, the target is an event object, with the dependencies event.start and event.end.

Bindings iterations.

Use the rv-each- [item] binder, which is represented in Rivets.js, to loop through all the elements of an array and add related instances of this element.

 <ul> <li rv-each-todo="list.todos"> <input type="checkbox" rv-checked="todo.done"> <span>{ todo.summary }</span> </li> <ul> 


Directory


text


Text output to item
 <h1 rv-text="user.name"></h1> 

You can also output text using interpolation.
 <p>{ user.name } is { user.age } years old.</p> 

html


Output HTML content to an element.
 <section rv-html="item.summary"></section> 

show


The output element depending on the value - if true, then the output, if false, then hide.
 <button rv-show="user.admin">Remove</button> 

hide


Reverse attribute rv-show, if the value is set to true, then hide, if false, then output.
 <section rv-hide="feature.disabled"></section> 

enabled


An attribute that specifies the activity of elements. True - the element is enabled, false - disabled.
 <button rv-enabled="user.canVote">Upvote</button> 

disabled


Reverse attribute rv-enabled. True - disabled, false - enabled.
 <button rv-disabled="user.suspended">Upvote</button> 

if


Inserts and binds the element, as well as the nodes (nodes) in the DOM when the value is true, and does not output the elements when the value is regarded as false.
 <section rv-if="item.editable"></section> 

unless


Reverse attribute rv-if.
 <section rv-unless="item.locked"></section> 

value


Sets the value of the element when the attribute changes, and sets the value of the associated object when the input element changes from user input (works in both directions).
 <input rv-value="item.name"> 

checked


Easy to guess intended for and. Sets the “checked” attribute when the value is regarded as true, and removes the “checked” attribute when the value is regarded as false. Also sets the value of the associated object when the checkbox element changes from user input (works both ways).
 <input type="checkbox" rv-checked="item.enabled"> 

unchecked


Attribute, reverse rv-checked.
 <input type="checkbox" rv-unchecked="item.disabled"> 

on- [event]


Bindit the event listener to the element using the event specified in [event] and the associated object (must return a function) as a callback
Note: If the final value of the binding changes to another function, this binder will automatically unlink the old callback and bind the new event listener to the new function.
 <button rv-on-click="item.destroy">Remove</button> 

each- [item]


Adds a new instance of the element for each element in the array. Each element is associated with a completely new nested view that contains an additional property that points to the current iterated element of the array.
 <ul> <li rv-each-todo="todos"> <input type="checkbox" rv-checked="todo.done"> { todo.name } </li> <ul> 


PS If there is interest in this documentation, I will supplement it with “live” examples.

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


All Articles