UNPKG

can

Version:

MIT-licensed, client-side, JavaScript framework that makes building rich web applications easy.

631 lines (473 loc) 19.1 kB
<!DOCTYPE html> <!--#################################################################### THIS IS A GENERATED FILE -- ANY CHANGES MADE WILL BE OVERWRITTEN INSTEAD CHANGE: source: [object Object] @page guides/pmo ######################################################################## --> <html lang="en"> <head> <meta charset="utf-8"> <title>CanJS - Place My Order Guide</title> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <link rel="stylesheet" type="text/css" href="../static/bundles/bit-docs-site/static.css"> <link rel="shortcut icon" sizes="16x16 24x24 32x32 48x48 64x64" href="/docs/images/canjs_favicon.ico"> <link rel="apple-touch-icon" sizes="57x57" href="../../docs/images/canjs_favicon_57x57.png"> <link rel="apple-touch-icon-precomposed" sizes="57x57" href="../../docs/images/canjs_favicon_57x57.png"> <link rel="apple-touch-icon" sizes="72x72" href="../../docs/images/canjs_favicon_72x72.png"> <link rel="apple-touch-icon" sizes="114x114" href="../../docs/images/canjs_favicon_114x114.png"> <link rel="apple-touch-icon" sizes="120x120" href="../../docs/images/canjs_favicon_128x128.png"> <link rel="apple-touch-icon" sizes="144x144" href="../../docs/images/canjs_favicon_144x144.png"> <link rel="apple-touch-icon" sizes="152x152" href="../../docs/images/canjs_favicon_152x152.png"> <meta content="yes" name="apple-mobile-web-app-capable"> <meta name="apple-mobile-web-app-status-bar-style" content="white-translucent"> <script> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-2302003-11', 'auto'); ga('send', 'pageview'); </script> </head> <body> <input type="checkbox" id="nav-trigger" class="nav-trigger"/> <label for="nav-trigger">Menu</label> <div id="everything"> <div id="left" class="column"> <div class="top-left"> <div class="brand"> <div class="logo"> <a href="../../index.html" alt="CanJS"></a> <div class="dropdown project-dropdown"> <a href="https://donejs.com/">DoneJS</a> <a href="http://stealjs.com/">StealJS</a> <a href="http://jquerypp.com/">jQuery ++</a> <a href="https://funcunit.com/">FuncUnit</a> <a href="http://documentjs.com/">DocumentJS</a> </div> </div> <div class="version"> <div class="version-number"> 3.0.0 </div> <div class="dropdown version-dropdown"> <a href="https://v2.canjs.com">2.3.27</a> </div> </div> </div> <div class="search-bar"> <p> &nbsp; </p> </div> </div> <div class="bottom-left"> <div class="social-side-container"> <ul class="social-side"> <li> <a class="header-mobile github" href="https://github.com/canjs/canjs" target="_blank"><img class="social-icon-small" src="../../docs/images/github.png">Github</a> </li> <li> <a class="header-mobile twitter" href="https://twitter.com/canjs" target="_blank"><img class="social-icon-small" src="../../docs/images/twitter.png">Twitter</a> </li> </ul> <ul class="social-side"> <li> <a class="header-mobile" href="https://gitter.im/canjs/canjs" target="_blank">Chat</a> </li> <li> <a class="header-mobile" href="http://forums.donejs.com/c/canjs" target="_blank">Forum</a> </li> </ul> </div> <ul> <li class=" "> <a class="page" href="pmo/Components.html" title=""> Components </a> </li> <li class=" "> <a class="page" href="pmo/ApplicationDesign.html" title=""> Application Design </a> </li> <li class=" "> <a class="page" href="../pmo/Setup.html" title=""> Setup </a> </li> <li class=" "> <a class="page" href="pmo/Constructors.html" title=""> Constructors </a> </li> <li class=" "> <a class="page" href="pmo/TheDefinePlugin.html" title=""> The Define Plugin </a> </li> <li class=" "> <a class="page" href="pmo/StacheTemplates.html" title=""> Stache Templates </a> </li> <li class=" "> <a class="page" href="pmo/AppStateAndRouting.html" title=""> App State and Routing </a> </li> <li class=" "> <a class="page" href="pmo/Observables.html" title=""> Observables </a> </li> <li class=" "> <a class="page" href="pmo/ViewModels.html" title=""> View Models </a> </li> <li class=" "> <a class="page" href="pmo/DataModelsAndFixtures.html" title=""> Data Models and Fixtures </a> </li> <li class=" "> <a class="page" href="pmo/LoadingStates.html" title=""> Loading States </a> </li> <li class=" "> <a class="page" href="pmo/EventHandling.html" title=""> Event Handling </a> </li> <li class=" "> <a class="page" href="pmo/WebServiceCommunication.html" title=""> Web Service Communication </a> </li> <li class=" "> <a class="page" href="pmo/Recap.html" title=""> Recap </a> </li> </ul> </div> </div> <div id="right" class="column"> <div class="top-right"> <div class="top-right-top"> <ul class="top-right-bitovi"> <li class="dropdown"> <a href="http://bitovi.com" class="bitovi icon-bits">Bitovi</a> <ul class="dropdown-menu"> <li><a href="http://bitovi.com">Bitovi.com</a></li> <li><a href="http://bitovi.com/blog/">Blog</a></li> <li><a href="http://bitovi.com/consulting/">Consulting</a></li> <li><a href="http://bitovi.com/training/">Training</a></li> <li><a href="http://bitovi.com/open-source/">Open Source</a></li> </ul> </li> </ul> <div class="brand"> <div class="logo"> <a href="../../index.html" alt="CanJS"></a> </div> </div> <ul class="top-right-links"> <li> <a href="https://gitter.im/canjs/canjs">Chat</a> </li> <li> <a href="http://forums.donejs.com/c/canjs">Forum</a> </li> <li> <a class="github-button nav-social" href="https://github.com/canjs/canjs" data-count-href="/canjs/canjs/stargazers" data-count-api="/repos/canjs/canjs#stargazers_count">Star</a> </li> <li> <a href="https://twitter.com/canjs" class="twitter-follow-button nav-social" data-show-count="true" data-show-screen-name="false">Follow @canjs</a><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script> </li> </ul> </div> <div class="breadcrumb"> <li><a href="pmo.html">Place My Order Guide</a></li> <li class="breadcrumb-dropdown">/ <a> On this page</a> <ul class="on-this-page"></ul> </li> <div class="nav-toggle" title="Back to top"></div> </div> </div> <div class="bottom-right"> <article> <section class="title"> <div class="page-type"> <h1>Place My Order Guide</h1> <div>page</div> </div> <section class="description"> </section> </section> <section class="on-this-page-table"> </section> <section class="title-footer"> <ul class="title-links"> <!-- <li><a href="#">docco</a></li> --> <li><a href="//github.com/canjs/canjs/tree/v3.0.0/docs/can-guides/experiment/pmo/tutorial.md">source</a></li> <!-- <li><a href="#">download</a></li> --> <!-- <li><a href="#">tests</a></li> --> </ul> </section> <section class="body"> <div class="getting-started"> <p><em>Better Apps, Faster</em></p> <p>CanJS is a lightweight, modern JavaScript <a href="https://en.wikipedia.org/wiki/Model_View_ViewModel" target="_blank">MVVM</a> framework that’s fast and easy to use, while remaining robust and extensible enough to power some of the most trafficked websites in the world. This guide will walk you through an analysis of a small e-commerce app built with CanJS called <strong>Place My Order</strong>. In each relevant section, we’ll give you some code to play with so you will have hands on experience working with CanJS.</p> <p><img src="../can/guides/images/application-design/Home.png" alt="place-my-order.com home page" /></p> <p>For a version of this guide that walks through testing, documenting, building, and deploying the same application, checkout <a href="http://donejs.com/place-my-order.html">DoneJS's In Depth Guide</a>. This guide focuses more on the CanJS parts.</p> <h2>The Basics</h2> <p>Every CanJS application contains:</p> <ul> <li><a href="#observables">Observables</a>,</li> <li><a href="#models">Models</a>,</li> <li><a href="#view-models">ViewModels</a></li> <li><a href="#views">Views</a>,</li> <li><a href="#custom_elements">Custom Elements</a>, and</li> <li><a href="#routing">Routing with an AppViewModel</a></li> </ul> <p><a name="observables"></a></p> <h3>Observables</h3> <p>Observable objects provide a way for you to make changes to data and listen to those changes. Observables such as <a href="../docs/can.List.html">can.List</a>, <a href="../docs/can.Map.html">can.Map</a>, and <a href="../docs/can.compute.html">can.compute</a> provide the foundation for models, view-models, view bindings, and even routing in your app. <a href="../docs/can.compute.html">can.compute</a> is able to combine observable values into new observable values.</p> <p><a href="http://justinbmeyer.jsbin.com/koqaxe/edit?js,console">Example: Creating a derived value from source observables.</a></p> <pre><code>var info = can.compute(function(){ return person.attr(&quot;first&quot;)+&quot; &quot;+person.attr(&quot;last&quot;)+ &quot; likes &quot;+ hobbies.join(&quot;, &quot;)+&quot;.&quot;; }); </code></pre> <p>The <a href="../docs/can.Map.prototype.define.html">define plugin</a> allows you to define rich property behaviors on custom Map types.</p> <p><a href="http://justinbmeyer.jsbin.com/wuwifaf/edit?js,console">Example: Creating a derived value as part of a custom type.</a></p> <pre><code>Person = can.Map.extend({ define: { fullName: { get: function(){ return this.attr(&quot;first&quot;)+&quot; &quot;+this.attr(&quot;last&quot;); } } } }); </code></pre> <p><a name="models"></a></p> <h3>Models</h3> <p>Models let you get and modify data from the server. They also hydrate raw, serialized service data into more useful (and observable) typed data in the client. <a href="../docs/can.Model.html">can.Model</a> makes it easy to connect to restful services and perform Create, Retrieve, Update, and Delete (CRUD) operations.</p> <p>For applications requiring real-time, high performance, restful data connections you should check out <a href="http://connect.canjs.com/">can-connect</a>.</p> <p><a href="http://justinbmeyer.jsbin.com/codubev/edit?js,console">Example: Simulate a restful service and create, update, and delete its data.</a></p> <pre><code>// Create an order. var order = new Order({ price: 20 }); // Create it on the server. order.save().then(function(order){ // Change its values and // update it on the server. return order.attr(&quot;price&quot;,22) .save(); }).then(function(order){ // Destroy it on the server. return order.destroy(); }); </code></pre> <p><a name="view-models"></a></p> <h3>ViewModels</h3> <p>ViewModels contain the state and model data used by views to create HTML. They also contain methods that the views can call. Custom <a href="../docs/can.Map.html">can.Map</a> types are used as easily unit-testable view-models.</p> <p><a href="http://jsbin.com/sotero/edit?js,output">Example: Define and test a view-model that derives values from source state.</a></p> <pre><code>var RestaurantListVM = can.Map.extend({ define: { restaurants: { get: function() { var state = this.attr('state'), city = this.attr('city'); if(state &amp;&amp; city) { return Restaurant.findAll({ 'address.state': state, 'address.city': city }); } return null; } } } }); </code></pre> <p><a name="views"></a></p> <h3>Views</h3> <p>Views are passed a view-model and generate visual output that’s meaningful to a user - in our case that output is HTML. Views are able to:</p> <ul> <li>Listen to changes in view-models and models and update the HTML (<strong>one-way bindings</strong>).</li> <li>Listen to HTML events, like clicks, and call methods on the view-models and models (<strong>event bindings</strong>).</li> <li>Listen to form elements changing and update view-model and model data (<strong>two-way bindings</strong>).</li> </ul> <p>In CanJS, the preferred method for creating views is using <a href="../docs/can.stache.html">can.stache</a> templates. <code>can.stache</code> uses mustache/handlebars syntax. <code>can.stache</code>'s event and two-way binding syntaxes can be found at <a href="../docs/can.view.bindings.html">can.view.bindings</a>.</p> <p>At this time, <code>can.stache</code> is supplied as a supporting library, which means you must explicitly add it to your application. We’ll see how to do that when we set up our application in the next chapter. In 3.0, Stache will part of the core CanJS lib.</p> <p><a href="http://justinbmeyer.jsbin.com/gewavi/edit?html,output">Example: Generate HTML for the previous example's view-model.</a></p> <pre><code>&lt;label&gt;State&lt;/label&gt; {{#if states.isPending}} &lt;select disabled&gt;&lt;option&gt;Loading...&lt;/option&gt;&lt;/select&gt; {{else}} &lt;select {($value)}=&quot;state&quot;&gt; {{^if state}} &lt;option value=&quot;&quot;&gt;Choose a state&lt;/option&gt; {{/if}} {{#each states.value}} &lt;option value=&quot;{{short}}&quot;&gt;{{name}}&lt;/option&gt; {{/each}} &lt;/select&gt; {{/if}} </code></pre> <p><a name="custom_elements"></a></p> <h3>Custom Elements</h3> <p>Custom HTML Elements are how CanJS encapsulates and orchestrates different pieces of functionality within an application. Custom elements are built with <a href="../docs/can.Component.html">can.Component</a> and combine a view-model and view.</p> <p><a href="http://justinbmeyer.jsbin.com/sonuwuc/edit?html,js,output">Example: Encapsulate rich select behavior with a custom &lt;select-loader&gt; element.</a></p> <pre><code>&lt;select-loader {promise}=&quot;states&quot; {(value)}=&quot;state&quot; choose-text=&quot;Choose a state&quot;&gt; {{#each states.value}} &lt;option value=&quot;{{short}}&quot;&gt;{{name}}&lt;/option&gt; {{/each}} &lt;/select-loader&gt; </code></pre> <p><a name="routing"></a></p> <h3>Routing with an AppViewModel</h3> <p>CanJS maintains a reciprocal relationship between the browser's url and a <a href="../docs/can.Map.html">can.Map</a> view-model. This view-model instance represents the state of the application as a whole and so is called the <code>appViewModel</code>. When the url changes, CanJS will update the properties of the <code>appViewModel</code>. When the <code>appViewModel</code> changes, CanJS will update the url.</p> <p><a href="../docs/can.route.html">can.route</a> is used to setup the relationship between the <code>appViewModel</code> and the URL. It can be used with both <a href="../docs/can.route.pushstate.html">pushstate</a> and hashchange (the default) routing.</p> <p><a href="http://jsbin.com/surokag/edit?html,js,output">Example: Route between &lt;home-page&gt; and &lt;restaurants-page&gt; custom elements.</a></p> <pre><code>{{#eq page 'home'}} &lt;home-page/&gt; {{else}} &lt;restaurants-page/&gt; {{/eq}} </code></pre> <pre><code>var AppViewModel = can.Map.extend({ define: {} }); // Create an instance of that map var appViewModel = new AppViewModel(); // Connect the map to the browser's URL can.route.map(appViewModel); // Define pretty routing rules can.route(&quot;:page&quot;,{page: &quot;home&quot;}); // Start the two-way binding between the URL and the `appViewModel`. can.route.ready(); </code></pre> <p>Application ViewModels free developers from worrying about what the url looks like. Instead, you focus on updating the state of the application.</p> <h2>Using the Getting Started Guide</h2> <p>Each chapter in the Getting Started Guide is prefaced with an overview of the topics covered in that chapter. The overview section also contains a link where you can download a zip file containing the code relevant to that chapter, as follows:</p> <hr /> <p><strong>In this Chapter</strong></p> <ul> <li>Topic 1</li> <li>Topic 2</li> <li>Connecting <code>can.Model</code>’s with <code>can.Component</code>’s</li> </ul> <p>Get the code for: <a href="/guides/examples/PlaceMyOrder/ch-0_canjs-getting-started.zip">chapter 0</a></p> <hr /> <hr /> <p><span class="pull-right"><a href="Setup.html">Setup &rsaquo;</a></span></p> </div> <script src="//static.jsbin.com/js/embed.min.js?3.35.5"></script> </section> <script type="text/javascript"> var docObject = {"src":{"path":"docs/can-guides/experiment/pmo/tutorial.md"},"description":"\n","name":"guides/pmo","title":"Place My Order Guide","type":"page","disabletableofcontents":true,"comment":" ","pathToRoot":"../.."}; </script> </article> <footer><p>CanJS is part of <a href="http://donejs.com" target="_blank">DoneJS</a>. Created and maintained by the core <a href="https://donejs.com/About.html#section=section_Team" target="_blank">DoneJS team</a> and <a href="http://bitovi.com" target="_blank">Bitovi</a>. <strong>Currently 3.0.0.</strong></p></footer> </div> </div> </div> <script> steal = { instantiated: { "bundles/bit-docs-site/static.css!$css" : null } }; </script> <script type='text/javascript' data-main="bit-docs-site/static" src="../static/node_modules/steal/steal.production.js"></script> <script async defer src="https://buttons.github.io/buttons.js"></script> </body> </html>