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.autostart = false

Don’t call alight.bootstrap on start

alight.bootstrap(element)

Manual start applications, element - DOM element or array of elements. If element is undefined then Angular Light will start all al-app on the document. If alight.autostart = true, the method will be called after the DOM is ready

alight.applyBindings(scope, element, config)

Bind the scope to the DOM element

  • scope - Scope object
  • 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 scope = alight.Scope();
var element = document.body;
alight.applyBindings(scope, element);

alight.Scope()

Create a (root) Scope

alight.controllers

Dictionary of controllers

alight.filters

Dictionary of filters

alight.directives

Dictionary of directives

alight.nextTick(callback)

Execute the function on next tick

alight.getController(name, scope)

Take a controller by name. A controller can be located in alight.controllers, in global scope

comments powered by Disqus

Scope

Scope.$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”

Option:

  • option = true or option.isArray = true - watch an array
  • option.init = true - Execute callback
  • 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)

Scope.$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
Example of $compile
 var scope = alight.Scope()
 var fn = scope.$compile('"hello " + title')
 scope.title = 'linux'
 fn() // return "hello linux"
 scope.title = 'macos'
 fn() // return "hello macos"
Example with input
 var fn = scope.$compile('title + v', { input:['v'] })
 fn(' X') // return "macos X"
Example with no_return
var fn = scope.$compile('title = v', { input:['v'], no_return:true })
fn('linux') // scope.title = "linux"

Scope.$eval(expression)

Execute an expression

Scope.$watchText(tpl, callback)

Track the template

Scope.$compileText(tpl)

Compile the template. Method is depricated (since v0.9)

Example with $complieText
var scope = alight.Scope()
var fn = scope.$compileText('Hello {{title}}!')
scope.title = 'linux'
fn() // return "Hello linux!"

Scope.$evalText(tpl)

Evalute the template. Method is depricated (since v0.9)

Scope.$new(isolate)

Create a child Scope, if isolate == true, then child scope will not be inherited from parent scope, if isolate == ‘root’ then it will be separate root scope.

Scope.$destroy()

Destroy the Scope.

Scope.$scan(callback or option)

Start the search for changes

  • 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.top - Choose the root scope for current scanning (depricated).
  • option.late = (true/false) - If there is a few $scan commands, Angular Light will call only last one.
Example with $scan
var scope = alight.Scope()
scope.$watch('title', function(value) {
    console.log('title =', value)
}) // make observing
scope.title = 'new'
scope.$scan()
// print title = new
scope.title = 'linux'
scope.$scan()
// print title = linux
scope.$scan()
// do nothing

Scope.$scanAsync(callback)

It the same as Scope.$scan({late: true, callback: callback})

Scope.$getValue(name)

Take the value of the variable, also you can use Scope.$eval

Scope.$setValue(name, value)

Set the value of the variable

Example with $setValue
scope.var = 1;
scope.path.var = 2;
scope.path[scope.key] = 3;

// equal
scope.$setValue('var', 1);
scope.$setValue('path.var', 2);
scope.$setValue('path[key]', 3);
comments powered by Disqus

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

Example of directive al-text
 alight.directives.al.text = function(element, name, scope, env) {
     // a function to set a text to the DOM-element
     var setter = function(text) {
         $(element).text(value)
     }

     // Track to the variable
     scope.$watch(name, setter, {
         init: true  // Run the setter immediately
     });
 };

Input arguments:

  • element - element of DOM
  • name - value of attribute
  • scope - current Scope
  • 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.

Attributes of directive:

  • priority - you can set priority for a directive
  • template - custom template
  • templateUrl - link to template
  • scope (true/’isolate’/’root’) - to make a child scope, an isolated scope (with no inheritance), a separate root scope
  • restrict = ‘A’, can be ‘AEM’, ‘A’ matches attribute name, ‘E’ matches element name, ‘M’ matches class name
  • init - the method is called when the directive is made, before template, scope
  • link - the method is called after template, scope
  • anyAttr - you can make a custom attribute, look. directive preprocessor
Directives with attributes
 alight.directives.al.stop = {
     priority: -10,
     template: '<b></b>',
     scope: true,
     init: function(element, name, scope, env) {
         return {
             owner: true
         };
     },
     link: function(element, name, scope, env) {
     }
 };

If a directive returns the flag owner return { owner:true }, then the process of binding will miss 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.

comments powered by Disqus

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:

Inherit al-value
 alight.directives.al.valueDelay = function() {
     // create a parent directive
     var dir = alight.directives.al.value.apply(null, arguments);

     // 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

comments powered by Disqus

Directives

Events

Controls

Special directives

Bind-once

comments powered by Disqus

Base filters

data

  • To convert the date to string
  • Input argument: date
example
<div>{{when | date:yyyy-mm-dd }}</div>

filter

  • To filter the list
  • Input argument: variable

Example

slice

  • To slice the list
  • input arguments: numbers
example
<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
example
<div al-repeat="it in 10 | generator"></div>
<div al-repeat="it in size | generator"></div>

Example

toArray

  • converts an object to array (for al-repeat)
  • input arguments: key, value
example
<div al-repeat="item in object | toArray:key,value track by key">

Example

orderBy

  • sorts an array by key (for al-repeat)
  • input arguments: key, reverse
example
<div al-repeat="item in array | orderBy:key,reverse">

Example

throttle

  • makes delay for output, pattern debounce
  • input arguments: delay
example
<input al-value="link" type="text" />
<p>{{link | throttle:300 | loadFromServer}}</p>

Example

comments powered by Disqus

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.

Example filter
alight.filters.mylimit = function(exp, scope) {
    var ce = scope.$compile(exp);       // compile the input expression
    return function(value) {            // return handler
        var limit = Number(ce() || 5);
        return value.slice(0, limit)
    }
}

Example on jsfiddle

Input arguments

  • expression - an input expression
  • scope - current Scope

The filter should return a handler/function, one instance of filter.

alight.getFilter(name, scope, param)

This function look for a necessary filter, you can change it, for example you can make own location for your filters.

comments powered by Disqus

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.

Example of async filter
alight.filters.trottle = function(delay, scope, env) {
    delay = Number(delay);
    var to;
    return {
        onChange: function(value) {
            if(to) clearTimeout(to);
            to = setTimeout(function() {
                to = null;
                env.setValue(value);
                scope.$scan();
            }, delay);
        }
    }
}

Input arguments

  • expression - an input expression
  • scope - current Scope
  • env - extra functional
  • env.setValue(value) - set value of filter
Example of async filter
alight.filters.asyncFilter = function(expression, scope, 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

Examples

comments powered by Disqus

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.utilits.pars_start_tag = '{#';
alight.utilits.pars_finish_tag = '#}';

For complex text bindings you can use text directives

comments powered by Disqus

Text directives

Overview

An able to control a declarative data binding in the HTML

example how to use text directives
<div al-app>
    counter {{#counter}}
</div>
text directive counter
 alight.text.counter = function(callback, expression, scope) {
     var n = 0;
     setInterval(function(){
         n++;
         callback(n)  // set result
         scope.$scan()  // $digest
     }, 1000);
 }

Input arguments

  • callback - a function to set a value
  • expression - expression of directive
  • scope
  • env. finally - a function to set the final value, after that $watch will be removed.
  • env.**setter** = callback

Examples

comments powered by Disqus

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.

example
<div class="red {{::class}}"> {{::text}} </div>
<div al-show="::visible"></div>
<li al-repeat="it in ::list">...</li>
and so on

Examples

comments powered by Disqus

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.

comments powered by Disqus

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.

Example

comments powered by Disqus

A few ways to bind a model to the DOM

1. Manual binding, applyBindings

html
<div id="app">
    <input al-value="title" type="text" class="form-control" />
    <p>{{title}}</p>
</div>

Make scope, then to bind it to the DOM with alight.applyBindings

code
var tag = document.querySelector('#app');  // take the tag

var scope = alight.Scope();  // make a Scope
scope.title = 'Hello!';  // set init value

alight.applyBindings(scope, tag);  // apply bindings

Example on jsfiddle

2. Auto binding, al-app

alight.bootstrap is called on start system, it takes each element with al-app and execute alight.applyBindings

html
<div al-app al-init="title='Hello!'">
    <input al-value="title" type="text" class="form-control" />
    <p>{{title}}</p>
</div>

Example on jsfiddle

3. Manual binding with alight.bootstrap

You can bind custom elements with alight.bootstrap

html
<div id="app" al-init="title='Hello!'">
    <input al-value="title" type="text" class="form-control" />
    <p>{{title}}</p>
</div>
javascript
var tag = document.querySelector('#app');  // take the tag

alight.bootstrap([tag]);  // bind to DOM

Example on jsfiddle

4. Deferred binding, alight.bootstrap

html
<div al-app al-init="title='Hello!'">
    <input al-value="title" type="text" class="form-control" />
    <p>{{title}}</p>
</div>
javascript
alight.autostart = false;
setTimeout(alight.bootstrap, 2000);

Example on jsfiddle

5. To bind to element with no DOM

html
<div id="app"></div>
javascript
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>';
var scope = alight.Scope();  // make a scope
scope.title = 'Hello!';  // set init value

alight.applyBindings(scope, tag);  // apply bindings

document.querySelector('#app').appendChild(tag);  // append to DOM

Example on jsfiddle

6. Manual binding #2

html
<div id="app">
    <input al-value="data.name" type="text" />
    {{data.name}} <br/>
    <button al-click="click()">Set Hello</button>
</div>
javascript
alight.bootstrap({
    $el: '#app',
    data: {
        name: 'Some text'
    },
    click: function() {
        this.data.name = 'Hello'
    }
});

Example on jsfiddle

comments powered by Disqus

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
Example how to create attribute ‘bold’
alight.directivePreprocessor.ext.splice(1, 0, {
    code: 'bold',  // not necessary
    fn: function() {
        if(this.directive.bold) this.element.innerHTML = '<b>' + this.element.innerHTML + '</b>'
    }
})
How ot use it
alight.directives.al.example = {
    bold: true
}
comments powered by Disqus

FAQ

How can I take a scope?

comments powered by Disqus
  • How to call Alert from al-click

  • How to simplify $parent.$parent.$parent...

  • An one scope for a few applications

  • 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? Something like al-click=”someFunc($this)”

    No, but you can extend the directive, or make a thin directive for this, example

  • 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"

  • Where is “$odd, $even, $first, $last, $rest” for al-repeat?

    You can append any attributes, example hot to append $odd $even

  • How to sort an array?

    Manual sort Filter orderBy Sort props of an object Call a method

  • Where is al-select directive?

    Here a few examples with select control.

  • 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?

    Example

comments powered by Disqus

Examples

comments powered by Disqus