• No results found

Loading data: using the controller to load and display data in the view

In document Ionic in Action (Page 71-74)

What you need to know about AngularJS

3.5 Loading data: using the controller to load and display data in the view

Let’s start loading the data and getting it to display in the application. On the left the application will show a list of the notes that have already been created. I’ve seeded this project with a few notes to get you started. Because you’ve already created your con-troller, you can update the controller to load data into the app. To do this, you’ll use the Angular $http service, which allows you to make HTTP requests to load data from the Node server. Figure 3.6 shows where the application will display the list of notes.

You can reset your project to step4 if you’re using Git:

$ git checkout -f step4 (continued)

You can look at the server.js file inside of this project to see the server code. This is a fully featured server, and it’s impressive how easy it is to create with Node. You can learn more about Express at www.expressjs.com.

The list of notes appears in the left column.

Figure 3.6 The data will be loaded and then displayed in the list on the left, showing the five default notes.

Now you need to modify the controller to add the HTTP request to the notes service, and assign the resulting data to the scope. Open the js/editor.js file and update it to the following code.

angular.module('App')

.controller('EditorController', function ($scope, $http) { $scope.editing = true;

$http.get('/notes').success(function (data) { $scope.notes = data;

}).error(function (err) {

$scope.error = 'Could not load notes';

});

});

This now will make an HTTP request to http://localhost:3000/notes to load the default list of notes from the data/notes.json file as soon as the controller loads. You can inspect the network requests in your browser inspector tools to see that the request returns the array of notes. Angular takes care of automatically parsing the JSON into a JavaScript object if it can detect the response body as a valid JSON string.

This makes it easy to load JSON data without having to handle the parsing yourself.

In your controller function, you can declare any number of parameters for the function, and Angular will try to locate a service by that name and inject it into the controller. For example, you’re able to inject the $http service into your controller

B

and then use it to load data

C

. This is called dependency injection (DI), and it’s a power-ful feature of Angular to be able to make services available for your controllers to use.

Angular services aren’t global and can’t be used without first being injected.

Imagine you have a menu at a restaurant that represents all of the Angular services available. Dependency injection is like a waiter who comes to your table and takes your order for a particular item on the menu. He goes to the kitchen, has the item prepared, and returns with it for you. Similarly, the DI system looks at your requested services, does any work to set them up, and returns the services to your function for you to use. You’re able to inject the default Angular services or any other services that you create yourself.

In the code there are two methods chained to the $http.get() method. The code inside of the success() function will run when the data has loaded, while the code inside of the error() function will run if there was a problem getting the data (for example, the HTTP request failed because the server was down).

Listing 3.2 Editor controller loading notes from service (js/editor.js)

Injects $http service into controller

B

Uses $http.get to load notes; on success,

You can’t yet see any of the data on your screen, so you need to update the template file to show the list of notes in the left column. This will require template binding and several Angular directives to manage the display of this data from the $scope. Open the index.html file and look for the markup shown in the following listing, and add the bold parts into the template.

<div class="col-sm-3">

<div class="panel panel-default">

<div class="panel-heading">

<h3 class="panel-title"><button class="btn btn-primary btn-xs pull-right">New</button> My Notes</h3>

</div>

<div class="panel-body">

<p ng-if="!notes.length">No notes</p>

<ul class="list-group">

<li class="list-group-item" ng-repeat="note in notes">{{note.title}}<br />

Listing 3.3 Notes list template (index.html) Angular and asynchronous methods

JavaScript is single-threaded, which means it can only execute one task at a time.

Certain tasks, such as loading data from a server, can take a reasonably long time.

In synchronous programming this would block other tasks’ code from running until it was finished, likely causing the interface to freeze during this time. Fortunately, JavaScript doesn’t do this. JavaScript supports many asynchronous tasks, which solves this problem.

When JavaScript runs an asynchronous task, it begins with the first part of the task, and then sets it aside to continue running other tasks. When the asynchronous task finishes, it alerts JavaScript, and the rest of the task is queued to execute. This frees up JavaScript to continue processing tasks. HTTP requests in JavaScript (also called AJAX or XHR requests) are one example of an asynchronous function because there’s a lot of time spent waiting for the server to respond.

There are two primary ways to handle asynchronous functions: callbacks and prom-ises. Angular uses promises for asynchronous method calls, but both may be used depending on the structure of the application or modules you’re using.

To get more details about promises with Angular, I recommend looking at this blog post from Xebia’s blog: http://blog.xebia.com/2014/02/23/promises-and-design-patterns-in-angularjs/.

ngIf conditionally includes or removes element from DOM depending on if there are notes.

ngRepeat loops over every note and displays the note title.

Binding shows date, but also formats date using short format date filter.

Here the template displays the list of notes once the controller has loaded them.

While the list is loading or if no notes are found, the ngRepeat list would be empty and the ngIf would display the “No notes” message. The expression is evaluated every time the notes model is updated, so as soon as the notes model has at least one item in the array, the expression !notes.length will return false to hide the paragraph element. This is a simple way to use Angular’s directives to modify the template based on values attached to the $scope.

ngRepeat will loop over every item in an array (or property of an object) and create an element for each item. In this case, there will be a <li> element for each note in the array, and it will display the title and date the note was last saved.

You can explore the large number of directives that Angular provides to see all of the features. You’ll use a number of them in Ionic apps, but I’ll provide some detail about any new ones as they’re used.

3.5.1 Filters: convert data to display in the view

The note.date data binding in the template is followed by | date:'short'. This is called a filter, which will modify the display of the binding without changing the value on the scope. For example, here we have a date object, and using the Angular date fil-ter, the display formats it to a human-readable format while retaining the original date object on the scope.

Filters are used in expressions by adding the pipe character and then the filter. Fil-ters can be chained together—in other words, you can add more than one filter. For example, a filter could sort an array (using the orderBy filter) and then another filter could reduce the array to 10 items (using the limitTo filter). The expression with the filters would appear like this:

{{notes | orderBy:'title' | limitTo:10}}

Angular has a handful of filters by default, such as a currency filter to format a num-ber as a currency value (like $100.00 for US dollars or €34 for Euros) based on browser settings. Filters can also be used as a service, but that’s less common.

In document Ionic in Action (Page 71-74)