On Github jagthedrummer / ember_ndc_london
NOT server side MVC
Many of the same termsbut sometimes they mean different things
Connect URLs to code paths
# Rails config/routes.rb Rails.application.routes.draw do get 'about' => 'static_pages#about', :as => :about end
// Ember Router App.Router.map(function(){ this.route('about'); });
Object wrapper for business data
# Rails db/schema.rb create_table "patterns" do |t| t.integer "p1" t.integer "p2" t.integer "p3" # ... end
class Pattern < ActiveRecord::Base def name "#{p1}-#{p2}-#{p3}" end end
Object wrapper for business data
App.Pattern = DS.Model.extend({ p1 : DS.attr('number'), p2 : DS.attr('number'), p3 : DS.attr('number'), name : function(){ return this.get('p1') + '-' + this.get('p2') + '-' + this.get('p3'); }.property('p1','p2','p3') });
Markup for UI
Interaction & DOM Logic
Ember Components are VERY similar
This is the place for jQuery DOM selectors andintegration with other JS libs.
# Rails config/routes.rb get 'about' # <-- This line is commonly called a route.
// Ember Router this.route('about'); // <-- This line is commonly called ??? // A line in the router? // It is NOT a Route.
# app/controllers/pages_controller.rb class PagesController < ApplicationController def about @authors = Author.all end end
App.AboutRoute = Ember.Route.extend({ model : function(){ return this.store.find('author'); } });
Setup data for user interaction (index, new, edit, show)
Handle user interactions and input (create, update, delete)
App.PatternsNewController = Ember.ObjectController.extend({ actions : { savePattern : function(){ this.get('model').save(); this.transitionToRoute('pattern',this.get('model')); } } });
# config/routes.rb Rails.application.routes.draw do root :to => 'static_pages#home' end
<!-- app/views/static_pages/home.html.erb --> <h1>This app is useless!</h1>
# app/controllers/static_pages_controller.rb class StaticPagesController < ApplicationController end
App = Ember.Application.create();
<script type="text/x-handlebars"> <h2>Welcome to the Pattern Lab!</h2> <p>Your home for procedurally generated patterns.</p> <p>This is a small demo app built with Ember and Ember Data.</p> </script>
App = Ember.Application.create(); App.Router.map(function(){ this.route('index',{ path:'' }) }); App.IndexRoute = Ember.Route.extend({}); App.IndexController = Ember.ObjectController.extend({}); App.IndexView = Ember.View.extend({}); <script type="text/x-handlebars" id="index"> <h1>This app is verbose AND useless!</h1> </script>http://emberjs.jsbin.com/boyim/3/edit
<!--app/views/layouts/application.html.erb --> <html> <head>...</head> <body> <h1>This is the layout</h1> <hr> <%= yield %> </body> </html>
<!-- app/views/static_pages/home.html.erb --> <h1>This app is useless!</h1>
<script type="text/x-handlebars"> <div class="header"> <h1 id='title'> {{#link-to 'index'}}PatternLab{{/link-to}} </h1> </div> {{outlet}} </script> <script type="text/x-handlebars" id="index"> <h2>Welcome to the Pattern Lab!</h2> <p>Your home for procedurally generated patterns.</p> <p>This is a small demo app built with Ember and Ember Data.</p> </script>
# config/routes.rb Rails.application.routes.draw do # ... get 'about' => 'static_pages#about', :as => :about end
<!-- app/views/static_pages/about.html.erb --> <h1>This app has not gotten any more useful...</h1>
<%= link_to 'About', about_path %>
App.Router.map(function(){ this.route('about'); });
<script type="text/x-handlebars" id="about"> <h2>About</h2> <p>PatternLab is a small demo appliction of Ember.</p> </script>
<script type="text/x-handlebars"> <!-- ... --> {{#link-to 'about'}}About{{/link-to}} <!-- ... --> </script>
<!-- in app/views/layouts/application.html.erb --> <%= render 'layouts/footer' %>
<!-- app/views/layouts/_footer.html.erb --> <hr>© OctoLabs
<script type="text/x-handlebars"> <!-- ... --> {{partial 'footer'}} </script>
<script type="text/x-handlebars" id="_footer"> <hr/>© OctoLabs </script>
# app/controllers/static_pages_controller.rb class StaticPagesController < ApplicationController def about @about_data = { :version => "0.0.1" } end end
<!-- app/views/static_pages/about.html.erb --> <h1>About</h1> <p>Version : <%= @about_data[:version] %></p>
App.IndexRoute = Ember.Route.extend({ model : function(){ return { version : "0.0.1" }; } });
<script type="text/x-handlebars" id="index"> <!-- ... --> <p>Version : {{version}}</p> </script>
<script type="text/x-handlebars" id="index"> <!-- ... --> <p>Version : {{version}}</p> {{input value=version}} </script>
# in db/schema.rb create_table "patterns" do |t| t.integer "p1" t.integer "p2" t.integer "p3" t.datetime "created_at", :null => false t.datetime "updated_at", :null => false end
class Pattern < ActiveRecord::Base def name "#{p1}-#{p2}-#{p3}" end end
resources :patterns
class PatternsController < ApplicationController def index @patterns = Pattern.all end end
<h2>Latest Patterns</h2> <ul> <% @patterns.each do |pattern| %> <li><%= pattern.name %></li> <% end %> </ul>
App.Pattern = DS.Model.extend({ p1 : DS.attr('number'), p2 : DS.attr('number'), p3 : DS.attr('number'), name : function(){ return this.get('p1') + '-' + this.get('p2') + '-' + this.get('p3'); }.property('p1','p2','p3') });
App.Router.map(function() { // ... this.resource('patterns'); });
App.PatternsRoute = Ember.Route.extend({ model : function(){ return [this.store.createRecord('pattern', { p1 : 1, p2 : 2, :p3 : 5} )]; } });
<script type="text/x-handlebars" id="patterns"> <h2>Latest Patterns</h2> <ul> {{#each}} <li>{{name}}</li> {{/each}} </ul> </script>
App.ApplicationAdapter = DS.FixtureAdapter;
App.Pattern.reopenClass({ FIXTURES: [ { id: 1, p1 : 1, p2 : 2, p3 : 5}, { id: 2, p1 : 42, p2 : 142, p3 : 242}, { id: 3, p1 : 100, p2 : 200, p3 : 300} ] });
App.PatternsRoute = Ember.Route.extend({ model : function(){ return this.store.find('pattern'); } });
App.Router.map(function() { this.resource('patterns',function(){ this.resource('pattern', { path: '/:pattern_id' }); }); });
<script type="text/x-handlebars" id="pattern"> <h3>{{name}}</h3> </script>
<script type="text/x-handlebars" id="patterns"> <h2>Latest Patterns</h2> <ul> {{#each}} <li> {{#link-to 'pattern' this}}{{name}}{{/link-to}} </li> {{/each}} </ul> {{outlet}} </script>
{{pattern-display pattern=model width="256" height="256"}}
<script type="text/x-handlebars" id="components/pattern-display"> <canvas {{bind-attr id=canvasId width=width height=height }}></canvas> </script>
App.PatternDisplayComponent = Ember.Component.extend({ drawPattern : function(){ var ch = new Chromanin(256,this.get('canvasId')), p1 = this.get('pattern.p1'), p2 = this.get('pattern.p2'), p3 = this.get('pattern.p3'); ch.initlayers(256,256); ch.checkerBoardLayer(0,16,16,p1,p2,p3,0,0,128); ch.sineDistort(0,0,0.100000001490116,p1,p2,p3); ch.addLayers(0,1,4,1,1); ch.addLayers(4,2,4,1,1); ch.addLayers(4,3,4,1,1); ch.writeCanvas(); } // ... });
App.PatternDisplayComponent = Ember.Component.extend({ // ... didInsertElement : function(){ this.drawPattern(); }, automaticUpdate : function(){ Ember.run.next(this,function(){ this.drawPattern(); }); }.observes('pattern','pattern.p1','pattern.p2','pattern.p3'), canvasId : function(){ return "canvas-" + Math.floor((Math.random() * 1000000) + 1);; }.property('pattern.id') });
App.Router.map(function() { this.resource('patterns',function(){ this.resource('pattern', { path: '/:pattern_id' }); this.route('new'); }); });
{{#link-to 'patterns.new'}}New Pattern{{/link-to}}
<script type="text/x-handlebars" id="patterns/new"> <h2>Create a new Pattern</h2> {{input value=p1 type='number'}} {{input value=p2 type='number'}} {{input value=p3 type='number'}} <button {{action randomize}}>Randomize</button> <button {{action savePattern}}>Save</button> <br/><br/> {{pattern-display pattern=model width="256" height="256"}} </script>
App.PatternsNewRoute = Ember.Route.extend({ model : function(){ return this.store.createRecord('pattern'); } });
App.PatternsNewController = Ember.ObjectController.extend({ actions : { savePattern : function(){ this.transitionToRoute('pattern',this.get('model')); }, randomize : function(){ this.setProperties({ p1 : Math.floor((Math.random() * 1000) + 1), p2 : Math.floor((Math.random() * 1000) + 1), p3 : Math.floor((Math.random() * 1000) + 1) }); } } });
App.ApplicationAdapter = DS.RESTAdapter.extend({ host : 'http://pattern-lab-api.herokuapp.com' });
savePattern : function(){ var _this = this; this.get('model').save().then(function(pattern){ _this.transitionToRoute('pattern',pattern); }); }http://emberjs.jsbin.com/kimoyo/2/edit
@jagthedrummer
jeremy@octolabs.com