5
<title>App Framework</title>
6
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Maven+Pro:400,700">
7
<link rel="stylesheet" href="../../build/cssgrids/grids-min.css">
8
<link rel="stylesheet" href="../assets/css/main.css">
9
<link rel="stylesheet" href="../assets/vendor/prettify/prettify-min.css">
10
<script src="../../build/yui/yui-min.js"></script>
15
<h1>App Framework</h1>
18
<a href="#toc" class="jump">Jump to Table of Contents</a>
22
<div class="yui3-u-3-4">
24
<div class="content"><div class="intro">
26
The YUI App Framework is a rollup of the <a href="#app-component">App</a>, <a href="../model/index.html">Model</a>, <a href="../model-list/index.html">Model List</a>, <a href="../router/index.html">Router</a>, and <a href="../view/index.html">View</a> components, combined to form a simple MVC-style framework for writing single-page JavaScript applications.
30
You can use these components separately or together to create anything from simple non-interactive views to rich applications with URL-based routing, data binding, and full client-server synchronization.
34
If you've used <a href="http://www.documentcloud.org/">DocumentCloud</a>'s excellent <a href="http://documentcloud.github.com/backbone/">Backbone.js</a> framework, many of the classes and APIs provided by App Framework components will look familiar to you. There are important differences, though, and the App Framework takes full advantage of YUI's powerful component and event infrastructure under the hood.
38
<h2 id="getting-started">Getting Started</h2>
41
To include the source files for App Framework and its dependencies, first load
42
the YUI seed file if you haven't already loaded it.
45
<pre class="code prettyprint"><script src="http://yui.yahooapis.com/3.5.1/build/yui/yui-min.js"></script></pre>
49
Next, create a new YUI instance for your application and populate it with the
50
modules you need by specifying them as arguments to the <code>YUI().use()</code> method.
51
YUI will automatically load any dependencies required by the modules you
55
<pre class="code prettyprint"><script>
56
// Create a new YUI instance and populate it with the required modules.
57
YUI().use('app', function (Y) {
58
// App Framework is available and ready for use. Add implementation
59
// code here.
61
</script></pre>
65
For more information on creating YUI instances and on the
66
<a href="http://yuilibrary.com/yui/docs/api/classes/YUI.html#method_use"><code>use()</code> method</a>, see the
67
documentation for the <a href="../yui/index.html">YUI Global Object</a>.
71
<h2 id="components-of-the-app-framework">Components of the App Framework</h2>
74
The <code>app</code> module is a rollup module consisting of the following individual components. These components may also be used individually if you don't need all of them at the same time.
87
<td><a href="#app-component">App</a></td>
88
<td style="white-space: nowrap;"><code>app-base</code></td>
91
Provides a top-level application component which manages navigation and views. This gives you a foundation and structure on which to build your application; it combines robust URL navigation with powerful routing and flexible view management.
97
<td><a href="../model/index.html">Model</a></td>
98
<td><code>model</code></td>
101
A lightweight <a href="http://yuilibrary.com/yui/docs/api/classes/Attribute.html"><code>Y.Attribute</code></a>-based data model with APIs for getting, setting, validating, and syncing attribute values to a persistence layer or server, as well as events for notifying subscribers of model changes.
107
<td><a href="../model-list/index.html">Model List</a></td>
108
<td style="white-space: nowrap;"><code>model-list</code></td>
111
An array-like ordered list of <code>Y.Model</code> instances with APIs for adding, removing, sorting, filtering, and performing other actions on models in the list. Acts as a bubble target for events fired by the models in the list.
117
<td><a href="../router/index.html">Router</a></td>
118
<td><code>router</code></td>
121
Provides URL-based same-page routing using <a href="https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history">HTML5 history</a> (<code>pushState</code>) or the location hash, depending on what the user's browser supports.
127
<td><a href="../view/index.html">View</a></td>
128
<td><code>view</code></td>
131
Represents a piece of an application's user interface and is responsible for rendering content and handling DOM events. Views are commonly associated with Models or Model Lists and are re-rendered when they change, although this isn't required.
138
<h2 id="app-component">App Component</h2>
141
App is a high-level component that builds upon other components in the App Framework. The App component is composed of <a href="../router/index.html">Router</a> and <a href="../view/index.html">View</a>, and also the <a href="../pjax/index.html">Pjax</a> utility. This combination creates a solid foundation and structure on which to build your application. It connects together robust URL navigation with powerful routing and flexible view management.
145
The goal of the App component is to provide you a place to organize and connect together the parts of your application. App implements infrastructural pieces which are common to all apps — such as <a href="#view-management">managing views</a> and the <a href="#navigating-between-pages">navigation between pages</a> — allowing you to focus on the specifics of <em>your</em> app.
149
App will enable you to seamlessly enhance the user experience and performance of traditional client/server apps. It enables you to create richer interactions without compromising standard browser behavior, URLs, or search engine craw-ability. The <a href="#routing-coordination-with-server">Routing Coordination with Server</a> section of this guide contain details on accomplishing this.
153
You can also use the App component to build client-only apps for when there is no server, or the server is not capable of routing and handling requests. There are <strong>drawbacks to client-only apps</strong> which you need to be aware of and fully understand their implications. Be sure to read the <a href="#progressively-enhanced-vs-client-only-apps">Progressively-enhanced vs. Client-only Apps</a> section which contains details on these drawbacks and best practices.
157
The remaining sections of this guide provide details on what you'll need to know to start working with the App component. Refer to the previous section for information about the <a href="#components-of-the-app-framework">other components of the App Framework</a>.
160
<h2 id="using-app">Using App</h2>
162
<h3 id="instantiating-app">Instantiating App</h3>
165
Creating an App instance couldn't be any simpler:
168
<pre class="code prettyprint">var app = new Y.App();</pre>
172
Two instantiable classes are provided by the <code>app-base</code> module: <code>Y.App</code>, and <code>Y.App.Base</code>. The difference between these is that <code>Y.App.Base</code> provides the basic app functionality and will remain pure; whereas <code>Y.App</code> (which extends <code>Y.App.Base</code>) will have all of the app-component extensions automatically mixed-in when they are included in the YUI instance.
176
In the following example, we are including both the <code>app-base</code> and <code>app-transitions</code> modules. When the <code>app-transitions</code> module is added to the YUI instance it will automatically mix itself into the <code>Y.App</code> class, adding transitions to all <code>Y.App</code> instances, but <code>Y.App.Base</code> will remain unaffected by the inclusion of this module.
179
<pre class="code prettyprint">YUI().use('app-base', 'app-transitions', function (Y) {
180
// This will create two YUI Apps, `basicApp` will not have transitions,
181
// but `fancyApp` will have transitions support included and turn itself on.
182
var basicApp = new Y.App.Base(),
183
fancyApp = new Y.App({transitions: true});
188
While App instances are usable without any configuration, any non-trivial app will need to be configured. You might also want to extend <code>Y.App</code> by mixing-in additional functionality, or even create a custom App class to implement the specific features of your application. The <a href="#extending-yapp">Extending <code>Y.App</code></a> section explains how to do this.
191
<h4 id="config-properties">Config Properties</h4>
194
When constructing a new <code>Y.App</code> instance you can provide a config object with initial values for <a href="#app-attributes">attributes</a> along with values for <a href="../view/index.html#view-properties"><code>Y.View</code>'s properties</a> and <a href="../api/classes/Base.html"><code>Y.Base</code>'s "special" properties</a> (used only during initialization). In addition to these, the following non-attribute properties have specific initialization logic applied and can be passed to the <code>Y.App</code> constructor:
198
<dt><code>views</code></dt>
201
Hash of view-name to metadata used to declaratively describe an application's views and their relationship with the app and its other views. The views specified here will override any defaults provided by the <code>views</code> object on the <code>prototype</code>. Every <code>Y.App</code> instance gets its own copy of a <code>views</code> object so this object on the prototype will not be polluted.
205
See the <a href="#app-properties">App Properties</a> and <a href="#declaring-views">Declaring Views</a> sections for more details.
211
Here's an example that defines some <code>views</code> at instantiation time:
214
<pre class="code prettyprint">var app = new Y.App({
216
home : {preserve: true},
217
users: {preserve: true},
218
user : {parent: 'users'}
223
<h3 id="app-properties">App Properties</h3>
226
The following properties are meaningful to App classes and subclasses. In addition to these, <a href="../view/index.html#view-properties">View's properties</a> are also applicable <code>Y.View</code> is part of App's composition.
233
<th>Default Value</th>
239
<td><code>views</code></td>
240
<td><code>{}</code></td>
243
Hash of view-name to metadata used to declaratively describe an application's views and their relationship with the app and its other views. See <a href="#declaring-views">Declaring Views</a> for more details.
247
The view metadata is composed of Objects keyed to a view-name that can have any or all of the following properties:
250
<dl style="margin-top:1em">
251
<dt><code>type</code></dt>
254
Function or a string representing the view constructor to use to create view instances. If a string is used, the constructor function is assumed to be on the <code>Y</code> object; e.g. <code>"SomeView"</code> -> <code>Y.SomeView</code>.
258
<dt><code>preserve</code></dt>
261
Boolean for whether the view instance should be retained. By default, the view instance will be destroyed when it is no longer the <code>activeView</code>. If <code>true</code> the view instance will simply be <code>removed()</code> from the DOM when it is no longer active. This is useful when the view is frequently used and may be expensive to re-create. See <a href="#preserved-views">Preserved Views</a> for best practices.
265
<dt><code>parent</code></dt>
268
String to another named view in this hash that represents the parent view within the application's view hierarchy; e.g. a <code>"photo"</code> view could have <code>"album"</code> has its <code>parent</code> view. This parent/child relationship is a useful cue for things like transitions.
272
<dt><code>instance</code></dt>
275
Used internally to manage the current instance of this named view. This can be used if your view instance is created up-front, or if you would rather manage the View lifecycle, but you probably should just let this be handled for you.
283
<td><code>transitions</code></td>
284
<td><code>{}</code></td>
287
Default transitions to use when the <code>activeView</code> changes. See the <a href="#switching-the-active-view">Switching the Active View</a> and <code><a href="#yapptransitions">Y.App.Transitions</a></code> sections for more details.
291
The following are types of changes for which transitions can be defined that correspond to the relationship between the new and old <code>activeView</code>:
294
<dl style="margin-top:1em">
295
<dt><code>navigate</code></dt>
298
The default transition to use when changing the <code>activeView</code> of the application. This will be <strong><code>"fade"</code></strong> by default.
302
<dt><code>toChild</code></dt>
305
The transition to use when the new <code>activeView</code> is configured as a child of the previously active view via its <code>parent</code> property as defined in this app's <code>views</code>. This will be <strong><code>"slideLeft"</code></strong> by default.
309
<dt><code>toParent</code></dt>
312
The transition to use when the new <code>activeView</code> is configured as the <code>parent</code> of the previously active view as defined in this app's <code>views</code>. This will be <strong><code>"slideRight"</code></strong> by default.
322
The App class uses both properties and attributes. Properties are best when their stored data might be useful to multiple App instances, whereas attributes are best when the data being stored only pertains to a single instance.
325
<h3 id="app-attributes">App Attributes</h3>
328
App is composed of <a href="../view/index.html#view-attributes">View</a>, <a href="../router/index.html#config-attributes">Router</a>, and <a href="../pjax/index.html#config-attributes">Pjax</a>, all of which provide attributes that will be of interest to you — beyond these, App adds the following attributes:
335
<th>Default Value</th>
341
<td><code>activeView</code></td>
342
<td><code>null</code></td>
345
The application's active/visible view. This attribute is read-only, to set the <code>activeView</code> use the <code>showView()</code> method.
349
See <a href="#switching-the-active-view">Switching the Active View</a> for more details.
355
<td><code>serverRouting</code></td>
356
<td><code>undefined</code></td>
359
Whether or not this application's server is capable of properly routing all requests and rendering the initial state in the HTML responses.
363
This can have three different values, each having particular implications on how the app will handle routing and navigation:
366
<dl style="margin-top:1em">
367
<dt><code>undefined</code></dt>
370
The best form of URLs will be chosen based on the capabilities of the browser. Given no information about the server environment, a balanced approach to routing and navigation is chosen. See <a href="#urls-based-on-browser-capabilities">URLs Based on Browser Capabilities</a> for more details.
374
<dt><code>true</code></dt>
377
The server is <em>fully</em> capable of properly handling requests to all full-path URLs the app can produce.
381
This is the best option for progressive-enhancement because it will cause <strong>all URLs to always have full-paths</strong>, which means the server will be able to accurately handle all URLs this app produces. See <a href="#full-path-urls-only">Full-path URLs Only</a> and <a href="#progressively-enhanced-vs-client-only-apps">Progressively-enhanced vs. Client-only Apps</a> for more details.
385
<dt><code>false</code></dt>
388
The server is <em>not</em> capable of properly handling requests to all full-path URLs the app can produce, therefore <em>all</em> routing will be handled by this App instance.
392
Be aware that this will cause <strong>all URLs to always be hash-based</strong>, even in browsers that are capable of using HTML5 history. Please make sure you fully understand the implications of client-only apps. See <a href="#hash-based-urls-only">Hash-based URLs Only</a> and <a href="#progressively-enhanced-vs-client-only-apps">Progressively-enhanced vs. Client-only Apps</a> for more details.
398
See <a href="#routing-coordination-with-server">Routing Coordination with Server</a> for more details.
404
<td><code>transitions</code></td>
405
<td><code>false</code></td>
408
Whether or not this application should use view transitions, and if so then which ones or <code>true</code> for the defaults which are specified by the <code>transitions</code> prototype property.
412
<strong>Note:</strong> Transitions are an opt-in feature and will only be used in browsers which support native CSS3 transitions.
416
See the <a href="#switching-the-active-view">Switching the Active View</a> and <code><a href="#yapptransitions">Y.App.Transitions</a></code> sections for more details.
422
<td><code>viewContainer</code></td>
423
<td><code><div></code> Node</td>
426
The node into which this app's <code>views</code> will be rendered when they become the <code>activeView</code>.
430
The view container node serves as the container to hold the app's <code>activeView</code>. Each time the <code>activeView</code> is set via <code>showView()</code>, the previous view will be removed from this node, and the new active view's <code>container</code> node will be appended.
434
The default view container is a <code><div></code> Node, but you can override this in a subclass, or by passing in a custom <code>viewContainer</code> config value at instantiation time. The <code>viewContainer</code> may be provided as a selector string, DOM element, or a <code>Y.Node</code> instance (having the <code>viewContainer</code> and the <code>container</code> be the same node is also supported).
438
The app's <code>render()</code> method will stamp the view container with the CSS class <code>"yui3-app-views"</code> and append it to the app's <code>container</code> node if it isn't already, and any <code>activeView</code> will be appended to this node if it isn't already.
442
See <a href="#rendering-an-app">Rendering an App</a> for more details.
450
A few of App's inherited attributes are given new default values:
457
<th>Inherited From</th>
458
<th>New Default Value</th>
464
<td><code>container</code></td>
465
<td><code>Y.View</code></td>
466
<td><code><body></code> Node</td>
469
Apps are considered to be full-page by default.
475
<td><code>html5</code></td>
476
<td><code>Y.Router</code></td>
480
This value is dependent on the value of <code>serverRouting</code> and will default accordingly.
486
<td><code>linkSelector</code></td>
487
<td><code>Y.PjaxBase</code></td>
488
<td><code>"a"</code></td>
491
By default this selector should match <em>all</em> links on the page because full-page apps are the default.
498
<h3 id="routing-coordination-with-server">Routing Coordination with Server</h3>
501
A primary feature of App is its powerful routing which enables you to enhance the user experience and performance of traditional client/server apps. Using <code>Y.App</code> you can create more meaningful and richer interactions for a user navigating through your application. App's routing features center on progressive enhancement and do <em>not</em> compromise standard browser features (back/forward button support), URLs, or search engine craw-ability.
505
There are two attributes which are used to configure an app's URLs and how its routing should coordinate with the server:
509
<dt><code>root</code></dt>
512
An app's <code>root</code> is the absolute path from which all routes should be evaluated, i.e. the path at which the app is mounted, usually "/".
516
See <a href="../router/index.html#setting-the-root-path">Setting the Root Path</a> in Router's user guide for more information.
520
<dt><code>serverRouting</code></dt>
523
Models a higher level concept over the capabilities of, and interactions between the browser and server with respect to URLs and inter-page navigation. This attribute determines how your <code>Y.App</code> instance will interact with the server: set this to <code>true</code> if the app can be progressively enhanced, or <code>false</code> if it's a client side-only app.
527
<strong>Note:</strong> The value of an app's <code>html5</code> attribute depends on the value of its <code>serverRouting</code> attribute. When <code>serverRouting</code> is explicit set to <code>false</code> (not just falsy), the default value for <code>html5</code> will be set to <code>false</code> for <em>all</em> browsers. When <code>serverRouting</code> is <code>true</code> or <code>undefined</code> the returned value will be dependent on the browser's capability of using HTML5 history.
533
<strong>Looking for general information about routing?</strong> See the <a href="../router/index.html#routing">Routing</a> section in Router's user guide.
536
<h4 id="urls-based-on-browser-capabilities">URLs Based on Browser Capabilities</h4>
539
This is the <strong>default</strong> behavior of how an app's routing will coordinate with the server. When <code>serverRouting</code> is left <code>undefined</code>, the app is given no information about the server's capabilities. In this case a balanced approach to URLs, routing, and navigation will be used:
545
Full-path URLs will only be used if the browser is capable of using HTML5 history, otherwise hash-based URLs will be used.
551
The <code>Y.App</code> instance will handle <em>all</em> routing since it is unknown whether the server is capable of properly routing requests.
557
The server is <em>required</em> to handle full-path URLs which will be generated by browsers which use the HTML5 <code>pushState()</code> history API. A server can handle these requests by either rendering the initial state in the HTML, or redirecting to a hash-based URL and letting the app dispatch to its route handlers.
563
This behavior has been chosen as the default because it provides the best path forward for a developer to upgrade a client side-only app to a progressively enhanced app (but you should always prefer to build an app using progressive enhancement from the start, that's the whole point).
567
The following is a simple <a href="http://nodejs.org/">Node.js</a> <a href="http://expressjs.com/">Express</a> server and very basic <code>Y.App</code> instance which demonstrate how the client and server can coordinate routing and the fulfillment of a request when using URLs that conform to the capabilities of the browser, but the server is "dumb":
570
<h5 class="no-toc">server.js - The Node.js Express server</h5>
572
<pre class="code prettyprint">var server = require('express').createServer();
574
// Handles requests to the root path ("/") my simply sending the "shell" page
575
// which creates the `Y.App` instance.
576
server.get('/', function (req, res) {
577
res.sendfile('index.html');
580
// Handles all other requests by redirecting the browser back to the root path
581
// and tacking on URL's path as the fragment; e.g. "/foo/" => "/#/foo/".
582
server.get('*', function (req, res) {
583
res.redirect('/#' + req.url, 302);
586
server.listen(process.env.PORT || 3000);</pre>
589
<h5 class="no-toc"><code>index.html</code> - The "shell" page for the <code>Y.App</code> instance</h5>
591
<pre class="code prettyprint"><!DOCTYPE html>
595
<meta charset="utf-8" />
596
<title>Example App</title>
600
<h1></h1>
602
<script src="http://yui.yahooapis.com/3.5.1/build/yui/yui-min.js"></script>
604
YUI().use('app-base', function (Y) {
606
var app = new Y.App({
607
// Configure the app.
610
// Handles requests for the root by updating the page heading.
611
app.route('/', function () {
612
Y.one('h1').set('text', 'Example App - Home');
615
// Handles all other requests by updating the page heading and
616
// displaying current path in it.
617
app.route('*', function (req) {
618
Y.one('h1').set('text', 'Example App - ' + req.path);
621
// Make sure to dispatch the current hash-based URL which was set by
622
// the server to our route handlers.
623
app.render().dispatch();
629
</html></pre>
633
In the above example, the server handles full URLs by sending a redirect back to the root ("/") with a hash-based path and serves a "shell" HTML page to delegate control to a <code>Y.App</code> instance. Once the app is loaded, it will dipatch the hash-based path to its route handlers, finishing the fulfillment of the request on the client.
637
You could also implement the server-side redirection logic using an Apache Mod Rewrite <code>.htaccess</code> file:
640
<pre class="code">RewriteEngine On
641
RewriteRule ^(.+)$ /#/$1 [L]</pre>
644
<h4 id="full-path-urls-only">Full-path URLs Only</h4>
647
Full-path URLs are standard URLs which have matching routes based on the URL's path segments. The follow are example full-path URLs you might expect to see in a photos application:
650
<pre class="code">http://example.com/
651
http://example.com/photos/
652
http://example.com/photos/1
653
http://example.com/photos/2
654
http://example.com/albums/
655
http://example.com/albums/vacation</pre>
659
Setting an app's <code>serverRouting</code> attribute to <code>true</code> signals that the server <em>is</em> capable of properly handling requests to all full-path URLs the app can produce. This causes the app to <em>always</em> use full-path URLs, regardless of whether the browser can use HTML5 history or not. In this case the capabilities of the client and server are coordinated in the most optimal way, giving the app the following qualities:
665
Full-path URLs are <em>always</em> used, older browsers which can not use HTML5 history will have to do full page loads.
671
The <code>Y.App</code> instance will only handle routing in browser which support HTML5 history, the other browser's "requests" will be handled completely by the server.
677
The server is <em>required</em> to handle full-path URLs which will be generated by the app. Ideally the server should render the application's initial state in the response HTML for the given URL.
683
This is the <strong>best option for progressive enhancement</strong>! All users of your app will have the same, full-path URLs, independent of the browser or device they are using. Configuring your app with <code>serverRouting</code> set to <code>true</code> means that the client and server components of your application are working together to provide the best overall experience for your users.
687
See <a href="#progressively-enhanced-vs-client-only-apps">Progressively-enhanced vs. Client-only Apps</a> for more information about best practices.
690
<h4 id="hash-based-urls-only">Hash-based URLs Only</h4>
693
Hash-based URLs have matching routes based on the URL's fragment identifier ("#"). The follow are example hash-based URLs you might expect to see in a photos application:
696
<pre class="code">http://example.com/#/
697
http://example.com/#/photos/
698
http://example.com/#/photos/1
699
http://example.com/#/photos/2
700
http://example.com/#/albums/
701
http://example.com/#/albums/vacation</pre>
705
Notice how the above URLs actually all contain the same path segment ("/"), but use the fragment identifier ("#") to hold a pseudo-path value.
709
Setting an app's <code>serverRouting</code> attribute to <code>false</code> signals that the server is <em>not</em> capable of properly handling requests to full-path URLs. This causes the app to <em>always</em> use hash-based URLs, regardless of the browser's capabilities. In this case the app will assume that there is no server to rely on, giving the app the following qualities:
715
Be aware that <strong>all URLs will be hash-based</strong>, even in browsers which are capable of using HTML5 history.
721
The <code>Y.App</code> instance will handle all routing since there is no server capable of properly routing handling requests.
727
The server is only expected to serve out a static HTML "shell" page with the required JavaScript to instantiate the <code>Y.App</code> instance, which will then render the initial state of the application.
733
This is the best option if there is no guarantee that your app will be served by a capable server. This allows an app to run when hosted on the filesystem or static file server. You should be aware that using hash-based URLs means there will be information loss. The server will <em>not</em> receive the full URL because browsers do not send the fragment-part to the server, that is everything after and including the "#".
737
<strong>Please read</strong> <a href="#progressively-enhanced-vs-client-only-apps">Progressively-enhanced vs. Client-only Apps</a> for more information and best practices.
740
<h3 id="rendering-an-app">Rendering an App</h3>
743
App inherits both its <code>container</code> attribute and <code>render()</code> method from View. Unlike <a href="../view/index.html#rendering-a-view">View's empty <code>render()</code> implementation</a>, App provides a default implementation which appends the <code>activeView</code> (if there is one) to the <code>viewContainer</code> node which itself is appended to the <code>container</code> node.
747
The basic usage of your app's <code>render()</code> method is to call it at least once, usually after you instantiate your app, this ensures the proper DOM structure is setup to handle rendering the app's <a href="#view-management">views</a>.
750
<pre class="code prettyprint">var app = new Y.App();
755
This results in the HTML of the page looking like this:
758
<pre class="code prettyprint"><body class="yui3-app">
760
<div class="yui3-app-views"></div>
761
</body></pre>
765
By default, an app's <code>container</code> node will be the <code><body></code> element and its <code>viewContainer</code> node will be a new <code><div></code>.
769
<strong>Note:</strong> The <code>"yui3-app"</code> and <code>"yui3-app-views"</code> CSS classes are added to the <code>container</code> and <code>viewContainer</code> respectively — this happens when the app is rendered.
772
<h4 id="specifying-container-nodes">Specifying Container Nodes</h4>
775
When constructing a new App instance you can specify values for the app's <code>container</code> and <code>viewContainer</code> attributes, and they can even reference the same node.
778
<pre class="code prettyprint">var app = new Y.App({
779
container : '#wrapper',
780
viewContainer: '#wrapper'
787
Assuming that a <code><div id="wrapper"></code> node already exists on the page, this uses a CSS selector string to reference the node, assigns it to both containers, and results in the following HTML:
790
<pre class="code prettyprint"><div id="wrapper" class="yui3-app yui3-app-views">
792
</div></pre>
796
If you specify a <code>container</code> that is not already within the markup of the page, you'll need to manually append it to an element that is:
799
<pre class="code prettyprint">var app = new Y.App({
800
container: Y.Node.create('<div id="fancy-app" />')
803
app.render().get('container').appendTo('body');</pre>
807
This results in the HTML of the page looking like this:
810
<pre class="code prettyprint"><body>
812
<div id="fancy-app" class="yui3-app">
813
<div class="yui3-app-views"></div>
815
</body></pre>
819
Refer to App's API Docs for more details about <a href="http://yuilibrary.com/yui/docs/api/classes/App.html#attr_container"><code>container</code></a> and <a href="http://yuilibrary.com/yui/docs/api/classes/App.html#attr_viewContainer"><code>viewContainer</code></a> attributes.
822
<h4 id="overriding-render">Overriding <code>render()</code></h4>
825
You may override the <code>render()</code> method to customize how the app renders itself, particularly if you are creating an App subclass.
829
<strong>Note:</strong> You should expect that the <code>viewContainer</code>'s contents will be modified by the app for the purpose of rendering the <code>activeView</code> when it changes; and ideally your <code>render()</code> method should also return <code>this</code> at the end to allow chaining, but that's up to you.
833
The following provides a templates for how you could subclass <code>Y.App</code> and implement a custom <code>render()</code> method while still preserving its default behavior:
836
<pre class="code prettyprint">Y.CustomApp = Y.Base.create('customApp', Y.App, [], {
837
render: function () {
838
// This calls the superclass' (Y.App) implementation of the `render()`
839
// method to preserve the default behavior.
840
Y.CustomApp.superclass.render.apply(this, arguments);
842
// Provide your custom rendering logic here.
844
// Returns this `Y.CustomApp` instance to allow for chaining.
851
Refer to App's API Docs for more details about the <a href="http://yuilibrary.com/yui/docs/api/classes/App.html#method_render"><code>render()</code> method</a>. See <a href="#subclassing">Subclassing</a> for more details on extending <code>Y.App</code>.
854
<h3 id="view-management">View Management</h3>
857
A primary feature of App is its flexible view management, which enables you to declare the primary views of your application and easily switch which one is active. This is very handy for defining your app's top-level "page" views, then switching between them as a user navigates through the application.
860
<h4 id="declaring-views">Declaring Views</h4>
863
The <code>views</code> property of an App class allows you to specify a mapping of view-names to view-metadata that should be registered to your app. This way you can specify information about your app's views — how they should be treated by the app, and how they related to other views — up-front, in a declarative way that is self-documenting.
867
You can setup this views mapping on both App subclasses and instances. Every App instance will receive its own copy of a <code>views</code> object, any <code>views</code> metadata defined at the class-level will be used as defaults and merged with any <code>views</code> specified during instantiation time.
871
The follow example shows the creation of an App subclass, <code>CustomApp</code>, which has a few default views defined, and an instance of <code>CustomApp</code> which defines another view and overrides some of the defaults.
874
<pre class="code prettyprint">// Create a Y.CustomApp class that extends Y.App.
875
Y.CustomApp = Y.Base.create('customApp', Y.App, [], {
876
// Default registered views inherited by all CustomApp instances.
878
home : {preserve: true},
879
users: {preserve: true},
880
user : {parent: 'users'}
884
// Create a CustomApp instance that inherits the defaults and adds to them.
885
var app = new Y.CustomApp({
886
// Additional view metadata to be merged with the defaults.
888
home : {preserve: false},
889
user : {preserve: false},
890
about: {preserve: true}
896
Using the <code>getViewInfo()</code> method, we can see how the <code>views</code> metadata from our <code>CustomView</code> class and instance were merged together.
899
<pre class="code prettyprint">// Overwrote "home"'s default `preserve` value.
900
Y.log(app.getViewInfo('home').preserve); // => false
902
// Added `preserve` to "user" view,
903
// and this did not overwrite the default `parent` value.
904
Y.log(app.getViewInfo('user').parent); // => "home"
905
Y.log(app.getViewInfo('user').preserve); // => false
907
// The specified "about" view was registered.
908
Y.log(app.getViewInfo('about').preserve); // => true</pre>
912
See the <a href="#app-properties">App Properties</a> section above for more details on what metadata can be stored for each view in <code>views</code> mapping.
915
<h4 id="switching-the-active-view">Switching the Active View</h4>
919
When decomposing an application into discrete user-interfaces, it is natural to think of these as different "pages"—with each one serving a particular role and being the main content on the screen. With the App component, changing the main content/user-interface is done by updating an app's <code>activeView</code> attribute via the <code>showView()</code> method.
923
Working in concert with an app's registered <code>views</code>, the <code>showView()</code> method will take a specified view and make it the app's <code>activeView</code>. This view will be "attached" to the app by rendering it inside the app's <code>viewContainer</code> and any custom events fired by the view will bubble to the app. Any previously active view will be "detached" from the app, removed from the DOM, and either preserved for later use or properly destroyed.
927
The following example is the most basic "Hello World" app:
930
<pre class="code prettyprint">// Creates a new App and View instance.
931
var app = new Y.App(),
934
// Overrides the view's `render()` method to render text into its `container`.
935
view.render = function () {
936
this.get('container').set('text', 'Hello World!');
940
// Renders the `app` and `view`, then sets the view as the app's `activeView`.
941
// We have to explicity tell the app to render the view because by default, if
942
// the view instance already exists it won't be rendered automatically.
943
app.render().showView(view, null, {render: true});
945
// Verify that `view` is now the `activeView`, and that the view's `container`
946
// is now rendered within the app's `viewContainer`.
947
Y.log(app.get('activeView') === view); // => true
948
Y.log(app.get('viewContainer').contains(view.get('container'))); // => true</pre>
952
This results in the HTML of the page looking like this:
955
<pre class="code prettyprint"><body class="yui3-app">
957
<div class="yui3-app-views">
958
<div>Hello World!</div>
960
</body></pre>
964
This example app can <em>easily</em> become dynamic and have the ability to say hello to someone by name. By creating a reusable <code>HelloView</code> class the app can dynamically switch between outputting "Hello World!" and "Hello [name]!" where the "name" is a path segment in the URL.
967
<pre class="code prettyprint">// Creates a HelloView which can say hello to someone named, or to the World
968
// if a name is not specified.
969
Y.HelloView = Y.Base.create('helloView', Y.View, [], {
970
render: function () {
971
var name = this.get('name');
972
this.get('container').set('text', 'Hello ' + (name || 'World') + '!');
977
// Creates a new App instance and registers the HelloView.
978
var app = new Y.App({
980
hello: {type: 'HelloView'}
984
// Adds a route handler for "/" to show the HelloView.
985
app.route('/', function (req) {
986
// Sets the `activeView` to a new instance of a `Y.HelloView` by just
987
// passing "hello", the name of the registered view.
988
this.showView('hello');
991
// Adds a route handler for "/:name" to show the HelloView with a `name`.
992
app.route('/:name', function (req) {
993
// The name which we want to say hello to is specified on `req.params`.
994
var name = req.params.name;
996
// Sets the `activeView` to a new instance of a `Y.HelloView`, but here
997
// we are also passing a config object which the new view instance will
998
// be constructed with, and it contains the name which we'll say hello to.
999
this.showView('hello', {name: name});
1002
// Renders the app, then saves a new history entry for "/eric" which will
1003
// dispatch the "/:name" route handler.
1004
app.render().save('/eric');</pre>
1008
This results in the URL being updated to either <code>"/eric"</code> or <code>"/#/eric"</code> depending on whether the browser is capable of HTML5 history, and the HTML of the page looking like this:
1011
<pre class="code prettyprint"><body class="yui3-app">
1013
<div class="yui3-app-views">
1014
<div>Hello eric!</div>
1016
</body></pre>
1019
<h5 id="understanding-showview-options">Understanding <code>showView()</code> Options</h5>
1022
App's <code>showView()</code> method has the following signature:
1025
<pre class="code prettyprint">showView ( view [config] [options] [callback] )</pre>
1029
As seen in the previous usage examples, <code>view</code> can either be a view instance or the string-name of a view defined in the app's <code>views</code> object. The optional <code>config</code> object is used when creating a new view instance. The <code>config</code> object can also be used to update an existing or preserved <code>view</code>'s attributes when <code>options.update</code> is <code>true</code>.
1033
The following is the list of <code>options</code> which affect how the app will switch its <code>activeView</code>:
1037
<dt><code>callback</code></dt>
1040
Optional callback function to call after new <code>activeView</code> is ready to use, the function will be passed a reference to the view.
1044
Specifying a callback function is useful you need access to the view instance which is created as a result of calling <code>showView()</code>. Also, if an app is using transitions, the callback function will be called once the transitions have completed.
1048
<dt><code>prepend</code></dt>
1051
Whether the <code>view</code> should be prepended instead of appended to the app's <code>viewContainer</code> node.
1055
This option is used internally to aid transitions by prepending the new <code>activeView</code> if it has been defined as the <code>parent</code> of the currently active view. This puts the view as the first child of the app's <code>viewContainer</code> node which helps the sliding transitions.
1059
<dt><code>render</code></dt>
1062
Whether the <code>view</code> should be rendered. <strong>Note:</strong> If no value is specified, a view instance will only be rendered if it's newly created by this method.
1066
Sometimes you may need greater control over when a view is rendered. Under certain circumstances you may wish to re-render a preserved view, you can use this option to accomplish this.
1070
<dt><code>transition</code></dt>
1073
Optional transition override. A transition can be specified which will override the default, or <code>false</code> for no transition.
1077
When an app is using transitions, this option allows you to override the default transition that will occur per the app's <code>transitions</code> configuration — enabling finer-grained control over how views transition.
1081
<dt><code>update</code></dt>
1084
Whether an existing view should have its attributes updated by passing the <code>config</code> object to its <code>setAttrs()</code> method. <strong>Note:</strong> This option does not have an effect if the <code>view</code> instance is created as a result of calling this method.
1088
This option would usually be used to update a preserved view with new data and can be used in conjunction with the <code>render</code> option to force a view to update and re-render.
1094
Refer to App's API docs</a> for more details about the <a href="http://yuilibrary.com/yui/docs/api/classes/App.html#method_showView"><code>showView()</code> method</a>.
1097
<h3 id="navigating-between-pages">Navigating Between "Pages"</h3>
1100
A key feature of <code>Y.App</code> is its robust URL navigation management. You can simply use standard HTML links within your app and when the user clicks a link, <code>Y.App</code> will handle it if there’s a matching route for that URL. With the <a href="#configuring-navigation-behavior">navigation-related config options</a> you have full control over your app's navigation behavior and experience, plus your app will automatically use the best available navigation method based on these settings, the browser’s capabilities, and the actions of the user.
1104
This enables an app fulfill a "page request" by using data it already has stored in models or loading new data, then composing and showing a view which represents the app's current state for this URL — all without requiring a full page load.
1107
<h4 id="programmatic-navigation">Programmatic navigation</h4>
1110
Beyond handling navigation via link clicks, <code>Y.App</code> also exposes a programmatic way to navigate the user though your app via the <code>navigate()</code> method.
1114
App's <code>navigate()</code> method implements a higher level concept of "browsing" over the <code>save()</code> and <code>replace()</code> methods. It will manage a user's navigation history like a browser, and is the recommended method to use when programmatically navigating the user to URLs within your app.
1118
The <code>navigate()</code> method will do the right thing (what the browser would do) when navigating the user to the same URL they are currently on — it will replace the history entry — or to an in-page fragment identifier — which only when configured will navigate. The following demonstrates some of these behaviors:
1121
<pre class="code prettyprint">var app = new Y.App();
1123
app.route('*', function (req, res, next) {
1124
// Handle all URLs.
1127
// Save a new history entry for "/", or replaces the current entry if we're
1128
// already on "/".
1129
app.navigate('/'); // => true
1131
// Does not navigate even though there's a matching route handler.
1132
app.navigate('#top'); // => false
1134
// Enable navigation on hash-only changes to the URL.
1135
app.set('navigateOnHash', true);
1137
// Does navigate because `navigateOnHash` was enabled.
1138
app.navigate('#top'); // => true</pre>
1142
Refer to App's API Docs for more details about the <a href="http://yuilibrary.com/yui/docs/api/classes/App.html#method_navigate"><code>navigate()</code> method</a>.
1145
<h4 id="configuring-navigation-behavior">Configuring Navigation Behavior</h4>
1148
The navigation features of <code>Y.App</code> are built on the <a href="http://yuilibrary.com/yui/docs/api/classes/PjaxBase.html">base pjax functionality</a>. This is what enables users to navigate to the different sections or "pages" of an app while avoiding full page loads.
1152
The following are configuration attributes which define an app’s navigation behavior:
1160
<th>Default Value</th>
1161
<th>Description</th>
1166
<td><code>linkSelector</code></td>
1167
<td><code>Y.PjaxBase</code></td>
1168
<td><code>"a"</code></td>
1171
CSS selector string used to filter link click events so that only the links which match it will have the enhanced-navigation behavior of pjax applied.
1175
When a link is clicked and that link matches this selector, navigating to the link's <code>href</code> URL using the enhanced, pjax, behavior will be attempted; and the browser's default way to navigate to new pages will be the fallback.
1179
By default this selector will match <em>all</em> links on the page.
1185
<td><code>navigateOnHash</code></td>
1186
<td><code>Y.PjaxBase</code></td>
1187
<td><code>false</code></td>
1190
Whether navigating to a hash-fragment identifier on the current page should be enhanced and cause the <code>navigate</code> event to fire.
1194
By default Pjax allows the browser to perform its default action when a user is navigating within a page by clicking in-page links (e.g. <code><a href="#top">Top of page</a></code>) and does not attempt to interfere or enhance in-page navigation.
1200
<td><code>scrollToTop</code></td>
1201
<td><code>Y.PjaxBase</code></td>
1202
<td><code>true</code></td>
1205
Whether the page should be scrolled to the top after navigating to a URL.
1209
When the user clicks the browser's back button, the previous scroll position will be maintained.
1215
<td><code>serverRouting</code></td>
1216
<td><code>Y.App.Base</code></td>
1217
<td><code>undefined</code></td>
1220
Whether or not this application's server is capable of properly routing all requests and rendering the initial state in the HTML responses.
1224
See <a href="#app-attributes">App Attributes</a> and <a href="#routing-coordination-with-server">Routing Coordination with Server</a> for more details.
1231
<h4 id="navigate-event"><code>navigate</code> Event</h4>
1234
When the user is navigating to a URL for which the app has a route handler, the <code>navigate</code> event will fire. The default action of this event updates the browser’s address bar to reflect the new URL, causing the app to dispatch to the matching route handlers.
1238
Listening to your app's <code>navigate</code> event is a useful way to indicate to the user that something is loading while they wait for the app to fully handle the new URL, possibly loading data from a remote server.
1241
<pre class="code prettyprint">var app = new Y.App({
1246
users: new Y.ModelList()
1249
app.route('/users/', function () {
1250
var users = app.get('users');
1252
// Load users data from a remote server.
1253
users.load(function () {
1254
app.showView('users', {users: users});
1256
// Removes the "loading" class from the app's `container` node.
1257
app.get('container').removeClass('loading');
1261
// Listen for the app's `navigate` event.
1262
app.on('navigate', function (e) {
1263
// Adds the "loading" class to the app's `container` node.
1264
app.get('container').addClass('loading');
1267
// Navigate the user to "/users/".
1268
app.navigate('/users/');</pre>
1272
Refer to App's API Docs for more details about the <a href="http://yuilibrary.com/yui/docs/api/classes/App.html#event_navigate"><code>navigate</code> event</a>.
1275
<h2 id="extending-yapp">Extending <code>Y.App</code></h2>
1278
The <code>Y.App</code> class is intended to be mutable insofar as being the host for <em>all</em> App-component features, whereas <code>Y.App.Base</code> is intended to remain pure and just host the basic set of features. This allows for two different ways to extend the functionality of <code>Y.App</code>: <a href="#mixing-in-features">mixing-in features</a>, and <a href="#subclassing">subclassing</a>.
1281
<h3 id="mixing-in-features">Mixing-In Features</h3>
1284
Additional class extensions can be automatically mixed-into <code>Y.App</code>, doing so will dynamically extend the functionality of the App class making these new features available to all of its instances and subclasses. The <a href="#yapptransitions"><code>Y.App.Transitions</code></a> class extension, provided by the <code>app-transitions</code> module, uses this pattern to add transitions support to <code>Y.App</code>.
1287
<pre class="code prettyprint">// Creates the namespace for the transitions class extension and assigns a
1288
// simple constructor function to it.
1289
Y.App.Transitions = function () {};
1291
// Defines the `transitions` attribute with a default value of `false`. This
1292
// makes the view transitions an opt-in feature.
1293
Y.App.Transitions.ATTRS = {
1294
transitions: {value: false}
1297
// This defines the prototype of the transitions class extension, the actual
1298
// implementation has been left out for the sake of simplicity.
1299
Y.App.Transitions.prototype = {
1301
// The implementation of the transition features would be here.
1305
// Here the transitions class extension is being applied automatically by
1306
// mixing itself into the `Y.App` class.
1307
Y.Base.mix(Y.App, [Y.App.Transitions]);</pre>
1311
When this module is included in the YUI instance, the transitions support for App can be used by simply toggling it on:
1314
<pre class="code prettyprint">YUI().use('app-base', 'app-transitions', function (Y) {
1315
var app = new Y.App({transitions: true});
1320
When writing your own class extensions to add features to <code>Y.App</code>, feel free to add them to App's namespace (e.g., <code>Y.App.SomeNewFeature</code>), and be sure to follow these two rules:
1326
The addition functionality should be <strong>disabled by default</strong>. The API for the class extensions should provide some way for the user to <em>opt-in</em> to using the features it adds.
1330
The <code>Y.App.Transitions</code> class extension does this be requiring a "truthy" value for the <code>transitions</code> attribute. By default the value will be <code>false</code>, making this an opt-in feature.
1336
Be courteous to the other App component class extensions, since they all share the same <code>prototype</code> be careful not to unintentionally overwrite other properties or methods.
1341
<h3 id="subclassing">Subclassing</h3>
1344
Creating class extensions for <a href="#mixing-in-features">mixing-in features</a> to <code>Y.App</code> is a great way to extend its functionality in a reusable way while not changing how you <a href="#instantiating-app">Instantiate an App</a>; but might find it more useful to extend the <code>Y.App</code> class to create a subclass customized to your specific needs.
1348
Use the <code>Y.Base.create()</code> method to extend <code>Y.App</code> and add or override prototype and static members and attributes. You may also optionally specify one or more <a href="../base/index.html#extensions">class extensions</a> to mix into your new class.
1351
<pre class="code prettyprint">// Create a Y.CustomApp class that extends Y.App.
1352
Y.CustomApp = Y.Base.create('customApp', Y.App, [], {
1353
// Add or override prototype properties and methods here.
1355
// Add static properties and methods here.
1358
// Add or override default attributes here.
1364
One benefit of extending <code>Y.App</code> is that you can easily add default views, routes, and route handlers to your custom App class, and they'll be shared by all instances of that class unless overridden at the instance level:
1367
<pre class="code prettyprint">// Create a Y.CustomApp class that extends Y.App.
1368
Y.CustomApp = Y.Base.create('customApp', Y.App, [], {
1369
// Default registered views inherited by all CustomApp instances.
1371
home : {preserve: true},
1372
users: {preserve: true},
1373
user : {parent: 'users'}
1376
// Default route handlers inherited by all CustomApp instances.
1378
handleHome: function (req) {
1379
// Handle the "/" route here.
1382
handleUsers: function (req) {
1383
// Handle the "/users/" route here.
1386
handleUser: function (req) {
1387
// Handle the "/users/:name/" route here.
1391
// Share these routes with all CustomApp instances.
1394
{path: '/', callback: 'handleHome'},
1395
{path: '/users/', callback: 'handleUsers'}
1396
{path: '/users/:name/', callback: 'handleUser'}
1402
// Create a CustomApp instance that inherits the defaults and adds to them.
1403
var app = new Y.CustomApp({
1404
// Register an additional view. The `home`, `users`, and `user` views will
1405
// also be inherited.
1407
about: {preserve: true}
1411
// Add a route and route handler.
1412
app.route('/about/', function (req) {
1413
// Handle the "/about/" route here.
1418
Now all instances of <code>Y.CustomApp</code> will inherit all the custom defaults and can add to or override them. The <code>app</code> instance created here will handle the <code>"/"</code>, <code>"/users/"</code>, and <code>"/users/:name/"</code> routes in addition to its own <code>"/about/"</code> route.
1422
Before you subclass <code>Y.App</code>, you should refer to <a href="http://yuilibrary.com/yui/docs/api/modules/app-base.html">App's API docs</a> to become familiar with its public and protected properties and methods.
1425
<h2 id="app-extensions">App Extensions</h2>
1427
<h3 id="yapptransitions"><code>Y.App.Transitions</code></h3>
1430
The <a href="http://yuilibrary.com/yui/docs/api/classes/App.Transitions.html">Transitions</a> extension provides view transitions for apps in browsers which support native CSS3 transitions. View transitions visually enhance the change from one "page" to the next that is both pleasant to the user and helps to communicate a hierarchy between sections of an application.
1433
<h4 class="no-toc">Enabling Transitions</h4>
1436
Enabling transitions for an app just requires <em>opting-in</em>. The following will create a new <code>Y.App</code> instance with the default transitions enabled:
1439
<pre class="code prettyprint">var app = new Y.App({transitions: true});</pre>
1443
With transitions enabled for an app, anytime the app's <code>activeView</code> changes, there will be a visual transition from the old to the new active view. How an app's <code>views</code> are configured effects which transition will be used, e.g. when changing between views which have a hierarchical relationship a sliding transition will be used.
1446
<h4 class="no-toc">Types of <code>activeView</code> Changes</h4>
1449
The following are the types of <code>activeView</code> changes for which transitions can be defined that correspond to the relationship between the new and old <code>activeView</code>:
1453
<dt><code>navigate</code></dt>
1456
The default transition to use when changing the <code>activeView</code> of the application. This will be <strong><code>"fade"</code></strong> by default.
1460
<dt><code>toChild</code></dt>
1463
The transition to use when the new <code>activeView</code> is configured as a child of the previously active view via its <code>parent</code> property as defined in this app's <code>views</code>. This will be <strong><code>"slideLeft"</code></strong> by default.
1467
<dt><code>toParent</code></dt>
1470
The transition to use when the new <code>activeView</code> is configured as the <code>parent</code> of the previously active view as defined in this app's <code>views</code>. This will be <strong><code>"slideRight"</code></strong> by default.
1475
<h4 class="no-toc">Overriding Default Transitions</h4>
1478
The default transitions can be overridden in the following ways:
1484
Overriding the <a href="http://yuilibrary.com/yui/docs/api/classes/App.html#property_transitions"><code>transitions</code> property</a> which is used as the default transitions for all <code>Y.App</code> instances.
1490
Specifying a <code>transitions</code> configuration object when instantiating a new app, which sets the app's <a href="http://yuilibrary.com/yui/docs/api/classes/App.html#attr_transitions"><code>transitions</code> attribute</a>.
1496
Specifying a <code>transition</code> when calling the <a href="http://yuilibrary.com/yui/docs/api/classes/App.html#method_showView"><code>showView()</code> method</a>.
1502
The following example will override which transitions should be used by default, and specifically set the <code>transition</code> option on certain calls to <code>showView()</code>.
1505
<pre class="code prettyprint">var app = new Y.App({
1506
// The app's three views and their relationships between one another.
1510
contact: {parent: 'about'},
1511
team : {parent: 'about'}
1514
// Overrides the default transitions types all to "fade" which will
1515
// cross-fade between `activeView` changes.
1517
navigate: 'fade',
1518
toChild : 'fade',
1519
toParent: 'fade'
1522
// The app's `team` model list for use by the "team" view.
1523
team: new Y.ModelList().reset([
1524
{name: 'Eric Ferraiuolo'},
1525
{name: 'Ryan Grove'}
1529
app.route('/', function () {
1530
// Will transition via "fade".
1531
app.showView('home');
1534
app.route('/about/', function () {
1535
// Will transition via "fade", even though we maybe coming from a child
1536
// view (i.e. "contact" or "team").
1537
app.showView('about');
1540
app.route('/about/contact/', function () {
1541
// Will transition via "fade", even though we maybe coming from the parent
1542
// "about" view.
1543
app.showView('contact');
1546
app.route('/about/team/', function () {
1547
// Shows the "team" view, passing it the app's `team` model list, and
1548
// overrides the `transition` options so no visual transitions will occur.
1549
app.showView('team', {team: this.get('team')}, {transition: false});
1552
app.render().dispatch();</pre>
1555
<h4 class="no-toc">Transition-Aiding CSS</h4>
1558
Some structural CSS is required to setup an app's <code>container</code> and <code>viewContainer</code> nodes so the app's views transition properly. While an app's views are transitioning, the CSS class: <strong><code>yui3-app-transitioning</code></strong> will be added to the app's <code>container</code> node.
1562
<strong>Note:</strong> While transitioning, the app's <code>viewContainer</code> node will have its <code>overflow-x</code> set to <code>hidden</code>. This causes its margins to <em>not collapse</em> with its child nodes. To compensate for this, it is best to not style your views with margins.
1565
<h2 id="best-practices">Best Practices</h2>
1567
<h3 id="progressively-enhanced-vs-client-only-apps">Progressively-enhanced vs. Client-only Apps</h3>
1570
It's important to understand the difference between the preferred approach of developing an app using a progressive enhancement strategy vs. creating a client side-only app, and when it might be appropriate to do so. As discussed in the <a href="#routing-coordination-with-server">Routing Coordination with Server</a>, <code>Y.App</code> provides the tools and is flexible enough implement an app using either strategy, but <strong>there are drawbacks to client-only applications</strong>.
1574
The following sections build on <a href="../router/index.html#best-practices">Router's Best Practices</a>, all of which apply, by looking at things from a higher level, application perspective:
1577
<h4 id="full-path-vs-hash-based-urls">Full-path vs. Hash-based URLs</h4>
1580
Before making a decision to use hash-based URLs in your application, you should <strong>be aware of their drawbacks</strong>.
1584
A client-only app will use hash-based URLs instead of the standard, full-path URLs. When the server receives a request for a hash-based URL everything after and including the fragment identifier ("#") is lost. This means your application will have to rely on the JavaScript to finish fulfilling the request for the user.
1588
The following shows how this information loss manifest itself:
1591
<pre class="code">Browser URL: http://example.com/#/foo/bar/
1592
Request URL: http://example.com/</pre>
1596
The request URL that the server will see is missing the entire path, this means every URL in your application looks to the server as if it's the same page! To prevent link rot in your application, you'll have to support the hash-based variation of your URLs indefinitely.
1600
Ideally you should prefer full-path URLs (e.g., http://example.com/foo/bar/) for your application and be able to handle full page loads for browsers which are not capable of using HTML5 history. This requires a server capable of routing requests and rendering the initial state of the application in the HTML responses. This is the main idea behind a progressive enhancement development strategy — providing a better experience for more capable browsers/devices.
1603
<h4 id="performance-and-seo">Performance and SEO</h4>
1606
Client-only apps suffer in more places than just their URLs. There are <em>horrible side-effects</em> of using hash-based URLs: degradation in performance of rendering the app's initial state, and lack of SEO.
1610
It is faster to render the initial state of an app on the server before delegating control to the client-side JavaScript. But in order to achieve this, the server must be capable of routing requests and rendering this initial state. This means your application needs to be using full-path URLs.
1614
To render the initial state in a client-only app, the server has to send over the HTML "shell" page, which then makes more HTTP requests to get the JavaScript. Once the JavaScript has been downloaded and parsed, it can execute and construct the <code>Y.App</code> instance. The app now needs to fetch data from the server (yet another HTTP request), and then it can display the initial state. All while the user is staring at a blank page — which is a horrible user experience, especially on a mobile device with a slower connection.
1618
Optimizing your app to be indexed by search engines is also relates to this. SEO requires that your app uses full-path URLs so the server can route requests and render the initial state. The basic functions of your app which you want to be indexable should work without JavaScript.
1621
<h4 id="when-client-only-apps-are-appropriate">When Client-only Apps are Appropriate</h4>
1624
Given all the drawbacks of client-only apps, there's one major advantage: <strong>they don't rely on the server</strong>. If your app needs to run off the filesystem, or be deployed to a "dumb" static file server, then this might be your only option.
1628
Developing a client-only app using <code>Y.App</code> still gives you nice (but hash-based) URLs that are bookmarkable, browser back/forward button support, and view management.
1632
<strong>Please make sure you understand the issues with hash-based URLs and their side-effects.</strong> Consider developing your application using a progressive enhancement strategy, it will be worth the extra effort in the long run.
1635
<h3 id="flow-control">Flow Control</h3>
1638
When developing an app, it's important to have a clear understanding about how the various components are working together. The use of consistent patterns for information sharing, and execution of operations aid in maintaining a separation of concerns which becomes ever more crucial as the size of the app and team increases.
1642
Restricting the flow of information to a single direction creates a "one-way street" which enforces a strict separation of concerns and divides control over execution throughout an application. This strategy can be implemented by leveraging YUI's powerful custom event infrastructure. All of the components of App Framework are <code>Y.Base</code>-based, and therefore are primed to be both publishers and subscribers of an app's custom events.
1646
The following example app demonstrates how to wire up the components of an application using custom events to achieve the one-way flow of information and divide control by maintaining a strict separation of concerns:
1649
<pre class="code prettyprint">// Create the `UserView`.
1650
Y.UserView = Y.Base.create('userView', Y.View, [], {
1651
template: '<p>{name}</p>' +
1652
'<label for="name-input">Name:</label>' +
1653
'<input id="name-input" type="text" value="{name}" />' +
1654
'<button>Save</button>',
1656
// Listens for DOM events from the user and translates them into application
1657
// events; e.g., "click" -> "save".
1659
'button': {click: 'save'}
1662
initializer: function () {
1663
// Listens for the user model to change, and re-renders the view.
1664
this.get('user').after('change', this.render, this);
1667
render: function () {
1668
var user = this.get('user'),
1669
content = Y.Lang.sub(this.template, {name: user.get('name')});
1671
this.get('container').setContent(content);
1675
// This view doesn't actually do the saving, instead, it is translating the
1676
// user's intent (they click the Save button) to an application-level event.
1677
// This way control is given to the app to respond to this action.
1679
var user = this.get('user'),
1680
name = this.get('container').one('input').get('value');
1682
// Fires the save event and passes along the needed information. When
1683
// this is the app's `activeView` this event will bubble to the app.
1684
this.fire('save', {
1691
// Create the app and define the app's `views`, and assign a new `Model`
1692
// instance as an ad-hoc attribute to the app.
1693
var app = new Y.App({
1696
type : 'UserView',
1704
// The app listens for the `UserView` to fire its `save` event. The only will
1705
// only be notified if the view is the app's current `activeView`.
1706
app.on('userView:save', function (e) {
1707
// The app has the control to execute update the model and execute the save
1708
// operation. Updating the model will cause the view to re-render.
1709
e.user.set('name', e.name).save();
1712
// Renders the app and set's the `user` view and the `activeView`, passing it
1713
// the user model.
1714
app.render().showView('user', {user: app.get('user')});</pre>
1718
The main thing to note about the above example is that the <code>UserView</code> is <em>not</em> updating its <code>user</code> model directly, instead it is translating the user's intent via DOM events into application-level events. This gives control back to the app so it can decide how best to proceed. The result is a flow of information and control that moves in one direction and in a continuous loop.
1721
<h3 id="preserved-views">Preserved Views</h3>
1724
An app's <code>views</code> can be defined so that a single instance of a particular view is preserved and can be reused. When a view is defined with its <code>preserve</code> property set to <code>true</code>, the same view instance will be used each time the app's <code>showView()</code> method is called to set it as the app's <code>activeView</code>.
1728
Preserved views should be used in situations where the contents of the view might not change and that view will be displayed often. They are especially useful if its contents have a complex DOM structure that would be costly to create each time the view was to be shown.
1732
Imagine a simple app that displays user information in two views: a <code>users</code> view that lists all the users, and a <code>user</code> view that displays the details of a single user. If the set of all users in this application won't change often, then it would be a good idea to make the <code>users</code> view a preserved view. That way it only has to be constructed once, and the same view instance can be shown many times. Whereas the contents of the <code>user</code> view are always going to change depending on which user is being displayed, making it <em>not</em> suitable to preserve.
1736
The following example demonstrates how this hypothetical users app would define its two views:
1739
<pre class="code prettyprint">// Create the `UsersView`.
1740
Y.UsersView = Y.Base.create('usersView', Y.View, [] {
1741
// Implementation would be here...
1744
// Create the `UserView`.
1745
Y.UserView = Y.Base.create('userView', Y.View, [] {
1746
// Implementation would be here...
1749
// Create the app and define its two views.
1750
var app = new Y.App({
1752
// Only one `users` view instance will be created and it will be
1753
// preserved for reuse.
1756
type : 'UsersView'
1759
// A new `user` view instance will be created every time.
1761
type : 'UserView',
1762
parent: 'users'
1769
Be cautious about the number of preserved views you have in your application. Their DOM structures are maintained even when they are not in the visible portion of the page's DOM, this means the more preserved views, the more memory your application will consume. On mobile devices with very limited memory and no swap space, consuming too much memory in your app can cause the browser to crash.
1774
<h2 id="known-limitations">Known Limitations</h2>
1779
<strong>When multiple App instances are on the page, only one can manage the URL and navigation.</strong> All of the app instances can have route handlers, but only one should have its <code>linkSelector</code> attribute set to a non-falsy value. See <a href="#configuring-navigation-behavior">Configuring Navigation Behavior</a> for more details.
1785
<strong>Transitions are only supported in WebKit and Firefox browsers which also support CSS3 transitions.</strong> It is intended to only support transitions in browser which have native CSS3 transitions, and YUI's <a href="../transition/index.html">Transition</a> component only supports WebKit and Firefox.
1791
App relies heavily on Router which has some know limitations in Internet Explorer 9 and lower, and Android 2.x. See <a href="../router/index.html#known-limitations">Router's Known Limitations</a> for more details.
1797
<div class="yui3-u-1-4">
1798
<div class="sidebar">
1800
<div id="toc" class="sidebox">
1802
<h2 class="no-toc">Table of Contents</h2>
1808
<a href="#getting-started">Getting Started</a>
1811
<a href="#components-of-the-app-framework">Components of the App Framework</a>
1814
<a href="#app-component">App Component</a>
1817
<a href="#using-app">Using App</a>
1820
<a href="#instantiating-app">Instantiating App</a>
1823
<a href="#config-properties">Config Properties</a>
1828
<a href="#app-properties">App Properties</a>
1831
<a href="#app-attributes">App Attributes</a>
1834
<a href="#routing-coordination-with-server">Routing Coordination with Server</a>
1837
<a href="#urls-based-on-browser-capabilities">URLs Based on Browser Capabilities</a>
1840
<a href="#full-path-urls-only">Full-path URLs Only</a>
1843
<a href="#hash-based-urls-only">Hash-based URLs Only</a>
1848
<a href="#rendering-an-app">Rendering an App</a>
1851
<a href="#specifying-container-nodes">Specifying Container Nodes</a>
1854
<a href="#overriding-render">Overriding <code>render()</code></a>
1859
<a href="#view-management">View Management</a>
1862
<a href="#declaring-views">Declaring Views</a>
1865
<a href="#switching-the-active-view">Switching the Active View</a>
1868
<a href="#understanding-showview-options">Understanding <code>showView()</code> Options</a>
1875
<a href="#navigating-between-pages">Navigating Between "Pages"</a>
1878
<a href="#programmatic-navigation">Programmatic navigation</a>
1881
<a href="#configuring-navigation-behavior">Configuring Navigation Behavior</a>
1884
<a href="#navigate-event"><code>navigate</code> Event</a>
1891
<a href="#extending-yapp">Extending <code>Y.App</code></a>
1894
<a href="#mixing-in-features">Mixing-In Features</a>
1897
<a href="#subclassing">Subclassing</a>
1902
<a href="#app-extensions">App Extensions</a>
1905
<a href="#yapptransitions"><code>Y.App.Transitions</code></a>
1910
<a href="#best-practices">Best Practices</a>
1913
<a href="#progressively-enhanced-vs-client-only-apps">Progressively-enhanced vs. Client-only Apps</a>
1916
<a href="#full-path-vs-hash-based-urls">Full-path vs. Hash-based URLs</a>
1919
<a href="#performance-and-seo">Performance and SEO</a>
1922
<a href="#when-client-only-apps-are-appropriate">When Client-only Apps are Appropriate</a>
1927
<a href="#flow-control">Flow Control</a>
1930
<a href="#preserved-views">Preserved Views</a>
1935
<a href="#known-limitations">Known Limitations</a>
1943
<div class="sidebox">
1945
<h2 class="no-toc">Examples</h2>
1949
<ul class="examples">
1952
<li data-description="A basic todo list built with the Model, Model List, and View components.">
1953
<a href="app-todo.html">Todo List</a>
1958
<li data-description="An application to browse through the contributors of a GitHub project.">
1959
<a href="app-contributors.html">GitHub Contributors</a>
1974
<script src="../assets/vendor/prettify/prettify-min.js"></script>
1975
<script>prettyPrint();</script>