Sorry my poor English, my native language is Pascal.
here: http://nanobind.asmer.fe2.a-level.com.ua/static/
MIT
Instead of write loops in code and/or template, just give a structure and get a view.
Good HTML declarative enough, to avoid using some template engine markers like {{ varname }}
, {% control structure syntax %}
and so on. Also, usually template loops
requires some loopable data structure, passed into temlate engine to render.
It's not jQuery, Angular or Meteor. It's just a way to put and get data from DOM Tree more transparent and declarative. And NanoBind does nothing to conflict with any other framework.
Support of ES6 Proxy
object.
Basic initialization:
<p id='p1'></p>
<p id='p2'></p>
<input type='text' value="some input value" name='sampleText'>
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
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:
id="input"
, if not found, it tries to find,input
, if not found, it tries to find,name="input"
. You can use it for radiobuttons, or, if not found,input
.This selectors changes default nanobind behaviour about data structures (cloning, round-robin, object-to-class assignements, nested structures, and so)
|dom
some selector|dom
says to nanobind than assigning structure isn't a subobject for nested tags, but dom object to assign to exactly this element(s).
|closure
some selector|closure
says to nanobind than assigning array isn't for default array nanobind behavior, but function with params, which initializes some plugin at matching elements. Function runned by nanobind, and should return a closure function
to read plugin status:
$s['somePluginContainer|closure'] = [function(value, options){
this.value = value
return function(){
return this.value
}
},
'someDefaultValueForInput']
....
alert($s['somePluginContainer|closure'])
When you set array to |closure
selector, nanobind runs your function (first in array) with this
set to matched element(s) (i. e. #somePluginContainer
in sample above). When you read this selector, nanobind runs function, returned by passed function
when set.
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.
<select id="select">
<option value="">--</option>
</select>
//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
.
How to set some HTML values and properties, using NanoBind, and how data types and structures interpreted.
Are used for setting DOM value
or innerText
:
<span></span>
<input type='number' placeholder="editable number"/>
$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:
<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>
$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.
Booleans has two roles in NanoBind
input[type='checkbox']
On checkboxes, booleans, naturally, turns check on or off:
<input type='checkbox' id='check1'>
$s.check1 = true;
$s.check1 = false;
it turns visibility on or off:
<div class="alert alert-danger">
<strong>Error</strong>Some error happens
</div>
$s["alert-danger"] = !!errorMessage; //if errorMessage is empty, turn off that div.
$s["alert-danger"] = errorMessage; //and set innerText to errorMessage value.
Usually arrays means some repeating one type data values, should be represented as list or table in HTML
:
round robin
<div id='menu'>
<a href='#' style='color: red;'></a>
<a href='#' style='color: green;'></a>
</div>
$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.
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:
<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>
$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)
NanoBind can fill tables with array of arrays recursively:
<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>
$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
.
Objects
used for set some paired values.
select > option
, ul|ol > li
and other simple cases.<select id="select">
<option value="">--</option>
</select>
//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
.
Sometimes you need to set some set of DOM HTML Element properties, and you can use objects for this:
<input id='someInput' />
$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.
To be free from HTML structure and key order in object, you can use object keys as class name:
<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>
$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"} ];
NanoBind attaches your data to DOM HTML Element when you set it as nbData
property, and use it as "template" for read. But, in some cases it doesn't returns updated
data, but other value.
Can't be returned at all, because DOM doesn't use numbers even for number properties like value
in li
or value
in input[type='number']
.
Are usual result of any read for primitive values.
Returned only when input[type='checkbox']
reading. You can't read visibility status as boolean
.
...like textarea
, select
, input
works as expected - returns what user has selected or entered into inputs.
...reading recursively, as passed when set. But some collisions possible with nested inputs.
simple sample of editable data set with minimal event handling
<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><button class='btnDel'>x</button></td>
</tr>
</tbody>
</table>
var persons = [{ 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"} ];
$s.hashTable = persons;
function btnDel(){
var thisLine = this.parentElement.parentElement;
thisLine.remove();
$s["#hashTable tr:first-child button"] = false; //turn off first delete button
};
$s.btnDel = {onclick: btnDel};
$s.addPerson = {onclick: function(){
var newLine = document.getElementById('hashTable').copy.children[0].cloneNode(true);
newLine.nbData = Object.assign({},persons[0]);
document.getElementById('hashTable').appendChild(newLine);
$s.btnDel = {onclick: btnDel};
}}
Overall, I'm not sure than event handlers and other imperative things might be used this way with NanoBind. Maybe frameworks better for this.
For building nested structures from same HTML subtree like tree control or menu
Proxy
Now data passed only when you're rewrite some key in $s
. Any changes like $s.hashTable[0].age = 19
has no effect, because object instance are same as before.
Now every element has one or zero nbData, but any element matches on many selectors, potentially with many nbData
. So, nbData should be converted to associative array
'selector': data.