Flex - Patterns

Creating template

Storing

Template is a simple HTML page with all basic parts, like DOCUMENT, HEAD and BODY. You can define in template tags LINK to define some CSS and SCRIPT – to define some JS files or controller. All such resource will be attached with your template.

So, from organization point of view, you can create basic folder “templates” and storage there your templates with resources.

Basic definitions

To create template, you should know only several definitions:

The best way to explain something – show example. So, to see how it works, let’s create simple dialog for authorization. We will need several temples (simple HTML files):

Let’s postpone HEAD and other places of HTML and paste only BODY tag to save place and your time.

<div data-type="Pattern.Login"> <p>Login</p> {{ login }} <p>Password</p> {{ password }} <div data-type="Pattern.Controls">{{ controls }}</div> </div> <div data-style="Popup" id="{ {id }}"> <div data-style="Popup.Container"> <div data-style="Popup.Title"> <p data-style="Popup.Title">{{ title }}</p> </div> <div data-style="Popup.Content">{{ content }}</div> <div data-style="Popup.Bottom"> <p data-style="Popup.Bottom">{{ bottom }}</p> </div> </div> </div> <p>{{ ::value }}</p> <div data-type="TextInput.Wrapper"> <div data-type="TextInput.Container"> <input data-type="TextInput" type="{{ type }}" value="{{ ::value }}" name="TestInput"/> </div> </div> <a data-type="Buttons.Flat" id="{{ id }}">{{ title }}</a>

Attaching template

You can attach template by two ways:

Attaching via JavaScript

Here is an example. To attach template via JavaScript you should to do this:

var id = flex.unique(); _patterns.get({ url : '/patterns/popup/pattern.html', node : document.body, hooks : { id : id, 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, dom = results.dom, model = results.model; }); }, }).render();

Parameters of method get (_patterns.get(parameters))

Name Obligatory Type Description
url yes string URL to HTML file of your template
node no node || string If you define this property your template will be mounted into defined node. You can define this property as reference to some node or as selector. For example, you can define it as: document.body (reference to node) or as ‘body’ (selector).
replace no bool Works only with property [node]. If it’s in true, your template will be mounted instead defined node.
before no node || string If you define this property your template will be mounted before defined node. You can define this property as reference to some node or as selector.
after no node || string If you define this property your template will be mounted after defined node. You can define this property as reference to some node or as selector.
id no string ID of your template.
hooks no object || array Collections of hooks.
conditions no object Collections of conditions.
controller no object You can define controller during calling template. It can be useful if you want to overwrite controller.
onReady no function This function will be called if rendering of your template was successful.
resources no any Property resources is used for exchanging of data between your application and controllers.
remove_missing_hooks no bool If flex-patterns cannot file hook, mark of hook ({{ name }} will be removed from markup. You can prevent such behavior by setting this property to false.

Method get is initializing pattern, but not render it. This method will return caller instance and you can call method render to render pattern according parameters, which was given to method get: _patterns.get(params).render().

Pay your attention, flex-patterns works asynchrony, because it gets sources of your template (HTML, JS and CSS) within HTTP(s) requests. That’s why method render will not return any results of operation.

So, method get can be used to define nested patterns.

But we have to say, such call (as in previous example) doesn’t look very nice – there are too many definitions of pattern’s urls. So, you can easy solve such issue by mapping your template. Everything what you need – just create JS file, place it with root-template (it’s “/patterns/popup/pattern.html” in our example) and define content of new file, like next:

Do not forget attach map.js file to your root template.

_map({ content: { url: '/patterns/login/pattern.html', hooks: { login: { url: '/patterns/controls/textinput/pattern.html' }, password: { url: '/patterns/controls/textinput/pattern.html' }, controls: { url: '/patterns/buttons/flat/pattern.html' }, } } }); <!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" /> <script type="text/javascript" src="map.js"></script> </head> <body> <div data-style="Popup" id="{{id}}"> <div data-style="Popup.Container"> <div data-style="Popup.Title"> <p data-style="Popup.Title">{{title}}</p> </div> <div data-style="Popup.Content">{{content}}</div> <div data-style="Popup.Bottom"> <p data-style="Popup.Bottom">{{bottom}}</p> </div> </div> </div> </body> </html> _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' }], } }, onReady: function (results) { var instance = this; } }).render();

Now as you can see our caller of pattern looks much simpler.

Method _map (in scope of pattern) allows define paths to nested patterns.

Attaching via HTML

Here is an example. To attach template within HTML, you should define in your page next HTML fragment:

<pattern src="/patterns/popup/pattern.html" data-hooks="id, title, content, login, password, type, controls"> <id>0</id> <title>Test dialog window</title> <content src="/patterns/patterns/login/pattern.html"> <login src="/patterns/controls/textinput/pattern.html"> <type>text</type> </login> <password src="/patterns/controls/textinput/pattern.html"> <type>password</type> </password> <controls src="/patterns/buttons/flat/pattern.html"> <id>login_button</id><title>login</title> <id>cancel_button</id><title>cancel</title> </controls> </content> </pattern> <pattern src="/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>

In attribute data-hooks you have to define names of all hooks, which will be used in template. You can include into such list nested patterns too. But if you have several instances of your template, it isn’t very comfortable to define same things each time. So, you can use tag LINK to define basic parameters of pattern.

<link rel="pattern" name="login" src="/patterns/popup/pattern.html" data-hooks="id, title, content, login, password, type, controls" />

Now you can render your template a bit simpler. Pay your attention, now you use tag LOGIN (as defined in attribute NAME of LINK) instead tag PATTERN.

<login> <id>0</id> <title>Test dialog window</title> <content src="/patterns/patterns/login/pattern.html"> <login src="/patterns/controls/textinput/pattern.html"> <type>text</type> </login> <password src="/patterns/controls/textinput/pattern.html"> <type>password</type> </password> <controls src="/patterns/buttons/flat/pattern.html"> <id>login_button</id><title>login</title> <id>cancel_button</id><title>cancel</title> </controls> </content> </login> <login> <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> </login>

If you do not want create addition JS-file with map to go away from definition of urls of nested templates, you can do it within LINK tag also:

<link rel="hook" name="login.content" src="patterns/patterns/login/pattern.html"/> <link rel="hook" name="login.content.login" src="/patterns/controls/textinput/pattern.html"/> <link rel="hook" name="login.content.password" src="/patterns/controls/textinput/pattern.html"/> <link rel="hook" name="login.content.controls" src="/patterns/buttons/flat/pattern.html"/>

In this case you can mount your template without map, like here:

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

Attributes of tag PATTERN

Name Obligatory Type Description
src yes string URL to HTML file of your template
onReady no string Name of handle, which will be called after pattern is initialized.
id no string ID of your template.

Attributes of tag LINK

Name Obligatory Type Description
rel yes string Can be “pattern” or “hook”. If rel = “pattern” – link is definition of parameters of template; if rel = “hook” – link is definition of nested template (mapping).
name yes string Case rel = "pattern”: name of tag, which will be used for this pattern in layout. Case rel = “hook”: path (map) to nested pattern. For example, if parent template is “tabs” (which has nested template – “tab”), path to nested template will be name = “tabs.tab”
data-hooks no string Used only in cases rel = “pattern” (definition of root-template). It’s list of all used hooks inside template (include nested).

If your template will be in layout during page are loading, in this case you should not call any JavaScript code – flex-patterns automatically find template, build it and mount instead tag PATTERN.

But if you will add your template into layout after page was loaded, or if you will define attribute onReady, in this case your template will not be rendered automatically to prevent situation, when callback functions aren’t ready (defined), but flex-pattern is ready to render. So, to render template from HTML with defined callbacks, you should do this (after your callback-functions will be ready):

_patterns.layout();

Multiply values

To repeat some template within different data several times you should define value of hook as an array of values. Let’s see how it works on an example of table. We will need two templates.

<table data-type="Demo.Table"> <tr> <th>{{ titles.column_0 }}</th> <th>{{ titles.column_1 }}</th> <th>{{ titles.column_2 }}</th> <th>{{ titles.column_3 }}</th> </tr> {{ rows }} </table> <tr> <td>{{ column_0 }}</td> <td>{{ column_1 }}</td> <td>{{ column_2 }}</td> <td>{{ column_3 }}</td> </tr>

Let’s render our table. Here is an example of this template – link.

var data_source = []; for (var i = 0; i < 100; i += 1) { data_source.push({ column_0: (Math.random() * 1000).toFixed(4), column_1: (Math.random() * 1000).toFixed(4), column_2: (Math.random() * 1000).toFixed(4), column_3: (Math.random() * 1000).toFixed(4), }); } _patterns.get({ url: '/patterns/table/container/pattern.html', node: document.body, hooks: { titles: { column_0: 'Column #0', column_1: 'Column #1', column_2: 'Column #2', column_3: 'Column #3', }, rows: _patterns.get({ url: '/patterns/table/row/pattern.html', hooks: data_source, }) } }).render();

Pay your attention, that we can define name of hook as a chain of properties – titles.column_x. It allows us to use an understandable structure of a hook’s object and group properties by their meaning.

But also you have more simple way. You can create only one template of table (with row template included). In this case you have to mark repeated element with next mark: {{ [name_of_propery] }}. Let’s see with example.

var data_source = []; for (var i = 0; i < 100; i += 1) { data_source.push({ column_0: (Math.random() * 1000).toFixed(4), column_1: (Math.random() * 1000).toFixed(4), column_2: (Math.random() * 1000).toFixed(4), column_3: (Math.random() * 1000).toFixed(4), }); } _patterns.get({ url : '/patterns/table/single/pattern.html', node : document.body, hooks : { titles: { column_0: 'Column #0', column_1: 'Column #1', column_2: 'Column #2', column_3: 'Column #3', }, rows: data_source } }).render(); <table data-type="Demo.Table"> <tr> <th>{{ titles.column_0 }}</th> <th>{{ titles.column_1 }}</th> <th>{{ titles.column_2 }}</th> <th>{{ titles.column_3 }}</th> </tr> <tr {{ [rows] }}> <td>{{ column_0 }}</td> <td>{{ column_1 }}</td> <td>{{ column_2 }}</td> <td>{{ column_3 }}</td> </tr> </table>

Here is example of such way. Or you can take a look on a simple drop down list example.

Also, you have seen, that in previous example (authorization window) we used multiple values for buttons, but pay your attention, in case of JavaScript attaching to define multiply value of hook we used an array to define several instances of template:

controls: _patterns.get({ url : '/patterns/buttons/flat/pattern.html', hooks : [{ title: 'login', id: 'login_button' }, { title: 'cancel', id: 'cancel_button' }] })

But in HTML to do same we have to define hooks just several times:

<controls src="/patterns/buttons/flat/pattern.html"> <id>login_button</id><title>login</title> <id>cancel_button</id><title>cancel</title> </controls>

Here you can discover an example of table, mounted into layout.

External data sources

In addition, you can use as hooks values source some URL. Sure, by defined URL should be returned some JSON object. This JSON object will be used as hooks values. Let’s see next example.

_patterns.get({ url : '/patterns/table/container/pattern.html', node : document.body, hooks : { titles : { column_0: 'Column #0', column_1: 'Column #1', column_2: 'Column #2', column_3: 'Column #3', }, rows :_patterns.get({ url : '/patterns/table/row_con/pattern.html', hooks : _patterns.url('/examples/json/table.json'), }) }, }).render();

To define external source of data you should use method url of _patterns: _patterns.url(url, parameters). Let’s see on parameters closer.

Name Default Type Description
url STRING url, where data can be received
parameters OBJECT Parameters of data request
parameters.parser(data) null FUNCTION You can define your parser which will be applied to received data
parameters.method GET STRING Method of request: POST or GET
parameters.parameters null STRING || ARRAY Parameters of your request. In GET case from ARRAY will be converted to STRING automatically
parameters.callbacks.success(response, request) null FUNCTION Handled in success
parameters.callbacks.fail(response, request) null FUNCTION Handled in fail
parameters.callbacks.before(request) null FUNCTION Handled before do request
parameters.callbacks.reaction(response, request) null FUNCTION Handled on each reaction of request
parameters.callbacks.timeout(response, request) null FUNCTION Handled in timeout case
parameters.callbacks.headers(response, request) null FUNCTION Handled when HEADERS are gotten
parameters.settings OBJECT Addition configuration of request
parameters.settings.id some string STRING ID of current request
parameters.settings.timeout 20000 NUMBER Timeout in ms
parameters.settings.doNotChangeHeaders false BOOLEAN In true headers will not be validate and parsed
parameters.settings.doNotChangeParameters false BOOLEAN In true parameters of request (defined as object or array) will not be validate and parsed. For POST requests
parameters.settings.doNotEncodeParametersAsURL false BOOLEAN In true parameters of request (defined as string) will not be validate and parsed. For GET requests
parameters.settings.headers null STRING || ARRAY Collection of headers

As URL you can define some specific hook (like in previous example) or all hooks, like here.

_patterns.get({ url : '/components/table.simple/component.html', node : document.body, hooks : _patterns.url('/examples/json/table.all.json', { parser: function (res) { res.titles.column_0 = 'Column 0 (UPD)'; return res; } }), }).render();