Controllers and callbacks

Callbacks

Flex-Patterns has only two types of callbacks:

Let’s see an example.

_patterns.get({ url : 'some_url_to_pattern', onReady : function (results) { var instance = this, //or instance = results.instance listener = results.listener, model = results.model, exchange = results.exchange; }, onFail : function () { }, }).render();

Also you can define callbacks not only for JavaScript call. If you mount pattern into layout, you can define names of callbacks with attributes.

<pattern onReady="myPatternOnReady" onFail="myPatternOnFail" data-pattern="/patterns/popup/pattern.html" data-hooks="id, title, content, login, password, type, controls"> <id>0</id> <title>Test dialog window</title> <content> <login> <type>text</type> </login> <password> <type>password</type> </password> <controls> <id>login_button</id><title>login</title> <id>cancel_button</id><title>cancel</title> </controls> </content> </pattern> <script type="text/javascript"> window['myPatternOnReady'] = function (results) { var instance = this, //or instance = results.instance listener = results.listener, model = results.model, exchange = results.exchange; }; window['myPatternOnFail'] = function () { //Do something }; </script> <pattern onReady="myCore.popups.onReady" onFail="myCore.popups.onFail" data-pattern="/patterns/popup/pattern.html" data-hooks="id, title, content, login, password, type, controls"> <id>0</id> <title>Test dialog window</title> <content> <login> <type>text</type> </login> <password> <type>password</type> </password> <controls> <id>login_button</id><title>login</title> <id>cancel_button</id><title>cancel</title> </controls> </content> </pattern> <script type="text/javascript"> window['myCore'] = { popups: { onReady: function (results) { var instance = this, //or instance = results.instance listener = results.listener, model = results.model, exchange = results.exchange; }, onFail : function () { } } }; </script>

Controller

You can attach controller via two ways:

var Controller = function (results) { this.instance = results.instance; this.listener = results.listener; this.model = results.model; this.exchange = results.exchange; }; Controller.prototype = { //Pay your attantion, here is same names, like callbacks have onReady : function (results) { }, onUpdate : function (results) { }, setInstance : function (results) { }, myMethod_0 : function () { }, myMethod_1 : function () { }, myMethod_N : function () { }, }; _patterns.get({ url : 'some_url_to_pattern', controller : Controller }).render(); var Controller = function (results) { this.instance = results.instance; this.listener = results.listener; this.model = results.model; this.exchange = results.exchange; }; Controller.prototype = { onReady : function (results) { }, onUpdate : function (results) { }, setInstance : function (results) { }, myMethod_0 : function () { }, myMethod_1 : function () { }, myMethod_N : function () { }, }; _controller(Controller); <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Flex.Template</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <link rel="stylesheet" type="text/css" href="pattern.css" /> <!-- =========== CONTROLLER =========== --> <script type="text/javascript" src="controler.js"></script> <!-- =========== CONTROLLER =========== --> </head> <body> <div data-type="Pattern.Login"> <p>Login</p> {{ login }} <p>Password</p> {{ password }} <div data-type="Pattern.Controls">{{ controls }}</div> </div> </body> </html>

But also you can do this:

_controller(function (results) { var instance = this, //or instance = results.instance listener = results.listener, model = results.model, exchange = results.exchange; });

In this case controller’s behavior will be same like callback onReady has.

To attach controller to your template you have to do just two actions:

Structure of controller

Controller is a “class”, which will be initialized after pattern will be ready. Flex-Pattern can detect controller only if prototype of constructor has at least one of next methods:

If function-constructor doesn’t have any from listed methods, flex-patterns will use such function as callback onReady.

Here is structure of controller:

var Controller = function (results) { this.instance = results.instance; this.listener = results.listener; this.model = results.model; this.exchange = results.exchange; }; Controller.prototype = { onReady : function (results) { }, onUpdate : function (results) { }, setInstance : function (results) { }, //Here you can add any your methods };

Pay your attention on next fragment of code:

this.instance = results.instance; this.listener = results.listener; this.model = results.model; this.exchange = results.exchange;

Flex-Pattern in any case will create these properties (instance, listener, model and exchange). So, strongly recommend do not use these names in your controller.

Name Description
onReady This method will be called only once, when pattern will be initialized and rendered.
onUpdate This method will be called each time of updating pattern.
setInstance This method will be called when pattern will be initialized and rendered and each time of updating pattern

Object results

Object results has only four properties:

Instance

Object instance has only one useful method: update. Using this method, you can update any hook of your pattern. Let’s see within example.

_patterns.get({ url : '/patterns/popup/pattern.html', node : document.body, hooks : { id : flex.unique(), title : 'Test dialog window', content : _patterns.get({ url : '/patterns/patterns/login/pattern.html', hooks : { login : _patterns.get({ url : '/patterns/controls/textinput/pattern.html', hooks : { type: 'text', } }), password: _patterns.get({ url : '/patterns/controls/textinput/pattern.html', hooks : { type: 'password', } }), controls: _patterns.get({ url : '/patterns/buttons/flat/pattern.html', hooks : [{ title: 'login', id: 'login_button' }, { title: 'cancel', id: 'cancel_button' }] }), } }) }, onReady: function (results) { var instance = this; instance.update({ title : 'Updated title', content : { controls: [ { title: 'UPD: Login' }, { title: 'UPD: Cancel' } ] } }); }, }).render(); var Controller = function (results) { this.instance = results.instance; this.listener = results.listener; this.model = results.model; this.exchange = results.exchange; }; Controller.prototype = { onReady : function (results) { this.instance.update({ title : 'Updated title', content : { controls: [ { title: 'UPD: Login' }, { title: 'UPD: Cancel' } ] } }); }, onUpdate : function (results) { }, setInstance : function (results) { }, }; _controller(Controller);

In this example, we change title of our popup and captions of buttons.

Pay your attention, using method update you skip definition of sub-patterns.

Each time after pattern will be updated, callback onUpdate will be called.

Listener

Listener is a good way to organize communication between nested patterns and different patterns on page. Object listener has next methods:

Name Scope Return Description
bind(event, handle, [id]) pattern ID [STRING] Attach handle to event in scope of current pattern. Parameter ID can be postponed.
bindGlobal(event, handle, [id]) global ID [STRING] Attach handle to event in global scope. Parameter ID can be postponed.
trigger(event, params) pattern BOOLEAN Handled event in scope of current pattern.
triggerGlobal(event, params) global BOOLEAN Handled event in global scope.

Let’s see on example. We have two controllers of two different patterns on page (never mind, what is it).

//Controller of Pattern "A" var ControllerA = function (results) { this.instance = results.instance; this.listener = results.listener; this.model = results.model; this.exchange = results.exchange; }; ControllerA.prototype = { onReady : function (results) { this.listener.bind('eventA', function (params) { console.log('Handled: event A'); }); this.listener.bindGlobal('eventG', function (params) { console.log('Handled: event G'); }); }, onUpdate : function (results) { }, setInstance : function (results) { }, }; _controller(ControllerA); //Controller of Pattern "B" var ControllerB = function (results) { this.instance = results.instance; this.listener = results.listener; this.model = results.model; this.exchange = results.exchange; }; ControllerB.prototype = { onReady : function (results) { this.listener.trigger('eventA', null); this.listener.triggerGlobal('eventG', null); }, onUpdate : function (results) { }, setInstance : function (results) { }, }; _controller(ControllerB); 'Handled: event G'; //Event A is in pattern "A" scope and can be handled only from pattern "A".

So all handles attached with method bind are isolated (in scope of current pattern) and you can use same names of events in different patterns. But method bindGlobal uses common global namespace, and here you should be care with potential conflicts.

Exchange

Object exchange can be used only in you initialize your pattern via JavaScript call. Let’s see on example:

_patterns.get({ url : '/patterns/popup/pattern.html', node : document.body, hooks : { id : id, title : 'Test dialog window', content : { login : { type: 'text' }, password: { type: 'password' }, controls: [{ title: 'login', id: 'login_button' }, { title: 'cancel', id: 'cancel_button' }], } }, exchange : { some_prop_0: 'some_value_0', some_prop_1: 'some_value_1', some_prop_2: 'some_value_2', }, }).render(); var Controller = function (results) { this.instance = results.instance; this.listener = results.listener; this.model = results.model; this.exchange = results.exchange; }; Controller.prototype = { onReady : function (results) { //We have access to properties: console.log(results.exchange.some_prop_0); console.log(results.exchange.some_prop_1); console.log(results.exchange.some_prop_2); }, onUpdate : function (results) { }, setInstance : function (results) { }, }; _controller(Controller);

So, you can use an object exchange as addition communication channel between nested patterns in both directions: parent – child and child – parent.

Model

About model read here please.