Angular Light¶
Contents:
API¶
alight.debug¶
Turn on a logging debug information
- alight.debug.scan - logging scan operations
- alight.debug.directive - logging binding directives
- alight.debug.parser - logging parsing expressions
- alight.debug.watch - logging function $watch
- alight.debug.watchText - logging function $watchText
alight.bind(ChangeDetector, element, option)¶
Bind a change detector to the DOM element, alias alight.applyBindings
- ChangeDetector - an instance of ChangeDetector
- element - DOM element
- config.skip_top = false - Skip binding the top DOM element
- config.skip_attr = [‘al-repeat’, ‘al-app’] - Skip attributes for a binding, for the top element
var cd = alight.ChangeDetector();
var element = document.body;
alight.bind(cd, element);
alight.ctrl¶
Dictionary of controllers, alias for alight.directives.ctrl
alight.filters¶
Dictionary of filters
alight.directives¶
Dictionary of directives, short alias alight.d
alight.text¶
Collection of text directives
alight.hook¶
Different hooks
alight.bootstrap¶
It lets you a few ways to bind DOM.
Binding to all elements with attribute [al-app]¶
- alight.bootstrap()
Binding by selector¶
- alight.bootstrap(‘#someId’)
- alight.bootstrap(‘#someId’, scope)
Binding to element¶
- alight.bootstrap(element)
- alight.bootstrap(element, scope)
Binding to array of elements¶
- alight.bootstrap([element1, element2, element3])
- alight.bootstrap([element1, element2, element3], scope)
Note: If you provide scope, then all elements will be binded to this scope, otherwise every dom will have own scope.
Example¶
alight.bootstrap('#app', {
name: 'world',
click: function() {
this.name = 'user'
}
});
Change Detector¶
It lets you observe changes in your scope
ChangeDetector.watch(name, callback, option)¶
Set the tracking variable. Also you can track system events, it returns object with method stop()
Name:
- <expression> - Expression/model
- <a function> - Track the result of the function, the function are called every iteration of $scan.
- “$destroy” - Track a destroying scope
- “$any” - Track a modifying any object
- “$finishScan” - a callback is executed as soon as $scan finish work
- “$finishBinding” - the callback is called when a binding process finishes, sample
- “$finishScanOnce”
- “$onScanOnce” - the callback is called in scan loop
Option:
- option = true or option.isArray = true - watch an array
- option.readOnly = true - You can use it if the callback doesn’t modify the scope. (an optimization option).
- option.deep = true - a deep comparison for the object.
- option.isArray
- option.OneTime
- option.onStop
Optimization tip: If callback returns ‘$scanNoChanges’ then $scan will not run extra-loop (like readonly watch)
ChangeDetector.compile(expression, option)¶
Compile an expression
option:
- option.input - list of input arguments
- option.no_return - a function will not return any result (compile a statment)
- option.string - result of method will convert to string
var scope = {};
var cd = alight.ChangeDetector(scope)
var fn = cd.compile('"hello " + title')
scope.title = 'linux'
fn(scope) // return "hello linux"
scope.title = 'macos'
fn(scope) // return "hello macos"
var fn = cd.compile('title + v', { input:['v'] })
fn(scope, ' X') // return "macos X"
var fn = cd.compile('title = v', { input:['v'], no_return:true })
fn(scope, 'linux') // scope.title = "linux"
ChangeDetector.eval(expression)¶
Execute an expression
ChangeDetector.watchText(tpl, callback)¶
Track the template
ChangeDetector.new([scope])¶
Create a child ChangeDetector, if scope is omitted, then it will used parent scope
ChangeDetector.destroy()¶
Destroy the Scope.
ChangeDetector.scan(callback or option)¶
Starts the search for changes, returns a watch statistic
- callback - Method will be called when $scan finishes a work, even if $scan has already started from other a place.
- option.callback - see above
- option.skipWatch - skip specific watch
- option.late = (true/false) - If there is a few $scan commands, Angular Light will call only last one.
var scope = {};
var cd = alight.ChangeDetector(scope);
cd.watch('title', function(value) {
console.log('title =', value)
}); // make observing
scope.title = 'new'
cd.scan()
// print title = new
scope.title = 'linux'
cd.scan()
// print title = linux
cd.scan()
// do nothing
ChangeDetector.getValue(name)¶
Take the value of the variable, also you can use ChangeDetector.eval
ChangeDetector.setValue(name, value)¶
Set the value of the variable
var scope = {}
scope.var = 1;
scope.path.var = 2;
scope.path[scope.key] = 3;
// equal
var scope = {}
var cd = alight.ChangeDetector(scope);
cd.setValue('var', 1);
cd.setValue('path.var', 2);
cd.setValue('path[key]', 3);
Create Directives¶
Directives should be placed in alight.directives.prefix, you can choose any prefix, for example al-text ( alight.directives.al.text ), bo-text ( alight.directives.bo.text ), also you can place your directives in scope.$ns.directives they will be private.
A hyphen should be changed to underscores, example: <input al-my-some-directive />
it will be in alight.directives.al. mySomeDirective
The prefixes are needed in order to be able to catch the lack of used directives. For example, if you use the directive “al-texta”, but it does not exists (a mistake in the name or js-file isn’t loaded), then aLight will throw an exception.
An example of directive al-text, the directive is called when the binding process comes to an DOM-element
alight.directives.al.text = function(scope, cd, element, name, env) {
// Track to the variable
cd.watch(name, function(text) {
// set a text to the DOM-element
$(element).text(value)
});
};
Input arguments:
- scope - current Scope
- cd - change detector
- element - element of DOM
- name - value of attribute
- env - access to different options
- env. attrName - name of attribute (directive)
- env. attributes - list of attributes
- env. takeAttr(name, skip=true) - take a value of the attribute, if skip=true then the attribute will skip a binding process, sample
- env. skippedAttr() - list of not active attributes
- env. stopBinding = false - stop binding for child elements
Attributes of directive:¶
- priority - you can set priority for a directive
- template - custom template
- templateUrl - link to template
- scope (false/true) - if it is true, there will be a new, empty scope
- ChangeDetector (false/true/’root’) - create a new change detector
- restrict = ‘A’, can be ‘AEM’, ‘A’ matches attribute name, ‘E’ matches element name, ‘M’ matches class name
- link - the method is called after template, scope
- init - the method is called when the directive is made, before template, scope. You usually need link instead of it.
- stopBinding (true) - stop binding for child elements
- anyAttr - you can make a custom attribute, look. directive preprocessor
alight.directives.al.stop = {
priority: -10,
template: '<b></b>',
stopBinding: true,
link: function(scope, cd, element, name, env) {
}
};
If “stopBinding” is true, then the process of binding will skip child DOM-elements, it is necessary for the directives which are themselves controlled subsidiary of DOM, such as al-repeat, al-controller, al-include, al-stop, etc.
Inheritance of directives¶
If you want make inheritance of a directive, you need call a parent directive after that you can replace methods of the directive. For example, al-value has a few methods:
- onDom - binding to DOM
- updateModel - updateing the model
- watchModel - $watch model
- updateDom - updateting DOM
- initDom - set first value to DOM, updateDom(init_value)
- start - It’s called when the directive is ready
Make a directive al-value with deferred updating of model:
alight.directives.al.valueDelay = function(scope, cd, element, value, env) {
// create a source directive
var dir = alight.directives.al.value(scope, cd, element, value, env);
// save the old method for update the model
var oldUpdate = dir.updateModel;
var timer = null;
// change the method
dir.updateModel = function() {
if(timer) clearTimeout(timer);
timer = setTimeout(function() {
timer = null;
// call the default method for update the model
oldUpdate();
}, 500);
}
return dir;
}
Examples of inheritance¶
Examples below for v0.10, but in v0.11 it works similar * al-value -> al-value-delay * al-show -> al-show-slow * al-repeat, add “$even”, “$odd” into the directive * al-repeat, change input expression my-repeat=”list.foreach item” * al-repeat, change rendering
Directives¶
Events¶
Controls¶
- al-checked, todo sample
- al-radio sample1 sample2
- al-value, todo sample
- al-disable
- al-enable
- al-focused, two-way bind for focus events. Sample
- al-readonly
Special directives¶
- al-app, init application with current element, examples
- al-cloak, hide current element until activate the application, examples
- al-class/al-css, todo sample, animated sample
- al-style examples
- al-show, sample with animation
- al-hide, sample with animation
- al-html
- al-if, sample with animation
- al-ifnot, sample with animation
- al-include, loads a html block from the server, sample with animation
- al-init
- al-repeat
- al-src
- al-stop, stops a bind process for the element and his children.
- al-text, example
- al-select + al-option, example
Bind-once¶
- bo-if
- bo-ifnot
- bo-repeat
- bo-src
- bo-switch
- bo-switchDefault
- bo-switchWhen
Base filters¶
slice¶
- To slice the list
- input arguments: numbers
<div al-repeat="it in list | slice:a"></div>
<div al-repeat="it in list | slice:a,b"></div>
generator¶
- The filter makes an array (for al-repeat)
- input arguments: numbers
<div al-repeat="it in 10 | generator"></div>
<div al-repeat="it in size | generator"></div>
toArray¶
- converts an object to array (for al-repeat)
- input arguments: key, value
<div al-repeat="item in object | toArray:key,value track by key">
orderBy¶
- sorts an array by key (for al-repeat)
- input arguments: key, reverse
<div al-repeat="item in array | orderBy:key,reverse">
throttle¶
- makes delay for output, pattern debounce
- input arguments: delay
<input al-value="link" type="text" />
<p>{{link | throttle:300 | loadFromServer}}</p>
Create filters¶
Overview¶
A filter should be placed in alight.filters (you can change path with alight.getFilter), or in scope.$ns for private filters.
alight.filters.mylimit = function(exp, cd) {
var ce = cd.compile(exp); // compile the input expression
return function(value) { // return handler
var limit = Number(ce() || 5);
return value.slice(0, limit)
}
}
Input arguments¶
- expression - an input expression
- cd - change detector
The filter should return a handler/function, one instance of filter.
Async filters¶
Overview¶
Async filters let you transform data in async mode, a filter should be placed in alight.filters or in scope.$ns for private filters.
alight.filters.trottle = function(delay, cd, env) {
delay = Number(delay);
var to;
return {
onChange: function(value) {
if(to) clearTimeout(to);
to = setTimeout(function() {
to = null;
env.setValue(value);
cd.scan();
}, delay);
}
}
}
Input arguments¶
- expression - an input expression
- cd - change detector
- env - extra functional
- env.setValue(value) - set value of filter
alight.filters.asyncFilter = function(expression, cd, env) {
return {
watchMode: 'deep',
onChange: function(value) {},
onStop: function() {}
}
}
- watchMode, you can set ‘simple’/’array’/’deep’, if you need to change a watch mode for the input
- onChange - it’s executed on every change of input
- onStop - it’s executed when a watch object was removed
Text bindings¶
It’s a way to draw information to DOM:
<div>Hello {{name}}!</div>
<a href="htp://example.com/{{link}}>link</a>
Also you can use method “bind once” for optimization, for that you should append “=” to begin of expression.
<div>Hello {{=name}}!</div>
<a href="htp://example.com/{{=link}}>link</a>
Also you can use one time binding
If you can’t use tags {{ }}
, you can change this to {# #}
, {< >}
, ## ##
or something like this, length of tags should be equal 2 symbols:
alight.utils.pars_start_tag = '{#';
alight.utils.pars_finish_tag = '#}';
For complex text bindings you can use text directives
Text directives¶
Overview¶
An able to control a declarative data binding in the HTML
<div al-app>
counter {{#counter}}
</div>
alight.text.counter = function(callback, expression, cd) {
var n = 0;
setInterval(function(){
n++;
callback(n) // set result
cd.scan() // $digest
}, 1000);
}
Input arguments¶
- callback - a function to set a value
- expression - expression of directive
- cd - change detector
- env. finally - a function to set the final value, after that $watch will be removed.
- env.**setter** = callback
One-time binding¶
Overview¶
Waits when an expression has a value (a non-undefined value), then stops watching. You need append ”::” in front of expression for using One-Time binding. It works with $watch, $watchText, directives and declarative bindings.
<div class="red {{::class}}"> {{::text}} </div>
<div al-show="::visible"></div>
<li al-repeat="it in ::list">...</li>
and so on
Isolated Angular Light¶
Angular Light can be invisible/inaccessible for alien code, you should make a function alightInitCallback(alightBuilder), it has to be callable for Angular Light. Angular Light starts the function and gives “alightBuilder()” as an argument on load.
It’s useful feature, when your webapp will be used on alien page. It lets use different versions of Angular Light on the same page.
Namespaces¶
Every scope and child scopes of it can have own sets of directives, controllers and filters. You should make an object $ns in scope. This can resolve conflict of names. This lets create private directives, filters and controllers.
If you want to inherit global directives, you may set scope.$ns.inheritGlobal = true.
A few ways to bind a model to the DOM¶
1. Manual binding¶
<div id="app">
<input al-value="title" type="text" class="form-control" />
<p>{{title}}</p>
</div>
Make ChangeDetector, then to bind it to the DOM with alight.applyBindings
var tag = document.querySelector('#app'); // take the tag
var scope = {
title: 'Hello!'
};
var cd = alight.ChangeDetector(scope);
alight.bind(cd, tag); // apply bindings
2. Auto binding, al-app¶
alight.bootstrap is called on start system, it takes each element with al-app and execute alight.applyBindings
<div al-app al-init="title='Hello!'">
<input al-value="title" type="text" class="form-control" />
<p>{{title}}</p>
</div>
3. Manual binding with alight.bootstrap¶
You can bind custom elements with alight.bootstrap
<div id="app" al-init="title='Hello!'">
<input al-value="title" type="text" class="form-control" />
<p>{{title}}</p>
</div>
alight.bootstrap('#app'); // bind to DOM
4. To bind to element with no DOM¶
<div id="app"></div>
var tag = document.createElement('div'); // make an element
// set up template
tag.innerHTML = '<input al-value="title" type="text" class="form-control" /><p>{{title}}</p>';
alight.bootstrap(tag, {
title: 'Hello!'
})
document.querySelector('#app').appendChild(tag); // append to DOM
5. Manual binding #2¶
<div id="app">
<input al-value="name" type="text" />
{{name}} <br/>
<button al-click="click()">Set Hello</button>
</div>
alight.bootstrap('#app', {
name: 'Some text'
click: function() {
this.name = 'Hello'
}
});
Directive preprocessor¶
Directive preprocessor lets you control process of creating directives. You can make custom attributes and make different transformations.
Objects:
- alight.directivePreprocessor - a default preprocessor, you can change it
- alight.directivePreprocessor.ext - a list of handlers, you can append/remove them
alight.directivePreprocessor.ext.splice(1, 0, {
code: 'bold', // not necessary
fn: function() {
if(this.directive.bold) this.element.innerHTML = '<b>' + this.element.innerHTML + '</b>'
}
})
alight.directives.al.example = {
bold: true
}
Migration from 0.10 to 0.11¶
Controllers¶
<div al-controller="main"></div>
alight.controllers.main = function(scope) {};
<div ctrl-main></div>
alight.ctrl.main = function(scope, cd) {};
alight.ctrl.main = {
scope: true,
link: function(scope, cd) {
scope.$parent // parent scope
}
};
Directives¶
alight.directives.al.test = function(element, value, scope, env) {};
alight.directives.al.test = {
scope: true, // true / 'isolate' / 'root'
link: function(element, value, scope, env) {}
}
alight.directives.al.test = function(scope, cd, element, value, env) {};
alight.directives.al.test = {
scope: true, // it make a new clean scope (object)
ChangeDetector: true // true / 'root'
link: function(scope, cd, element, value, env) {}
}
Scope¶
Scope - it was a mix of change detector and user’s data, in v0.11 Scope was devided to ChangeDetector and scope={} (user’s data), it gives different advatages.
scope = alight.Scope()
scope.name = 'linux'
scope.$watch('name', function(value) {
}, {
init: true // it calls the callback immediately
})
scope.$scan()
scope.$destroy()
scope = {
name: 'linux'
}
cd = alight.ChangeDetector scope
// now cd.scope === scope
cd.watch('name', function(value) {});
// you don't need set 'init' anymore, the callback is executed on finish binding process, also you can call cd.scan() for this.
cd.scan()
cd.destroy()
FAQ¶
How can I take a scope?¶
for Angular Light v0.10 and older
- Where can I take a debug version
Here you can get release and debug of any version, also you can use bower:
bower install alight
- Where is $http service
Angular Light doesn’t have it, you can use jQuery.ajax or anyone that you usually use. But there is
alight.f$.ajax
for inner purpose.
- Angular Light updates a whole DOM or it tracks changes and update only changed elements?
Only changed elements.
- I need Angular Light runs my function when a bindings process will finish.
You can observe it
scope.$scan("$finishBinding", callback)
- Is it possible to pass jquery $element to function from al-click?
You can use $event that contains element, al-click=”someFunc($event)”
- How can I use al-repeat not as attribute, but as a comment?
al-repeat supports comment binding, example
- Why al-show with an empty array doesn’t hide my element:
al-show="model.array"
? Because there is javascript and !!model.array always give you true, you can use
al-show="model.array.length"
- Why al-show with an empty array doesn’t hide my element:
- Where is “$odd, $even, $first, $last, $rest” for al-repeat?
You can append any attributes, example how to append $odd $even
- How to sort an array?
Manual sort Filter orderBy Sort props of an object Call a method
- Can I rename directives?
Yes,
alight.directives.al.myKeypress = alight.directives.al.keypress
- How to call my function when Scope.$scan finish digets process?
You can pass your function as callback
Scope.$scan(callback)
- How to redraw bind-once?
\ Sort by:\ best rated\ newest\ oldest\
\\
Add a comment\ (markup):
\``code``
, \ code blocks:::
and an indented block after blank line