Controllers and callbacks
Callbacks
Flex-Patterns has only two types of callbacks:
- onReady. Will be called after template will be successfully initialized and rendered.
- onFail. Will be called in case, if initialization or rendering will be failed.
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:
- During JavaScript call;
- In template.
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:
- Create JS-file with controller “body” (like in example);
- Add reference (via tag SCRIPT) to JS-file in your template.
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:
- onReady
- onUpdate
- setInstance
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 – reference to just initialized instance of your pattern;
- listener – controller of internal events (in scope of current pattern or in global scope)
- model – reference to model of pattern
- exchange – special storage for exchanging of data between nested patterns in all directions (from child to parent and from parent to child).
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.