Web App Development Book Guide to Ember.js David V. Copyright2016 by David V All Rights Reserved
Copyright 2016 by David V All rights reserved. No part of this publication may be reproduced, distributed, or transmitted in any form or by any means, including photocopying, recording, or other electronic or mechanical methods, without the prior written permission of the author, except in the case of brief quotations embodied in critical reviews and certain other noncommercial uses permitted by copyright law.
Table of Contents
Disclaimer While all attempts have been made to verify the information provided in this book, the author does assume any responsibility for errors, omissions, or contrary interpretations of the subject matter contained within. The information provided in this book is for educational and entertainment purposes only. The reader is responsible for his or her own actions and the author does not accept any responsibilities for any liabilities or damages, real or perceived, resulting from the use of this information.
The trademarks that are used are without any consent, and the publication of the trademark is without permission or backing by the trademark owner. All trademarks and brands within this book are for clarifying purposes only and are the owned by the owners themselves, not affiliated with this document.
Introduction
There is an increase in the demand for web apps. Ember JS is a JavaScript which can assist in development of such apps. The framework is easy to learn, and especially for JavaScript experts. However, even if you are not good in JavaScript at all, you dont have to worry, as the explanations in this book are very easy for you to understand.
With this JavaScript, you can create web apps with very interactive user interfaces, and your users will definitely like your apps.
Chapter 1- Controllers
Controllers are much like components, and it is believed that these will be replaced by components in the future. In most of the current apps, controllers are not used much. When they are used, they are tasked with the following responsibilities:
- Used for maintaining state based on the route in use currently.
- When the user actions are passing from a component to a route, they have to pass through a controller.
We need to demonstrate this by use of a route which will help us display a blog post. The template will be bound to the following properties in the template:
{{model.title}}
by {{model.author}}
{{model.intro}}
{{model.body}} As shown in the above example, we do not have specific properties or actions to display. Suppose that we need to add a feature which will allow the user to toggle between the displays of your body sections.
For us to implement this, we would modify the code to the following:
{{model.title}}
by {{model.author}}
{{model.intro}}
{{#if isExpanded}} Hide the Body {{model.body}} {{else}} Show the Body {{/if}} In the actions hook of our controller, we can define what our action will be doing as we can do it with a component. This is shown in the code given below: export default Ember.Controller.extend({ actions: { toggleBody() { this.toggleProperty('isExpanded'); } } });
Management of Dependencies between Controllers Sometimes, when we are nesting resources, we usually need to establish a connection between two controllers. Consider the router given below: Router.map(function() { this.route('post', { path: '/p/:post_id' }, function() { this.route('comments', { path: '/comments' }); }); }); On visiting the URL /posts/1/comments, the model post will be loaded into the model of the PostController. However, some information related to it might be displayed in the template for comments. For us to do this, we have to inject the pController into our CommentsController. This is shown below: export default Ember.Controller.extend({ pController: Ember.inject.controller('post') }); Our comments will be in a position to access the PController, which is a read-only alias which can be used for reading the model from the controller.
Consider the code given below: export default Ember.Controller.extend({ pController: Ember.inject.controller('post'), post: Ember.computed.reads('pController.model') }); Consider the next one for the .hbs file:
Comments for the {{post.title}}
{{#each model as |comment|}} - {{comment.text}}
{{/each}}
Chapter 2- Models
One of the ways to build web applications is to implement user interface components which are highly coupled to data fetching. Consider a situation in which you are creating a blog app. If you are creating the admin part of the app, you may be forced to give the component the responsibility of fetching and storing the data. Consider the code given below:
Comments for {{post.title}}
{{#each model as |comment|}} - {{comment.text}}
{{/each}}
The list of drafts contained in the template of the component can then be shown. The following code demonstrates this:
{{#each drafts key="id" as |draft|}} - {{draft.title}}
{{/each}}
Note that the app is made up of a number of components. You may want to have all of the drafts displayed on another page.
This may require copying and pasting the old code into the new component: export default Ember.Component.extend({ willRender() { $.getJSON('/myDrafts').then(data => { this.set('drafts', data); }); } }); The .hbs file for the button code should be as follows: {{#link-to 'drafts' tagName="button"}} Drafts ({{drafts.length}}) {{/link-to}} With the above, our app will make two requests which are separate but for the same information. In Ember data, the representation of a model is done using a subclass of the model which defines the relationships, attributes, and the behavior of the data which is presented to the user. With models, one can define the kind of data which the server will provide to us. Consider the example given below of a model named human : export default DS.Model.extend({ fName: DS.attr('string'), birthday: DS.attr('date') }); A model can also describe the relationship between itself and the rest of the models. Consider the example given below, which shows how this can be done: export default DS.Model.extend({ lItems: DS.hasMany('line-item') }); The above code is for an order. The code for the line.js should be as follows: export default DS.Model.extend({ order: DS.belongsTo('order') }); You have to note that the models themselves do not have data, but they are used for definition of the attributes, relationships, and the behavior of specific instances referred to as records.
Creating Records When you need to create records, you just have to call the method createRecord() on your store. Consider the code given below: store.createRecord('post', { title: 'Ember is a Great Framework', body: 'Lorem ipsum' }); The stored object will be available to the controllers and the routers by use of this.store. Updating Records You can make changes to the Ember JS data records by setting the attribute which you are in need of changing. This is shown in the code given below: this.store.findRecord('human', 1).then(function(myfunction) { // ...once the record has been loaded myfunction.set('fName', "John"); }); All Ember.js conveniences are always available for modification of attributes. This can be done as shown below: human.incrementProperty('age'); // Happy birthday!
Persisting Records In Ember JS, records are persisted on the basis of a per-instance. When you call the method save() on any instance of the DS.Model, a network request will be made.
By default, newly created records in EmberJS will be posted to their type URL in Ember data. This is shown in the following code: var p = store.createRecord('post', { title: 'Ember is Great', body: 'Lorem ipsum' }); p.save(); // => POST to '/posts' Records which exist on the backend will be updated by use of the HTTP PATCH verb. This is shown in the code given below: store.findRecord('post', 1).then(function(p) { p.get('title'); // => "Ember JS is Great" p.set('title', 'New post'); p.save(); // => PATCH to '/posts/1' }); Consider the code given below: human.get('isAdmin'); //=> false human.get('hasDirtyAttributes'); //=> false human.set('isAdmin', true); human.get('hasDirtyAttributes'); //=> true human.changedAttributes(); //=> { isAdmin: [false, true] } One can tell if an outstanding record has some outstanding changes which have not yet been saved by checking on its property hasDirtyAttributes. At the above point, you can just save the changes by calling the save() method or just roll them back. Consider the code given below: human.get('hasDirtyAttributes'); //=> true human.changedAttributes(); //=> { isAdmin: [false, true] } human.rollbackAttributes(); human.get('hasDirtyAttributes'); //=> false human.get('isAdmin'); //=> false human.changedAttributes(); //=> {} Handling Validation Errors In case your backend server returns validation errors once you try to save, the property errors of your model will havethese. The errors can be displayed as shown below: {{#each p.errors.title as |err|}}