November 7, 2014

[Tutorial] HTML5 Web App - AngularJS

Note: This tutorial was written a couple years ago now, and is likely obsolete in a lot of ways. In fact, I don't think I ever completed this one. Still, it may be helpful, so give it a look-see if it's relevant to you.





Rather than add to my previous tutorial post, I've decided to write a new post covering how to take our basic Cordova HTML5 web app and expand on it with AngularJS. If you haven't read the previous post, I recommend doing so. Otherwise, these are the things you will need:

  • AngularJS - 
  • angular-local-storage - 

Getting Started

We'll be using AngularJS primarily for its utilization of MVC (Model-View-Controller). Put in as basic terms as I can, MVC is made up of three parts. The Model contains the logic and manipulates data. The View displays the data. The Controller is the ever-vigilant translator, taking input from Model or View and making it usable by the other. This allows us to make more dynamic web experiences, changing and updating content immediately with far less effort than a more typical HTML-based program.

Data Binding

The View, which is what is displayed to the user, uses data binding to show the data. Rather than some static text in the page that requires editing the code to be changed, Angular designates a section where the values can be different. Say you have this line in your HTML:

<p>3 + 2 = 5</p>

We can take that statement for granted, or we can prove it. Now consider this line:

<p>3 + 2 = {{ 3+2 }}</p>

Inside the curly braces, we have "3+2" again. But rather than displaying as such on the page, we will only see "3 + 2 = 5". The curly braces are used by Angular to designate a section containing data to be manipulated. But this isn't exactly data binding, it's just evaluating an expression. Let's try adding in a model.

Models

I'm going to copy/paste an HTML document here, and then discuss what it contains. This was adopted from this tutorial video.

<!DOCTYPE html>
<html lang="en" ng-app="app_AngularNameTest">
<head>
<title>Angular Test</title>
</head>
<body>
<input type="text" placeholder="text" value="" ng-model="m_NameText">
<p>Entered: {{ m_NameText }}</p>
<script type="text/javascript" src="js/angular.min.js"></script>
<script type="text/javascript" src="js/angularNameTest.js"></script>
</body>
</html>

For the most part, this is a basic HTML page. You'll notice that I've highlighted some things in blue. These are things I've added that use Angular; in the case of element properties, they're always prefixed by "ng-". In the "html" element, the "ng-app" property tells Angular that this page is to be run as an Angular app, and there'll be more relevant content within. The "ng-model" designates a model being used. Within the curly braces of the following paragraph, the model is invoked.

You'll also notice that a "angularNameTest.js" script file is being called. Within that file is this code:

angular.module('app_AngularNameTest', []);

This is the basis of an Angular app. If you run this project, and type in the text box, you'll see what you type being displayed in the "Entered" paragraph. This is because the text input has a model ("m_NameText") bound to it, so the data entered is applied to the model. Since this HTML file is the View, we can display the value of the model by referencing it within the curly braces.

Controllers
Here's another basic Angular app, that's a bit more involved than the previous one.

<!DOCTYPE html>
<html lang="en" ng-app="app_AngularTest">
    <head>
        <title>Angular Test</title>
    </head>
    <body ng-controller="c_AngularTest">
        <h1>Angular Test App</h1>
        <div>
            <form ng-submit="addTodo(m_TodoText)">
                <input type="text" placeholder="text" value="" ng-model="m_TodoText">
                <button type="submit">+</button>
            </form>
            <p>Entered: {{ m_TodoText}}</p>
            <ul>
                <li ng-repeat="todo in todos">
                    <button ng-click="removeTodo($index)">-</button>
                    <b>{{todo.text}}</b>
                </li>
            </ul>
        </div>
        <!--DO NOT PUT HTML BELOW THIS LINE-->
        <script type="text/javascript" src="js/angular.min.js"></script>
        <script type="text/javascript" src="js/main.js"></script>
    </body>
</html>

And here's the Javascript for it:

angular.module('angularTestApp', [])
.controller('c_AngularTest', function($scope)
{
$scope.todos = [{
text: "Learn AngularJS"
}];
$scope.addTodo = function(todoText)
{
var todo = {
text: todoText
};
$scope.todos.push(todo);
}
$scope.removeTodo = function(index)
{
$scope.todos.splice(index, 1);
}
});

You can see that the model on the text input is still being displayed as in the previous example. But now it's contained within a form, and that form runs a function called "addTodo()", passing in the model, when the form is submitted. That function is part of the controller "c_AngularTest"; it accepts the text passed in through the model, and pushes it to an array. Looking back at the HTML, we see an unordered list element with a single list item, and the list item has an "ng-repeat" property. In Angular, this is essentially like doing a for-each loop in Javascript, with "todo" representing the current index, and "todos" being the array inside the controller. When you enter a new item in the text box and click the plus button to submit it, it's added to the array, and the "ng-repeat" automatically updates the view and displays the list with the new data. Part of each list item, since it's contained in the "ng-repeat", is a button that will call a function to splice that list item's data from the array. Once removed, the view updates again and no longer contains that data.

You're probably wondering what the "$scope" variable is about. It's the reference to the model, and as the Angular documentation defines it, "can watch expressions and propagate events". This all may seem a little complicated from a conceptual standpoint, so feel free to create these files and play around with them.

Layouts and Partials

An excellent use for MVC is to write code once but use it multiple times. (I guess that goes for any language, really!) Normally in an HTML project you have to copy/paste code multiple times for it to appear across every page, which of course requires editing each page to make a consistent change. With Angular, you can set up something called a partial, which is essentially a chunk of HTML (and any other code you're including) that's slipped into a certain spot on a layout page, but can easily be replaced by other code as needed, all without having to modify any files. If you have a partial that's used on multiple changes, you only need to change the one partial file for everything to be updated.

Routing

Since we're basically loading one file inside of another, but that inner file is what provides context to the page we visit, we have to be able to tell the browser that we want to visit that page specifically. To do that, we need to provide a method of deep linking through a route object.

First, download the "angular-route.min.js" file from the AngularJS website. Then let's set up a basic Angular page again:

<!DOCTYPE html>
<html lang="en" ng-app="app_AngularPartialsTest">
<head>
<title>Angular Partials Test</title>
</head>
<body ng-controller="c_AngularPartialsTest">
<div ng-view></div>

<script type="text/javascript" src="js/angular.min.js"></script>
<script type="text/javascript" src="js/angular-route.min.js"></script> <script type="text/javascript" src="js/angularPartialsTest.js"></script>
</body>
</html>

And in our "angularPartialsTest.js" file:

angular.module('app_AngularPartialsTest', [])
.controller('c_AngularPartialsTest', function($scope)
{

}


Our Cordova App

Let's look back at the "index.html" file in our Cordova project. This time, I've highlighted the Angular-specific things I've added in blue.

<!DOCTYPE html>
<!--
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License.  You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     KIND, either express or implied.  See the License for the
    specific language governing permissions and limitations
    under the License.
-->
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta name="format-detection" content="telephone=no" />
        <meta name="msapplication-tap-highlight" content="no" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
        <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
        <link rel="stylesheet" type="text/css" href="css/index.css" />
        <link rel="stylesheet" type="text/css" href="css/main.css" />
        <title>Hello World</title>
    </head>
    <body>
        <div class="app">
            <h1>Apache Cordova</h1>
            <div id="deviceready" class="blink">
                <p class="event listening">Connecting to Device</p>
                <p class="event received">Device is Ready</p>
            </div>
        </div>
        <!--DO NOT PUT HTML BELOW THIS LINE-->
        <script type="text/javascript" src="cordova.js"></script>
        <script type="text/javascript" src="js/jquery-2.1.1.min.js"></script>
        <script type="text/javascript" src="js/bootstrap.min.js"></script>
        <script type="text/javascript" src="js/index.js"></script>
        <script type="text/javascript" src="js/main.js"></script>
    </body>
</html>

No comments:

Post a Comment