Skip to content
Newer
Older
100644 922 lines (820 sloc) 32.7 KB
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
1 ==============
2 Binding Events
3 ==============
4
5 **Time Estimate:** 20 minutes
6
7 **Difficulty Level:** Advanced
8
9 Summary
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax f…
zhouyaoji authored
10 =======
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
11
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view …
zhouyaoji authored
12 This example shows how to bind events to a mojit, configure code to run on the client, and make AJAX
13 calls to the YQL Web service. The application listens for events and then makes AJAX calls to
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
14 YQL to get Flickr photo information.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
15
16 The following topics will be covered:
17
18 - configuring the application to run on the client
19 - getting Flickr data from the model with YQL
20 - binding events through the ``mojitProxy`` object
21 - making AJAX calls to YQL from the binder
22
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
23 Prerequisite
24 ------------
25
26 You will need to `get a Flickr API key <http://www.flickr.com/services/api/keys/apply/>`_
27 to run this example.
28
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
29 Implementation Notes
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax f…
zhouyaoji authored
30 ====================
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
31
32 Configuring the Application to Run on the Client
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax f…
zhouyaoji authored
33 ------------------------------------------------
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
34
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view …
zhouyaoji authored
35 Mojito lets you configure applications to run on either the server or client side. This example uses
36 binders that are deployed to the client, so we need to configure Mojito to deploy the application
37 to the client, where it will be executed by the browser.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
38
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view …
zhouyaoji authored
39 To configure Mojito to run on the client, you simply set the ``"deploy"`` property to ``true`` in
40 ``application.json`` as seen below.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
41
42 .. code-block:: javascript
43
44 [
45 {
46 "settings": [ "master" ],
47 "specs": {
48 "frame": {
49 "type": "HTMLFrameMojit",
50 "config": {
51 "deploy": true,
52 "child": {
53 "type": "PagerMojit"
54 }
55 }
56 }
57 }
58 }
59 ]
60
61 Getting Data with YQL in the Model
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax f…
zhouyaoji authored
62 ----------------------------------
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
63
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view …
zhouyaoji authored
64 In the mojit model, the `YUI YQL Query Utility <http://developer.yahoo.com/yui/3/yql/>`_ is used to
65 get Flickr photo information. To access the utility in your model, specify ``'yql'`` in the
66 ``requires`` array as seen in the code snippet below:
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
67
68 .. code-block:: javascript
69
74b3d8a @zhouyaoji Fixed syntax for namespacing controllers/models in docs/examples.
zhouyaoji authored
70 YUI.add('PagerMojitModel', function(Y, NAME) {
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
71 ...
72 /* Code for PagerMojitModel */
73 ...
74 }, '0.0.1', {requires: ['yql']});
75
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view …
zhouyaoji authored
76 This code example uses the ``flickr.photos.search`` table to get information for photos that have a
77 title, description, or tags containing a string. For example, the YQL statement below returns Flickr
78 photo information for those photos that have a title, description, or tags containing the string
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
79 "Manhattan".
80
81 Using you Flickr API key, run the query in the `YQL Console <http://developer.yahoo.com/yql/console/>`_
82 and click **TEST** to see the returned XML response.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
83
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
84 ``select * from flickr.photos.search where text="Manhattan" and api_key="{your_flickr_api_key}"
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
85
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view …
zhouyaoji authored
86 The returned response contains photo information in the ``photo`` element. You extract the ``farm``,
87 ``server``, ``id``, and ``secret`` attributes from each photo element to create the photo URI as
88 seen here:
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
89
90 ``http://farm + {farm} + static.flickr.com/ + {server} + / + {id} + _ + {secret} + .jpg``
91
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view …
zhouyaoji authored
92 In the ``model.js`` of ``PagerMojit`` shown below, the ``YQL`` function uses the YQL statement above
93 to get photo data, then parses the returned response to create the photo URIs. The model then wraps
94 the photo information in an object and stores those objects in the ``images`` array that is sent to
95 the controller through the ``callback`` function.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
96
97 .. code-block:: javascript
98
74b3d8a @zhouyaoji Fixed syntax for namespacing controllers/models in docs/examples.
zhouyaoji authored
99 YUI.add('PagerMojitModel', function(Y, NAME) {
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
100 /**
101 * The PagerMojitModel module.
102 * @module PagerMojitModel
103 */
104 /**
105 * Constructor for the Model class.
106 * @class Model
107 * @constructor
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view …
zhouyaoji authored
108 **/
74b3d8a @zhouyaoji Fixed syntax for namespacing controllers/models in docs/examples.
zhouyaoji authored
109 Y.namespace('mojito.models')[NAME] = {
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
110 init: function(config) {
111 this.config = config;
112 },
113 getData: function(query, start, count, callback) {
114 var q = null;
115 // Get Flickr API key: http://www.flickr.com/services/api/keys/apply/
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
116 var API_KEY = "{your_flickr_api_key}";
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
117 start = parseInt(start) || 0;
118 count = parseInt(count) || 10;
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
119 q = 'select * from flickr.photos.search(' + start + ',' + count + ') where text="%' + query + '%" and api_key="' + API_KEY + '"';
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
120 Y.YQL(q, function(rawData) {
121 if (!rawData.query.results) {
122 callback([]);
123 return;
124 }
125 var rawImages = rawData.query.results.photo, rawImage = null,images = [], image = null, i = 0;
126 for (; i<rawImages.length; i++) {
127 rawImage = rawImages[i];
128 image = {
129 title: rawImage.title,
130 location: 'http://farm' + rawImage.farm + '.static.flickr.com/' + rawImage.server + '/' + rawImage.id + '_' + rawImage.secret + '.jpg',
131 farm: rawImage.farm,
132 server: rawImage.server,
133 image_id: rawImage.id,
134 secret: rawImage.secret
135 };
136 if (!image.title) {
137 image.title = "Generic Title: " + query;
138 }
139 images.push(image);
140 }
141 callback(images);
142 });
143 }
144 };
145 }, '0.0.1', {requires: [ 'yql']});
146
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view …
zhouyaoji authored
147
148 For a more detailed explanation about how to use YQL in your Mojito application, see `Calling YQL
149 from a Mojit <calling_yql.html>`_. For more information about YQL, see the
150 `YQL Guide <http://developer.yahoo.com/yql/guide>`_.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
151
152 Binding Events
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax f…
zhouyaoji authored
153 --------------
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
154
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
155 This section will discuss the basics of binding events in Mojito and then look at the
156 binder used in this code example.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
157
158 Binder Basics
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax f…
zhouyaoji authored
159 #############
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
160
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
161 A mojit may have zero, one, or many binders within the ``binders`` directory. Each binder
162 will be deployed to the browser along with the rest of the mojit code, where the client-side
163 Mojito runtime will call it appropriately. On the client, the binder has a proxy
164 object (``mojitProxy``) for interacting with the mojit it represents as well as with other
165 mojits on the page. Methods can be called from the ``mojitProxy`` object that allow
166 binders to listen for and fire events.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
167
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
168 The binder consists of a constructor, an initializer, and a bind function. The following
169 describes each component and indicates when the ``mojitProxy`` object can be used.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
170
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
171 - **constructor** - creates the namespace for your binder that wraps the initialization
172 code and binder.
173 - **initializer** - is passed the ``mojitProxy`` where it can be stored and used to listen
174 and fire events with other binders. The ``mojitProxy`` is the only gateway back into the
175 Mojito framework for your binder.
176 - **bind** - is a function that is passed a ``Y.Node`` instance that wraps the DOM node
177 representing this mojit instance. The DOM event handlers for capturing user interactions
178 should be attached in this function.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
179
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
180 The skeleton of the ``binders/index.js`` file below illustrates the basic structure of the
181 binder. For more information, see `Mojito Binders <../intro/mojito_binders.html>`_.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
182
183 .. code-block:: javascript
184
185 YUI.add('AwesomeMojitBinder', function(Y, NAME) {
186 // Binder constructor
187 Y.namespace('mojito.binders')[NAME] = {
188 init: function(mojitProxy) {
189 this.mojitProxy = mojitProxy;
190 },
191 // The bind function
192 bind: function(node) {
193 var thatNode = node;
194 }
195 };
196 Y.mojito.registerEventBinder('AwesomeMojit', Binder);
197 }, '0.0.1', {requires: ['mojito']});
198
199 Examining the PageMojitBinder
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax f…
zhouyaoji authored
200 #############################
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
201
202 This code example uses the binder ``PageMojitBinder`` to perform the following:
203
204 - attach ``onClick`` handlers to ``prev`` and ``next`` links
205 - invoke the ``index`` method of the controller through the ``mojitProxy`` object
206 - create an overlay with Flickr photo information received from YQL
207
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
208 The ``binders/index.js`` for this code example is long and fairly involved, so we will
209 dissect and analyze the code. Let's begin by looking at the ``bind`` function of
210 ``index.js``, which allows mojits to attach DOM event handlers.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
211
de93f81 @zhouyaoji Fixed formatting of code examples; removed any last remnants of view …
zhouyaoji authored
212 In this code snippet of ``binders/index.js``, the ``bind`` function contains the nested
213 ``updateDOM`` function that updates node content and attaches event handlers. Using the
214 ``mojitProxy`` object, the nested ``flipper`` function calls the ``index`` function of the
215 controller. The callback ``updateDOM`` is passed to ``index`` to update the content.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
216
217 .. code-block:: javascript
218
219 ...
220 bind: function(node) {
221 var thatNode = node;
222 // Define the action when user click on prev/next.
223 var flipper = function(event) {
224 var target = event.target;
225 // Get the link to the page.
226 var page = parsePage(target.get('href'));
227 var updateDOM = function(markup) {
228 thatNode.set('innerHTML', markup);
229 thatNode.all('#nav a').on('click', flipper, this);
230 thatNode.all('#master ul li a').on('mouseover', showOverlay, this);
231 thatNode.all('#master ul li a').on('mouseout', showOverlay, this);
232 };
233 this.mojitProxy.invoke('index',
234 {
235 params: {page: page},
236 }, updateDOM
237 );
238 };
239 ...
240
241
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
242 The event handler for mouseovers and mouseouts are handled by the ``showOverlay`` function,
243 which creates the overlay containing photo information. In the code snippet below,
244 ``showOverlay`` makes an AJAX call to YQL to get photo data that is placed in an unordered
245 list for the overlay.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
246
247 .. code-block:: javascript
248
249 ...
250 bind: function(node) {
251 ...
252 var showOverlay = function(event) {
253 var target = event.target;
254 var href = target.get('href');
255 var imageId = parseImageId(href);
256 if (target.hasClass('overlayed')) {
257 target.removeClass('overlayed');
258 thatNode.one('#display').setContent('');
259 } else {
260 Y.log('HREF: ' + href);
261 Y.log('IMAGE ID: ' + imageId);
262 target.addClass('overlayed');
263 // Query for the image metadata
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
264 var query = 'select * from flickr.photos.info where photo_id="' + imageId + '" and api_key="' + {your_flickr_api_key} + '"';
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
265 thatNode.one('#display').setContent('Loading ...');
266 Y.YQL(query, function(raw) {
267 if (!raw.query.results.photo) {
268 Y.log('No results found for photoId: ' + imageId);
269 return;
270 }
271 var props = raw.query.results.photo;
272 var snippet = '<ul style="list-style-type: square;">';
273 for (var key in props) {
274 if (typeof(props[key]) == 'object') {
275 continue;
276 }
277 snippet += '<li>' + key + ': ' + props[key] + '</li>';
278 }
279 snippet += '</ul>';
280 thatNode.one('#display').setContent(snippet);
281 });
282 }
283 };
284 ...
285 }
286 ...
287
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
288 Thus far, we've looked at the event handlers, but not the actual binding of the handlers
289 to nodes. At the end of the ``bind`` function, you'll see three important lines
290 (shown below) that bind the ``flipper`` and ``showOutlay`` functions to handle click and
291 mouseover events.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
292
293 .. code-block:: javascript
294
295 ...
296 bind: function(node) {
297 ...
298 // Bind all the image links to showOverlay
299 thatNode.all('#master ul li a').on('mouseover', showOverlay, this);
300 thatNode.all('#master ul li a').on('mouseout', showOverlay, this);
301 // Bind the prev + next links to flipper
302 thatNode.all('#nav a').on('click', flipper, this);
303 }
304 ...
305
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
306 After a little analysis, the full ``binders/index.js`` below should be easier to
307 understand. The binder attaches event handlers to nodes, invokes a function in the
308 controller, and updates the content in the template. The binder also has a couple of
309 helper functions for parsing and requires the IO and YQL modules, which are specified in
310 the ``requires`` array.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
311
312 .. code-block:: javascript
313
314 YUI.add('PagerMojitBinder', function(Y, NAME) {
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
315 var API_KEY = '{your_api_key}';
316 function parseImageId(link) {
317 var matches = link.match(/com\/(\d+)\/(\d+)_([0-9a-z]+)\.jpg$/);
318 return matches[2];
319 }
320 function parsePage(link) {
321 var matches = link.match(/page=(\d+)/);
322 return matches[1];
323 }
324
325 /**
326 * The PagerMojitBinder module.
327 * @module PagerMojitBinder
328 */
329 /**
330 * Constructor for the Binder class.
331 *
332 * @param mojitProxy {Object} The proxy to allow
333 * the binder to interact with its owning mojit.
334 * @class Binder
335 * @constructor
336 */
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
337 Y.namespace('mojito.binders')[NAME] = {
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
338 /**
339 * Binder initialization method, invoked
340 * after all binders on the page have
341 * been constructed.
342 */
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
343 init: function(mojitProxy) {
344 this.mojitProxy = mojitProxy;
345 },
346 /**
347 * The binder method, invoked to allow the mojit
348 * to attach DOM event handlers.
349 * @param node {Node} The DOM node to which this
350 * mojit is attached.
351 */
352 bind: function(node) {
353 var thatNode = node;
354 Y.log('NODE: ' + Y.dump(this.node));
355 // define the action when user click on prev/next
356 var flipper = function(event) {
357 var target = event.target;
358 // get the link to the page
359 var page = parsePage(target.get('href'));
360 Y.log('PAGE: ' + page);
361 var updateDOM = function(markup) {
362 thatNode.set('innerHTML', markup);
363 thatNode.all('#nav a').on('click', flipper, this);
364 thatNode.all('#master ul li a').on('mouseover', showOverlay, this);
365 thatNode.all('#master ul li a').on('mouseout', showOverlay, this);
366 };
367 this.mojitProxy.invoke('index',
368 {
369 params: {page: page}
370 }, updateDOM
371 );
372 };
373 var showOverlay = function(event) {
374 var target = event.target;
375 var href = target.get('href');
376 var imageId = parseImageId(href);
377 if (target.hasClass('overlayed')) {
378 target.removeClass('overlayed');
379 thatNode.one('#display').setContent('');
380 } else {
381 Y.log('HREF: ' + href);
382 Y.log('IMAGE ID: ' + imageId);
383 target.addClass('overlayed');
384 // Query for the image metadata
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
385 var query = 'select * from flickr.photos.info where photo_id="' + imageId + '" and api_key="' + API_KEY + '"';
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
386 thatNode.one('#display').setContent('Loading ...');
387 Y.YQL(query, function(raw) {
388 if (!raw.query.results.photo) {
389 Y.log('No results found for photoId: ' + imageId);
390 return;
391 }
392 var props = raw.query.results.photo;
393 var snippet = '<ul style="list-style-type: square;">';
394 for (var key in props) {
395 if (typeof(props[key]) == 'object') {
396 continue;
397 }
398 snippet += '<li>' + key + ': ' + props[key] + '</li>';
399 }
400 snippet += '</ul>';
401 thatNode.one('#display').setContent(snippet);
402 });
403 }
404 };
405 // Bind all the image links to showOverlay
406 thatNode.all('#master ul li a').on('mouseover', showOverlay, this);
407 thatNode.all('#master ul li a').on('mouseout', showOverlay, this);
408 // Bind the prev + next links to flipper
409 thatNode.all('#nav a').on('click', flipper, this);
410 }
411 };
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
412 }, '0.0.1', {requires: ['yql', 'io', 'dump']});
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
413 Using Paging
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax f…
zhouyaoji authored
414 ------------
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
415
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
416 The paging for this code example relies on the application configuration to set route
417 paths and the controller to create links to access previous and next pages.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
418
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
419 The ``routes.json`` file below configures two route paths for HTTP GET calls made on the
420 root path. The ``perpage`` configuration, however, requires a query string with the
421 ``page`` parameter, which is used for paging. The ``page`` parameter has the value
422 ``:page``, which is a variable that is assigned a value by the controller that we're
423 going to look shortly.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
424
425 .. code-block:: javascript
426
427 [
428 {
429 "settings": ["master"],
430 "root": {
431 "verbs": ["get"],
432 "path": "/",
433 "call": "frame.index"
434 },
435 "perpage": {
436 "verbs": ["get"],
437 "path": "/?page=:page",
438 "call": "frame.index"
439 }
440 }
441 ]
442
443 The controller for ``PagerMojit`` performs several functions:
444
445 - uses the ``Params`` addon to get the ``page`` parameter from the query string
446 - calculates the index of the first photo on the page
447 - calls the ``getData`` function in the model to get photo data
448 - creates URLs for the **next** and **prev** links
449
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
450 The `Params addon <../../api/classes/Params.common.html>`_ allows you to access variables
451 from the query string parameters, the POST request bodies, or the routing systems URLs.
452 In this code example, you use the ``getFromMerged`` method, which merges the parameters
453 from the query string, POST request body, and the routing system URLs to give you access
454 to all of the parameters. In the code snippet taken from ``controller.server.js`` below,
455 the ``getFromMerged`` method is used to get the value for the ``page`` parameter and then
456 calculate the index of the first photo to display:
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
457
458 .. code-block:: javascript
459
460 ...
461 index: function(actionContext) {
462 var page = actionContext.params.getFromMerged('page');
463 var start;
464 page = parseInt(page) || 1;
465 if ((!page) || (page<1)) {
466 page = 1;
467 }
468 // Page param is 1 based, but the model is 0 based
469 start = (page - 1) * PAGE_SIZE;
470 ...
471 }
472 ...
473
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
474 To get the photo data, the controller depends on the model to call YQL to query the
475 Flickr API. Using ``actionContext.models.{model_name}`` lets you get a reference to the
476 model. In this example controller, the model of the ``PagerMojit`` is accessed through
477 ``actionContext.models.PageMojit``, allowing you to call ``getData`` and get the returned
478 data from YQL in the callback function.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
479
480 .. code-block:: javascript
481
482 ...
483 index: function(actionContext) {
484 ...
485 var model = actionContext.models.PagerMojit;
486 // Data is an array of images
487 model.getData('mojito', start, PAGE_SIZE, function(data) {
488 Y.log('DATA: ' + Y.dump(data));
489 var theData = {
490 data: data, // images
491 hasLink: false,
492 prev: {
493 title: "prev" // opportunity to localize
494 },
495 next: {
496 link: createLink(actionContext, {page: page+1}),
497 title: "next"
498 },
499 query: 'mojito'
500 };
501 if (page > 1) {
502 theData.prev.link = createLink(actionContext, {page: page-1});
503 theData.hasLink = true;
504 }
505 actionContext.done(theData);
506 });
507 }
508 ...
509 };
510 ...
511
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
512 The URLs for the **prev** and **next** links are created by passing the mojit instance,
513 the method, and the query string parameters to the ``make`` method from the ``Url`` addon.
514 The code snippet below creates the query string parameters with the
515 `YUI QueryString module <http://yuilibrary.com/yui/docs/api/modules/querystring.html>`_.
516 If the query string created by ``Y.QueryString.stringify`` is "page=2" ,
517 ``actionContext.url.make`` would return the URL ``{domain_name}:8666/?page=2``.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
518
519 .. code-block:: javascript
520
521 ...
522 function createLink(actionContext, params) {
523 var mergedParams = Y.mojito.util.copy(actionContext.params.getFromMerged());
524 for (var k in params) {
525 mergedParams[k] = params[k];
526 }
527 return actionContext.url.make('frame', 'index', Y.QueryString.stringify(mergedParams));
528 }
529 ...
530
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
531 Stitching the above code snippets together, we have the ``controller.server.js`` below.
532 The ``index`` function relies on the model for data and the ``createLink`` function to
533 create URLs for the **next** and **prev** links.
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
534
535 .. code-block:: javascript
536
74b3d8a @zhouyaoji Fixed syntax for namespacing controllers/models in docs/examples.
zhouyaoji authored
537 YUI.add('PagerMojit', function(Y, NAME) {
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
538 /**
539 * The PagerMojit module.
540 * @module PagerMojit */
541 var PAGE_SIZE = 10;
542 /**
543 * Constructor for the Controller class.
544 * @class Controller
545 * @constructor
546 */
74b3d8a @zhouyaoji Fixed syntax for namespacing controllers/models in docs/examples.
zhouyaoji authored
547 Y.namespace('mojito.controllers')[NAME] = {
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
548 init: function(config) {
549 this.config = config;
550 },
551 index: function(actionContext) {
552 var page = actionContext.params.getFromMerged('page');
553 var start;
554 page = parseInt(page) || 1;
555 if ((!page) || (page<1)) {
556 page = 1;
557 }
558 // Page param is 1 based, but the model is 0 based
559 start = (page - 1) * PAGE_SIZE;
560 var model = actionContext.models.PagerMojit;
561 // Data is an array of images
562 model.getData('mojito', start, PAGE_SIZE, function(data) {
563 Y.log('DATA: ' + Y.dump(data));
564 var theData = {
565 data: data, // images
566 hasLink: false,
567 prev: {
568 title: "prev" // opportunity to localize
569 },
570 next: {
571 link: createLink(actionContext, {page: page+1}),
572 title: "next"
573 },
574 query: 'mojito'
575 };
576 if (page > 1) {
577 theData.prev.link = createLink(actionContext, {page: page-1});
578 theData.hasLink = true;
579 }
580 actionContext.done(theData);
581 });
582 }
583 };
584 // generate the link to the next page based on:
585 // - mojit id
586 // - action
587 // - params
588 function createLink(actionContext, params) {
589 var mergedParams = Y.mojito.util.copy(actionContext.params.getFromMerged());
590 for (var k in params) {
591 mergedParams[k] = params[k];
592 }
593 return actionContext.url.make('frame', 'index', Y.QueryString.stringify(mergedParams));
594 }
595 }, '0.0.1', {requires: ['dump']});
596
597 Setting Up this Example
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax f…
zhouyaoji authored
598 =======================
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
599
600 To set up and run ``binding_events``:
601
602 #. Create your application.
603
604 ``$ mojito create app binding_events``
605 #. Change to the application directory.
606 #. Create your mojit.
607
608 ``$ mojito create mojit PagerMojit``
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
609 #. To configure you application to run on the client and use ``HTMLFrameMojit``, replace
610 the code in ``application.json`` with the following:
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
611
612 .. code-block:: javascript
613
614 [
615 {
616 "settings": [ "master" ],
617 "specs": {
618 "frame": {
619 "type": "HTMLFrameMojit",
620 "config": {
621 "deploy": true,
622 "child": {
623 "type": "PagerMojit"
624 }
625 }
626 }
627 }
628 }
629 ]
630
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
631 #. To configure routing to call the ``index`` action from the instance of the
632 ``HTMLFrameMojit``, replace the code in ``routes.json`` with the following:
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
633
634 .. code-block:: javascript
635
636 [
637 {
638 "settings": ["master"],
639 "root": {
640 "verbs": ["get"],
641 "path": "/",
642 "call": "frame.index"
643 },
644 "perpage": {
645 "verbs": ["get"],
646 "path": "/?page=:page",
647 "call": "frame.index"
648 }
649 }
650 ]
651
652 #. Change to ``mojits/PageMojit``.
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
653 #. To have the controller get data from the model and create links for paging, replace the
654 code in ``controller.server.js`` with the following:
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
655
656 .. code-block:: javascript
657
74b3d8a @zhouyaoji Fixed syntax for namespacing controllers/models in docs/examples.
zhouyaoji authored
658 YUI.add('PagerMojit', function(Y, NAME) {
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
659 var PAGE_SIZE = 10;
660 /**
661 * Constructor for the Controller class.
662 * @class Controller
663 * @constructor
664 */
74b3d8a @zhouyaoji Fixed syntax for namespacing controllers/models in docs/examples.
zhouyaoji authored
665 Y.namespace('mojito.controllers')[NAME] = {
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
666 init: function(config) {
667 this.config = config;
668 },
669 index: function(actionContext) {
670 var page = actionContext.params.getFromMerged('page');
671 var start;
672 page = parseInt(page) || 1;
673 if ((!page) || (page<1)) {
674 page = 1;
675 }
676 // Page param is 1 based, but the model is 0 based
677 start = (page - 1) * PAGE_SIZE;
678 var model = actionContext.models.PagerMojit;
679 // Data is an array of images
680 model.getData('mojito', start, PAGE_SIZE, function(data) {
681 Y.log('DATA: ' + Y.dump(data));
682 var theData = {
683 data: data, // images
684 hasLink: false,
685 prev: {
686 title: "prev" // opportunity to localize
687 },
688 next: {
689 link: createLink(actionContext, {page: page+1}),
690 title: "next"
691 },
692 query: 'mojito'
693 };
694 if (page > 1) {
695 theData.prev.link = createLink(actionContext, {page: page-1});
696 theData.hasLink = true;
697 }
698 actionContext.done(theData);
699 });
700 }
701 };
702 // Generate the link to the next page based on:
703 // - mojit id
704 // - action
705 // - params
706 function createLink(actionContext, params) {
707 var mergedParams = Y.mojito.util.copy(actionContext.params.getFromMerged());
708 for (var k in params) {
709 mergedParams[k] = params[k];
710 }
711 return actionContext.url.make('frame', 'index', Y.QueryString.stringify(mergedParams));
712 }
713 }, '0.0.1', {requires: ['dump']});
714
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
715 #. To get Flickr photo information using YQL, replace the code in ``model.server.js`` with
716 the following:
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
717
718 .. code-block:: javascript
719
74b3d8a @zhouyaoji Fixed syntax for namespacing controllers/models in docs/examples.
zhouyaoji authored
720 YUI.add('PagerMojitModel', function(Y, NAME) {
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
721 var API_KEY = '{your_api_key}';
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
722 /**
723 * The PagerMojitModel module.
724 * @module PagerMojitModel
725 */
726 /**
727 * Constructor for the Model class.
728 * @class Model
729 * @constructor
730 */
74b3d8a @zhouyaoji Fixed syntax for namespacing controllers/models in docs/examples.
zhouyaoji authored
731 Y.namespace('mojito.models')[NAME] = {
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
732 init: function(config) {
733 this.config = config;
734 },
735 getData: function(query, start, count, callback) {
736 var q = null;
737 // Get Flickr API key: http://www.flickr.com/services/api/keys/apply/
738 var API_KEY = "{your_api_key}";
739 start = parseInt(start) || 0;
740 count = parseInt(count) || 10;
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
741 q = 'select * from flickr.photos.search(' + start + ',' + count + ') where text="%' + query + '%" and api_key="' + API_KEY+ '"';
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
742 Y.YQL(q, function(rawData) {
743 if (!rawData.query.results) {
744 callback([]);
745 return;
746 }
747 var rawImages = rawData.query.results.photo, rawImage = null,images = [], image = null, i = 0;
748 for (; i<rawImages.length; i++) {
749 rawImage = rawImages[i];
750 image = {
751 title: rawImage.title,
752 location: 'http://farm' + rawImage.farm + '.static.flickr.com/' + rawImage.server + '/' + rawImage.id + '_' + rawImage.secret + '.jpg',
753 farm: rawImage.farm,
754 server: rawImage.server,
755 image_id: rawImage.id,
756 secret: rawImage.secret
757 };
758 if (!image.title) {
759 image.title = "Generic Title: " + query;
760 }
761 images.push(image);
762 }
763 callback(images);
764 });
765 }
766 };
767 }, '0.0.1', {requires: ['yql']});
768
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
769 #. To create the binder for click events and invoke the ``index`` function of the
770 controller, replace the code in ``binders/index.js`` with the following:
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
771
772 .. code-block:: javascript
773
774 YUI.add('PagerMojitBinder', function(Y, NAME) {
3c5bb67 @zhouyaoji Added a placeholder for the API key and modified query.
zhouyaoji authored
775 var API_KEY = '{your_api_key}';
776 function parseImageId(link) {
777 var matches = link.match(/com\/(\d+)\/(\d+)_([0-9a-z]+)\.jpg$/);
778 return matches[2];
779 }
780 function parsePage(link) {
781 var matches = link.match(/page=(\d+)/);
782 return matches[1];
783 }
784
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
785 /**
786 * The PagerMojitBinder module.
787 * @module PagerMojitBinder
788 */
789 /**
790 * Constructor for the Binder class.
791 *
792 * @param mojitProxy {Object} The proxy to allow
793 * the binder to interact with its owning mojit.
794 * @class Binder
795 * @constructor
796 */
797 Y.namespace('mojito.binders')[NAME] = {
798 /**
799 * Binder initialization method, invoked
800 * after all binders on the page have
801 * been constructed.
802 */
803 init: function(mojitProxy) {
804 this.mojitProxy = mojitProxy;
805 },
806 /**
807 * The binder method, invoked to allow the mojit
808 * to attach DOM event handlers.
809 * @param node {Node} The DOM node to which this
810 * mojit is attached.
811 */
812 bind: function(node) {
813 var thatNode = node;
814 Y.log('NODE: ' + Y.dump(this.node));
815 // define the action when user click on prev/next
816 var flipper = function(event) {
817 var target = event.target;
818 // get the link to the page
819 var page = parsePage(target.get('href'));
820 Y.log('PAGE: ' + page);
821 var updateDOM = function(markup) {
822 thatNode.set('innerHTML', markup);
823 thatNode.all('#nav a').on('click', flipper, this);
824 thatNode.all('#master ul li a').on('mouseover', showOverlay, this);
825 thatNode.all('#master ul li a').on('mouseout', showOverlay, this);
826 };
827 this.mojitProxy.invoke('index',
828 {
829 params: {page: page}
830 }, updateDOM
831 );
832 };
833 var showOverlay = function(event) {
834 var target = event.target;
835 var href = target.get('href');
836 var imageId = parseImageId(href);
837 if (target.hasClass('overlayed')) {
838 target.removeClass('overlayed');
839 thatNode.one('#display').setContent('');
840 } else {
841 Y.log('HREF: ' + href);
842 Y.log('IMAGE ID: ' + imageId);
843 target.addClass('overlayed');
844 // Query for the image metadata
f0af949 @zhouyaoji Updated query.
zhouyaoji authored
845 var query = 'select * from flickr.photos.info where photo_id="' + imageId + '" and api_key="' + API_KEY + '"';
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
846 thatNode.one('#display').setContent('Loading ...');
847 Y.YQL(query, function(raw) {
848 if (!raw.query.results.photo) {
849 Y.log('No results found for photoId: ' + imageId);
850 return;
851 }
852 var props = raw.query.results.photo;
853 var snippet = '<ul style="list-style-type: square;">';
854 for (var key in props) {
855 if (typeof(props[key]) == 'object') {
856 continue;
857 }
858 snippet += '<li>' + key + ': ' + props[key] + '</li>';
859 }
860 snippet += '</ul>';
861 thatNode.one('#display').setContent(snippet);
862 });
863 }
864 };
865 // Bind all the image links to showOverlay
866 thatNode.all('#master ul li a').on('mouseover', showOverlay, this);
867 thatNode.all('#master ul li a').on('mouseout', showOverlay, this);
868 // Bind the prev + next links to flipper
869 thatNode.all('#nav a').on('click', flipper, this);
870 }
871 };
872 }, '0.0.1', {requires: ['yql', 'io', 'dump']});
873
351e25f @zhouyaoji Added a prereq for doing the code example, added a link to get Flickr…
zhouyaoji authored
874 #. To display links to photos and associated photo data in the rendered template, replace
875 the code in ``views/index.hb.html`` with the following:
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
876
877 .. code-block:: html
878
879 <div id="{{mojit_view_id}}" class="mojit" style="position: relative; width: 960px">
880 <h3>Query Term: {{query}}</h3>
881 <div id="nav" style="clear: both;">
882 {{#hasLink}}
883 {{#prev}}
884 <a href="{{{link}}}">{{title}}</a>
885 {{/prev}}
886 {{/hasLink}}
887 {{^hasLink}}
888 {{#prev}}{{title}}{{/prev}}
889 {{/hasLink}}
890 {{#next}}
891 <a href="{{{link}}}">{{title}}</a>
892 {{/next}}
893 </div>
894 <div id="master" style="width: 30%; float: left;">
895 <ul>
896 {{#data}}
897 <li><a href="{{location}}" data-id="{{image_id}}">{{title}}</a></li>
898 {{/data}}
899 </ul>
900 </div>
901 <div style="width: 50%; float: right">
902 <!-- load image here dynamically -->
903 <div id="display" style="margin: 0 auto;">
904 &nbsp;
905 </div>
906 </div>
907 </div>
908
909 #. From the application directory, run the server.
910
911 ``$ mojito start``
912 #. To view your application, go to the URL:
913
914 http://localhost:8666
915
916 Source Code
b5ece1a @zhouyaoji Fixed steps, replaced 'view template' with 'template', fixed syntax f…
zhouyaoji authored
917 ===========
4b30716 @zhouyaoji Adding the reST documentation to the Mojito project.
zhouyaoji authored
918
919 - `Application Configuration <http://github.com/yahoo/mojito/tree/master/examples/developer-guide/binding_events/application.json>`_
920 - `Mojit Binder <http://github.com/yahoo/mojito/tree/master/examples/developer-guide/binding_events/mojits/PagerMojit/binders/index.js>`_
74b3d8a @zhouyaoji Fixed syntax for namespacing controllers/models in docs/examples.
zhouyaoji authored
921 - `Binding Events Application <http://github.com/yahoo/mojito/tree/master/examples/developer-guide/binding_events/>`_
Something went wrong with that request. Please try again.