|
@@ -1,5 +1,280 @@
|
|
|
-# NanoBind
|
|
|
+# NanoBind - Templating and Data binding on DOM in JS
|
|
|
|
|
|
-idea:
|
|
|
+## Requirements
|
|
|
|
|
|
-DOM <-> JS (on proxies) <-> AJAX <-> Node.js two-way dataflow
|
|
|
+Support of ES6 `Proxy` object.
|
|
|
+
|
|
|
+## It's a magic
|
|
|
+
|
|
|
+Basic initialization:
|
|
|
+```html
|
|
|
+<p id='p1'></p>
|
|
|
+<p id='p2'></p>
|
|
|
+<input type='text' value="some input value" name='sampleText'>
|
|
|
+```
|
|
|
+```javascript
|
|
|
+var $s = nbInit({p1: "first paragraph"});
|
|
|
+
|
|
|
+$s.p2 = "second paragraph";
|
|
|
+
|
|
|
+alert($s.sampleText);
|
|
|
+```
|
|
|
+
|
|
|
+NanoBind gives ability to read and write data into DOM tree, using usual JS data structures: strings, booleans, arrays and objects. Access to DOM tree works
|
|
|
+on `ids`, `names`, `classes` and `CSS-Selectors`
|
|
|
+
|
|
|
+## DOM Tree search priorities
|
|
|
+
|
|
|
+When you accessing to some property in bound object (`$s` in this document), for example `$s.input` NanoBind tries to find DOM elements in next priority order:
|
|
|
+- Element with `id="input"`, if not found, it tries to find,
|
|
|
+- Element(s) by CSS-Selector "input", e. g. some tag(s) `input`, if not found, it tries to find,
|
|
|
+- Element(s) with `name="input"`. You can use it for radiobuttons, or, if not found,
|
|
|
+- Element(s) with one of classes, equals `input`.
|
|
|
+
|
|
|
+## Anisotropic dataflow
|
|
|
+
|
|
|
+**Nanobind** offers *anisotropic* behavior for data passed and read in DOM tree. I. e. when you set something to DOM and read this property, it's sometimes aren't
|
|
|
+same value.
|
|
|
+
|
|
|
+```html
|
|
|
+<select id="select">
|
|
|
+ <option value="">--</option>
|
|
|
+</select>
|
|
|
+```
|
|
|
+
|
|
|
+```javascript
|
|
|
+//filling dropdown list
|
|
|
+$s.select = {"": "--",
|
|
|
+ M: "Male",
|
|
|
+ F: "Female",
|
|
|
+ X: "Xenomorph"};
|
|
|
+//reading dropdown value:
|
|
|
+$s.select; //evaluates as "", because it's first value in list
|
|
|
+//set it to Xenomorph:
|
|
|
+$s.select = 'X';
|
|
|
+```
|
|
|
+
|
|
|
+In sample above we are populate select with options from associative array, than read value of select, and it's *not associative array*, it's *value of select*. Than we
|
|
|
+set other value for this select using `option` `value`.
|
|
|
+
|
|
|
+## Setting and templating
|
|
|
+
|
|
|
+How to set some HTML values and properties, using **NanoBind**, and how data types and structures interpreted.
|
|
|
+
|
|
|
+### Strings and Numbers
|
|
|
+
|
|
|
+Are used for setting **DOM** `value` or `innerText`:
|
|
|
+
|
|
|
+```html
|
|
|
+<span></span>
|
|
|
+<input type='number' placeholder="editable number"/>
|
|
|
+```
|
|
|
+```javascript
|
|
|
+$s.span = "Some text in span";
|
|
|
+$s.input = "45";
|
|
|
+```
|
|
|
+
|
|
|
+Please note, than both tags will be found by **CSS-Selector**. **NanoBind** will change *all* matched tags found.
|
|
|
+
|
|
|
+#### `input[type='radio']`
|
|
|
+
|
|
|
+Radiogroups works as expected:
|
|
|
+
|
|
|
+```html
|
|
|
+<label>
|
|
|
+ <input type="radio" class="radio" name="sex" value="M">
|
|
|
+ <span class="description">Male</span><br>
|
|
|
+</label>
|
|
|
+<label>
|
|
|
+ <input type="radio" class="radio" name="sex" value="F">
|
|
|
+ <span class="description">Female</span><br>
|
|
|
+</label>
|
|
|
+```
|
|
|
+
|
|
|
+```javascript
|
|
|
+$s.sex = "M"; //set to male sex, or
|
|
|
+//$s.sex = "F"; //set to female sex
|
|
|
+
|
|
|
+
|
|
|
+$s.sex; //evaluated as 'M' or 'F', depending on current radio group value.
|
|
|
+```
|
|
|
+
|
|
|
+### Boolean
|
|
|
+
|
|
|
+Booleans has two roles in **NanoBind**
|
|
|
+
|
|
|
+#### `input[type='checkbox']`
|
|
|
+
|
|
|
+On checkboxes, booleans, naturally, turns check on or off:
|
|
|
+
|
|
|
+```html
|
|
|
+ <input type='checkbox' id='check1'>
|
|
|
+```
|
|
|
+
|
|
|
+```javascript
|
|
|
+$s.check1 = true;
|
|
|
+$s.check1 = false;
|
|
|
+```
|
|
|
+
|
|
|
+#### On other elements
|
|
|
+
|
|
|
+it turns visibility on or off:
|
|
|
+
|
|
|
+```html
|
|
|
+<div class="alert alert-danger">
|
|
|
+ <strong>Error</strong>Some error happens
|
|
|
+</div>
|
|
|
+```
|
|
|
+
|
|
|
+```javascript
|
|
|
+$s["alert-danger"] = !!errorMessage; //if errorMessage is empty, turn off that div.
|
|
|
+$s["alert-danger"] = errorMessage; //and set innerText to errorMessage value.
|
|
|
+```
|
|
|
+
|
|
|
+### Arrays
|
|
|
+
|
|
|
+Usually arrays means some repeating one type data values, should be represented as list or table in `HTML`:
|
|
|
+
|
|
|
+#### `round robin`
|
|
|
+
|
|
|
+```html
|
|
|
+<div id='menu'>
|
|
|
+ <a href='#' style='color: red;'></a>
|
|
|
+ <a href='#' style='color: green;'></a>
|
|
|
+</div>
|
|
|
+```
|
|
|
+
|
|
|
+```javascript
|
|
|
+$s.menu = ["Main", "About Us", "Other links", "second green link"];
|
|
|
+```
|
|
|
+
|
|
|
+In sample above **NanoBind** create four elements `a`, using round robin, and fills them with data from array.
|
|
|
+
|
|
|
+#### Arrays and many found elements
|
|
|
+
|
|
|
+If **NanoBind** found more than one matched element with **no children** or count of elements equals array length, it set them one-to-one, w/o multiplication:
|
|
|
+
|
|
|
+```html
|
|
|
+<label><input type='checkbox' class='check'><span class='description'></span><br/></label>
|
|
|
+<label><input type='checkbox' class='check'><span class='description'></span><br/></label>
|
|
|
+<label><input type='checkbox' class='check'><span class='description'></span><br/></label>
|
|
|
+```
|
|
|
+
|
|
|
+```javascript
|
|
|
+$s.check = [false,false,false]; //turn all checkboxes with class `check` to unchecked state
|
|
|
+```
|
|
|
+
|
|
|
+In other cases every matched element will be set with array (with multiplication of subnodes)
|
|
|
+
|
|
|
+#### Arrays and recursion.
|
|
|
+
|
|
|
+**NanoBind** can fill tables with array of arrays recursively:
|
|
|
+
|
|
|
+```html
|
|
|
+<table>
|
|
|
+ <tbody id="numberTable">
|
|
|
+ <tr>
|
|
|
+ <td><input>table template line 1</td>
|
|
|
+ <td style='background-color: blue;'>table template line 1</td>
|
|
|
+ </tr>
|
|
|
+ <tr style='background-color: gray;'>
|
|
|
+ <td>table template line 2</td>
|
|
|
+ <td style='background-color: red;'>table template line 2</td>
|
|
|
+ </tr>
|
|
|
+ </tbody>
|
|
|
+</table>
|
|
|
+```
|
|
|
+
|
|
|
+```javascript
|
|
|
+$s.numberTable = [[[1],2,[3,"input"],4,5,6],
|
|
|
+ [7,8,9,10,11,12],
|
|
|
+ [13,14,15,16,17,18],
|
|
|
+ [19,20,21,22,23,24]],
|
|
|
+```
|
|
|
+
|
|
|
+Due to `input` in some `td`, some values passed as one-element array to get one level deeper into `input`. As you can see, `round-robin` works recursively on `tr` and
|
|
|
+`td` levels. Also, you may set more than one element in deepest arrays like `[1]` and `[3]` and got third level of recurrent multiplication: many `input`s in `td`.
|
|
|
+
|
|
|
+
|
|
|
+### Associative Arrays (Objects)
|
|
|
+
|
|
|
+`Objects` used for set some paired values.
|
|
|
+
|
|
|
+#### `select > option`, `ul|ol > li` and other simple cases.
|
|
|
+
|
|
|
+```html
|
|
|
+<select id="select">
|
|
|
+ <option value="">--</option>
|
|
|
+</select>
|
|
|
+```
|
|
|
+
|
|
|
+```javascript
|
|
|
+//filling dropdown list
|
|
|
+$s.select = {"": "--",
|
|
|
+ M: "Male",
|
|
|
+ F: "Female",
|
|
|
+ X: "Xenomorph"};
|
|
|
+```
|
|
|
+
|
|
|
+works as expected - multiplying option with object, using keys as `value` and values as `innerText`.
|
|
|
+
|
|
|
+#### Setting element properties
|
|
|
+
|
|
|
+Sometimes you need to set some set of DOM HTML Element properties, and you can use objects for this:
|
|
|
+
|
|
|
+```html
|
|
|
+<input id='someInput' />
|
|
|
+```
|
|
|
+
|
|
|
+```javascript
|
|
|
+$s.someInput = {type: "number", placeholder: "percents", max: "100", min: "0", value: 50, onchange: function(){
|
|
|
+ alert(this.value);
|
|
|
+}}
|
|
|
+```
|
|
|
+
|
|
|
+Event handlers can be passed as HTML Element properties too.
|
|
|
+
|
|
|
+#### Using key as class
|
|
|
+
|
|
|
+To be free from HTML structure and key order in object, you can use object keys as class name:
|
|
|
+
|
|
|
+```html
|
|
|
+<table>
|
|
|
+ <thead>
|
|
|
+ <th> age</th>
|
|
|
+ <th> married</th>
|
|
|
+ <th> surname</th>
|
|
|
+ <th> name</th>
|
|
|
+ <th> note</th>
|
|
|
+ </thead>
|
|
|
+ <tbody id="hashTable">
|
|
|
+ <tr>
|
|
|
+ <td class='age'></td>
|
|
|
+ <td><input type='checkbox' class='married'></td>
|
|
|
+ <td class='surname'></td>
|
|
|
+ <td class='name'></td>
|
|
|
+ <td><textarea class='note'></textarea></td>
|
|
|
+ <td> just some another field, not bound to data</td>
|
|
|
+ </tr>
|
|
|
+ </tbody>
|
|
|
+</table>
|
|
|
+```
|
|
|
+
|
|
|
+```javascript
|
|
|
+$s.hashTable = [{ name: "Ivan",
|
|
|
+ surname: "Ivanovv",
|
|
|
+ age: "57",
|
|
|
+ note: {value: "Buhaet", name: 'ivanovvsTextArea'},
|
|
|
+ married: true},
|
|
|
+ { name: "Petr",
|
|
|
+ surname: "Petroff",
|
|
|
+ age: "17",
|
|
|
+ note: "Tyolki v golove",
|
|
|
+ married: false,
|
|
|
+ },
|
|
|
+ { name: "Mary",
|
|
|
+ surname: "Tester",
|
|
|
+ married: true,
|
|
|
+ note: "Ovulyashka",
|
|
|
+ age: "27"} ];
|
|
|
+```
|