At this point, you should have a better understanding of what Ember is and what it can do. You should also understand each component that enables Ember to implement its capabilities: application (application), model (models), view (view), and controller (director). Now it's time to apply this knowledge to write a truly usable application. You'll skip the industry-standard "Todo app" and move on to being closer and familiar to many people: Twitter. In the remainder of this tutorial, you will build a Twitter timeline viewer. It may be helpful to look at the final results before writing any code.
Using the boilerplate HTML page at the beginning of this article, you will first build the underlying HTML. Copy the following code and paste it into a new HTML file named Index.html. You need to reference the CSS file in the sample file in this article. The sample file also contains a starting point for the project and can be used at any time.
<!doctype html>
You can see that the app has three parts: an input field that allows the user to enter a Twitter user name, a timeline viewer to display tweets for the selected Twitter user, and the latest list of users that will store the previous search.
The search box will appear at the top of the page, the newest user in the left column, and the tweet itself will occupy most of the pages on the right side of the page.
Next, create another file named App.js, and add the following. These annotations can help you keep your code organized. Load this page in your browser and make sure there are no errors.
/************************** * Application **************************/ /************************** * Models **************************/ /************************** * Views **************************/ /************************** * Controllers **************************/
Application initializationThe first thing you need to do is to initialize your application. Directly below the comment block labeled application, put the following code:
App = Em.Application.create();
Note that this line is not using ember.application, but em.application. You can use "Ember" anywhere you might want to use "Em", and the Ember team reduces the number of words to enter by adding this handy shortcut.
Next, you will add the TextInput view and the Submit button. Directly below the comment block labeled "views," put the following code:
App.SearchTextField = Em.TextField.extend({ insertNewline: function(){ App.tweetsController.loadTweets(); } });
This block starts with the APP namespace and then expands one of the pre-packaged view TextField for Ember. In addition to allowing arbitrary properties and functions within the views, Ember also provides built-in helper functions. That is the function, which is executed whenever the cursor is in the insertNewLine()
input box and the user presses the Enter/return key on the keyboard.
Create a template blockNow that you have defined the TextField view, you will add the appropriate view helper code to the HTML file. Switch to index.html and add the following code directly after the line that appears as "Load Tweets for". Keep in mind {{
that }}
any and all of the code inside is a template and will be Ember for output data. In addition, any template that starts with a word refers to a view
view that has already been defined in your JavaScript code.
{{view App.SearchTextField placeholder="Twitter username" valueBinding="App.tweetsController.username"}} <button {{action "loadTweets" target="App.tweetsController"}}>Go!</button>
This section of the template contains a view helper, and a {{action}}
button tag with an auxiliary program. TextField View SearchTextField
begins with placeholder text, which is a property built into the HTML5 text input field. If the field is blank, the placeholder
text in the attribute is placed in the input field. When someone starts typing, the value disappears. Ember enables developers to use any of the HTML 5 standard properties within their built-in views.
The second property highlights the ability to Ember data binding. Ember uses a set of conventions to help it determine what you want to accomplish. Any property in the view (a template or a view in a JavaScript file) that ends with the word "Binding" (note capital letter) automatically sets the binding for the property that precedes it. In this example, Ember App.tweetsController.username
binds the value to the property of the input field value
. Whenever the contents of a variable change, the value in the input field is automatically updated and vice versa.
{{action}}
Makes it easier to add functionality to input-driven elements. It has two options: operation name and Target. The two combine to form a "path" that points to the functions contained in the Ember object. In the example of the above button, the path will be the App.tweetsController.loadTweets()
same function that is called when the user presses the Enter key within the text field. Load index.html in your browser and click the Submit button, or press Enter in the input field. If you view the browser console, you will see an error. This is because there is no definition yet App.tweetsController
.
Preparing Tweet Storage ObjectsNow is a App.tweetsController
good time to define. Controllers
Add the following code after the comment block in App.js. You should already be familiar with the following code. namespaces, Arraycontroller, content arrays-everything is in. But this time you will add an arbitrary attribute ( username
) and a function ( loadTweets
). After adding Arraycontroller, reload your browser. Enter a word in the input box, and then click the button. You will get a prompt box to echo the words you typed. You can delete the prompt line at any time. You will also see an error indicating that the method has not been defined addUser
.
App.tweetsController = Em.ArrayController.create({ content: [], username: ‘‘, loadTweets: function() { var me = this; var username = me.get("username"); alert(username); if ( username ) { var url = ‘http://api.twitter.com/1/statuses/user_timeline.json‘ url += ‘?screen_name=%@&callback=?‘.fmt(me.get("username")); // push username to recent user array App.recentUsersController.addUser(username); } } });
Take a closer look at loadTweets
the definition of the function; it has some strange code. The remainder of the first behavior function sets a range . By definition, the scope or this is the current function for all Ember objects, in this case App.tweetsController
. However, in this tutorial, you can add more features to a function later loadTweets
. Setting the current scope now helps Ember understand the context you're using.
As mentioned earlier, Ember provides many helper functions that make it easier to write applications that include get()
and set()
. The two functions are built into each Ember object and provide quick access to any property or function. The next line uses the scope of the current object, App.tweetsController
and then calls the get()
function to pass in the name of the property whose value you want to get. You may wonder where the value of the user name to use at the beginning comes from. Keep in mind that Ember data binding is bidirectional. This means that once you type a value in the input field, the property of the input field view valueBinding
updates the object with a value App.tweetsController
.
After the user name is retrieved, a test is run to ensure that it is not empty. if
There are only two statements in this block, but this will change later. The first statement sets the URL for a user to a JSON file for Twitter. You may not notice what's special here, but take a closer look and you'll find the sum at the end %@
.fmt()
. .fmt()
The function performs a convenient string substitution, which is used %@
as a token. Because the design of your application requires that you store a search list, you must store your search terms in some way. The last line executes the function, pushing the value of the user name to App.recentUsersController
Arraycontroller. Because the object does not already exist, running the code produces an error.
Search before storingIn the following section, you will create an object to store the most recent search. Use the following code and add it App.tweetsController
behind the object.
App.recentUsersController = Em.ArrayController.create({ content: [], addUser: function(name) { if ( this.contains(name) ) this.removeObject(name); this.pushObject(name); }, removeUser: function(view){ this.removeObject(view.context); }, searchAgain: function(view){ App.tweetsController.set(‘username‘, view.context); App.tweetsController.loadTweets(); }, reverse: function(){ return this.toArray().reverse(); }.property(‘@each‘) });
You are already familiar with how to create Arraycontroller and add an empty array of content, but the object has some new elements that addUser
begin with a function. This will use contains()
the built-in Ember function named to examine the existing array ( this
). If it finds a result, it uses the Arraycontroller function to removeObject()
delete the result. In contrast to this function, there is a pushObject()
function called, which is used to add a separate object to the content array. Both of these functions have complex versions that handle multiple objects: pushObjects()
and removeObjects()
. This code deletes the existing search term before adding the search term, so the same search term is not displayed more than once. Now that you know how to remove an object from the content array, the removeUser()
only new element in the function is the parameter. When {{action}}
a function is called using a helper program, Ember implicitly passes a reference to the current view. In App.tweetsController
The example, the view has a context, which is basically the item that is currently being traversed. The context is used to remove the selected item from the array.
searchAgain()
The function also receives the current view as a parameter. When the user clicks a previously searched word, the function populates with the selected user name App.tweetsController.username
and then triggers the loadTweets()
function to provide a click view for the previous search.
By default, Ember displays content to the page in ascending order. Array index 1 is the first, array index 2 is the second, and so on. The design of this application requires that the most recent search be displayed in descending order. This means that the array must be reversed. Although this is not a built-in function, you can see how easy it is to add it. Reverse()
First Use the Ember toArray()
function to convert the Ember content array into a normal array, reverse it, and then return it. So that the function can be used as a data source, is the function added at the end property()
. The property()
function uses a comma-delimited list of attributes required by a specified function. In this case, the property()
function implicitly uses the content array itself, using @each
a dependent key to address each element within the array. In the next section, you'll see how to implement the reverse()
function.
Show previous searchesNow that you have stored the previous search, it is time to display them on the page. Copy the following template and add it after the tag labeled Recent Users
h3
.
<ol> {{#each App.recentUsersController.reverse}} <li> <a href="#" title="view again" {{action "searchAgain" target="App.recentUsersController"}}>{{this}}</a> - <a href="#" title="remove" {{action "removeUser" target="App.recentUsersController"}}>X</a> </li> {{/each}} </ol>
You should now be familiar with all of this code. The each
block points to the content array, and the HTML contained within it is applied to App.recentUsersController
each item in the variable. You do not have to explicitly point to the content array, but in this case, the code points to the reverse
function, which provides the data in reverse order. {{action}}
the helper program lets the user click each anchor tag and trigger the specified function. The only element that may not be familiar is {{this}}
. When iterating through an array of contents, Ember {{this}}
holds a reference to the current index in the variable. Because the value of each item is just a string, you can use {{this}}
the direct output value of the current item. Clicking the Twitter user name will reload the user's tweets, and clicking on the tweets will recentUsersController
remove them from them.
Loading tweetsIt's okay to save the search term, but what about actually performing the search? Next, you'll add a fragment that retrieves the JSON package from Twitter and displays it to the page. Use the following Ember Model and add it directly behind the comment block labeled model. Keep in mind that the Ember Model is the data they will contain is a blueprint.
App.Tweet = Em.Object.extend({ avatar: null, screen_name: null, text: null, date: null });
In App.js, locate App.recentUsersController.addUser(username);
the line of code that is displayed, and add the following code directly after it:
$.getJSON(url,function(data){ me.set(‘content‘, []); $(data).each(function(index,value){ var t = App.Tweet.create({ avatar: value.user.profile_image_url, screen_name: value.user.screen_name, text: value.text, date: value.created_at }); me.pushObject(t); }) });
If you've used JQuery before, you might have used a .get()
function to retrieve the data. The .getJSON()
function does the same thing, but it sees the JSON package as a result. In addition, it uses the returned JSON string and transforms it into an executable JavaScript code. After the data is retrieved, the content array is emptied and all existing tweets are deleted. The next line extracts the packet and encapsulates it in a JQuery object, so .each()
the method can loop the generated Tweets. In the each
block, a copy of the Tweet Model is populated with data and then pushed to Arraycontroller.
Finally, you need to add the following display code to index.html. Copy and paste it directly Tweets
behind the tag tag h3
.
<ul> {{#each App.tweetsController}} <li> <span>{{date}}</span>
Ember uses pure {{Handlebars}}
can easily output data to the page, but there is a problem. Remember how Ember wrapped the output value in a script tag? This is not an option when you are using HTML attributes. So Ember provides the {{bindAttr}}
auxiliary program. Any properties placed within this helper will be output as usual, but the bindings remain. Continue with the operation and now run your application. Enter a user name and you will see Tweets appear.
Next reading directionIn this article, you learned the basics of ember.js functionality. You also learned how Ember uses its models, views, Controllers, and, of course, application objects to implement MVC. You use handlebars to create a template from a view helper and an action helper program. You learned how to use Models to create a blueprint for your data, use Controllers to store the data in a collection set, and use views to display the data to the page. Finally, you used Ember to build a complete application with data binding, computed properties, and Automatic Update templates. Your mother will be very proud of you!
For more reading about Ember, check out some of the links below:
- Ember.js
- Ember.js Documentation
- The Emberist
- Tom Dale at the Ember.js Meetup
- Andy Matthews Blog
- Cerebris Blog
- Code 418 Holy Moly Blog
This article was published based on the creative Commons attribution-noncommercial-share Alike 3.0 Unported License protocol.
Light the Flame! Ember.js Beginner's Guide