Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

AngularJS is getting started


May 08, 2021 AngularJS


Table of contents


Get started quickly

Why AngularJS?

HTML is ideal for declaring static documents, but when we try to use it to declare a dynamic view in a web application, it's not very powerful. A ngularJS can extend HTML vocabulary for your application. The resulting environment is very expressive, readable and developing rapidly.

Alternatives

Other frameworks that address the drawbacks of HTML either abstract HTML, CSS, and/or JavaScript, or provide a necessary way to manipulate the DOM. None of them solves the fundamental problem that HTML is not designed for dynamic views.

Scalability

AngularJS is a tool set for building frameworks that are ideal for your application development. I t's fully scalable and work well with other libraries. E ach feature can be modified or replaced to suit your unique development workflow and functional needs. Read on to find out why.

The Basics

index.html

<!doctype html>
<html ng-app>
  <head>
    <script src="https://atts.w3cschool.cn/attachments/image/wk/angularjs/angular.min.js"></script>
  </head>
  <body>
    <div>
      <label>Name:</label>
      <input type="text" ng-model="yourName" placeholder="Enter a name here">
      <hr>
      <h1>Hello {{yourName}}!</h1>
    </div>
  </body>
</html>

Add some controls

Data binding

Data binding is an automatic way to update a view whenever the model changes, and it also updates the model when the view changes. This is great because it subtracts DOM manipulation from the list you need to worry about.

Control

Control is the behavior behind the DOM element. AngularJS allows you to express behavior in a clean, readable form without having to update the doM's usual model, register callbacks, or observe model changes.

Flat JavaScript

Unlike other frameworks, you do not need to inherit a private type for the model in the wrapper accessor method. T he Angular model is a flat, legacy JavaScript object. This makes your code easy to read, maintainable, re-usable, and doesn't require a model.

index.html

<!doctype html>
<html ng-app="todoApp">
  <head>
    <script src="https://atts.w3cschool.cn/attachments/image/wk/angularjs/angular.min.js"></script>
    <script src="todo.js"></script>
    <link rel="stylesheet" href="todo.css">
  </head>
  <body>
    <h2>Todo</h2>
    <div ng-controller="TodoListController as todoList">
      <span>{{todoList.remaining()}} of {{todoList.todos.length}} remaining</span>
      [ <a href="" ng-click="todoList.archive()">archive</a> ]
      <ul class="unstyled">
        <li ng-repeat="todo in todoList.todos">
          <input type="checkbox" ng-model="todo.done">
          <span class="done-{{todo.done}}">{{todo.text}}</span>
        </li>
      </ul>
      <form ng-submit="todoList.addTodo()">
        <input type="text" ng-model="todoList.todoText"  size="30"
               placeholder="add new todo here">
        <input class="btn-primary" type="submit" value="add">
      </form>
    </div>
  </body>
</html>

todo.js

angular.module('todoApp', [])
  .controller('TodoListController', function() {
    var todoList = this;
    todoList.todos = [
      {text:'learn angular', done:true},
      {text:'build an angular app', done:false}];

    todoList.addTodo = function() {
      todoList.todos.push({text:todoList.todoText, done:false});
      todoList.todoText = '';
    };

    todoList.remaining = function() {
      var count = 0;
      angular.forEach(todoList.todos, function(todo) {
        count += todo.done ? 0 : 1;
      });
      return count;
    };

    todoList.archive = function() {
      var oldTodos = todoList.todos;
      todoList.todos = [];
      angular.forEach(oldTodos, function(todo) {
        if (!todo.done) todoList.todos.push(todo);
      });
    };
  });

todo.css

.done-true {
  text-decoration: line-through;
  color: grey;
}

The back-end connection

Deep link

A deep link reflects where the user is in the app, which is useful, so users can save it as a bookmark and e-mail link to locate it inside the app. T he round trip app automatically gets this feature, but the Ajax app doesn't by its nature. AngularJS combines the benefits of deep links with behavior similar to desktop applications.

Form validation

Client form validation is an important part of a perfect user experience. A ngularJS enables you to declare the validity rules of your form without having to write JavaScript code. So do more with less.

Server communication

AngularJS offers built-in services built on top of XHR, as well as a wide variety of other backends that use third-party libraries. P romise further simplifies your code by processing asynchronously returned data. In this example, we use the Angular Fire library to connect a Firebase backend to a simple Angular application.

index.html

<!doctype html>
<html ng-app="project">
  <head>
    <script src="/attachments/image/wk/angularjs/angular.min.js"></script>
    <script src="/attachments/image/wk/angularjs/angular-resource.min.js">
    </script>
    <script src="/attachments/image/wk/angularjs/angular-route.min.js">
   </script>
    <script src="/attachments/image/wk/angularjs/firebase.js"></script>
    <script src="/attachments/image/wk/angularjs/angularfire.min.js"></script>
    <link rel="stylesheet" href="bootstrap.css">
    <script src="project.js"></script>
  </head>
  <body>
    <h2>JavaScript Projects</h2>
    <div ng-view></div>
  </body>
</html>

bootstrap.css

// Uncomment this in Plunker or JSFiddle: @import '//netdna.bootstrapcdn.com/twitter-bootstrap/2.0.4/css/bootstrap-combined.min.css';

project.js

angular.module('project', ['ngRoute', 'firebase'])

.value('fbURL', 'https://ng-projects-list.firebaseio.com/')
.service('fbRef', function(fbURL) {
  return new Firebase(fbURL)
})
.service('fbAuth', function($q, $firebase, $firebaseAuth, fbRef) {
  var auth;
  return function () {
      if (auth) return $q.when(auth);
      var authObj = $firebaseAuth(fbRef);
      if (authObj.$getAuth()) {
        return $q.when(auth = authObj.$getAuth());
      }
      var deferred = $q.defer();
      authObj.$authAnonymously().then(function(authData) {
          auth = authData;
          deferred.resolve(authData);
      });
      return deferred.promise;
  }
})

.service('Projects', function($q, $firebase, fbRef, fbAuth) {
  var self = this;
  this.fetch = function () {
    if (this.projects) return $q.when(this.projects);
    return fbAuth().then(function(auth) {
      var deferred = $q.defer();
      var ref = fbRef.child('projects-fresh/' + auth.auth.uid);
      var $projects = $firebase(ref);
      ref.on('value', function(snapshot) {
        if (snapshot.val() === null) {
          $projects.$set(window.projectsArray);
        }
        self.projects = $projects.$asArray();
        deferred.resolve(self.projects);
      });

      //Remove projects list when no longer needed.
      ref.onDisconnect().remove();
      return deferred.promise;
    });
  };
})

.config(function($routeProvider) {
  var resolveProjects = {
    projects: function (Projects) {
      return Projects.fetch();
    }
  };

  $routeProvider
    .when('/', {
      controller:'ProjectListController as projectList',
      templateUrl:'list.html',
      resolve: resolveProjects
    })
    .when('/edit/:projectId', {
      controller:'EditProjectController as editProject',
      templateUrl:'detail.html',
      resolve: resolveProjects
    })
    .when('/new', {
      controller:'NewProjectController as editProject',
      templateUrl:'detail.html',
      resolve: resolveProjects
    })
    .otherwise({
      redirectTo:'/'
    });
})

.controller('ProjectListController', function(projects) {
  var projectList = this;
  projectList.projects = projects;
})

.controller('NewProjectController', function($location, projects) {
  var editProject = this;
  editProject.save = function() {
      projects.$add(editProject.project).then(function(data) {
          $location.path('/');
      });
  };
})

.controller('EditProjectController',
  function($location, $routeParams, projects) {
    var editProject = this;
    var projectId = $routeParams.projectId,
        projectIndex;

    editProject.projects = projects;
    projectIndex = editProject.projects.$indexFor(projectId);
    editProject.project = editProject.projects[projectIndex];

    editProject.destroy = function() {
        editProject.projects.$remove(editProject.project).then(function(data) {
            $location.path('/');
        });
    };

    editProject.save = function() {
        editProject.projects.$save(editProject.project).then(function(data) {
           $location.path('/');
        });
    };
});

list.html

<input type="text" ng-model="projectList.search" class="search-query" id="projects_search"
       placeholder="Search">
<table>
  <thead>
  <tr>
    <th>Project</th>
    <th>Description</th>
    <th><a href="#/new"><i class="icon-plus-sign"></i></a></th>
  </tr>
  </thead>
  <tbody>
  <tr ng-repeat="project in projectList.projects | filter:projectList.search | orderBy:'name'">
    <td><a ng-href="{{project.site}}" target="_blank">{{project.name}}</a></td>
    <td>{{project.description}}</td>
    <td>
      <a ng-href="#/edit/{{project.$id}}"><i class="icon-pencil"></i></a>
    </td>
  </tr>
  </tbody>
</table>

detail.html

<form name="myForm">
  <div class="control-group" ng-class="{error: myForm.name.$invalid && !myForm.name.$pristine}">
    <label>Name</label>
    <input type="text" name="name" ng-model="editProject.project.name" required>
    <span ng-show="myForm.name.$error.required && !myForm.name.$pristine" class="help-inline">
        Required {{myForm.name.$pristine}}</span>
  </div>

  <div class="control-group" ng-class="{error: myForm.site.$invalid && !myForm.site.$pristine}">
    <label>Website</label>
    <input type="url" name="site" ng-model="editProject.project.site" required>
    <span ng-show="myForm.site.$error.required && !myForm.site.$pristine" class="help-inline">
        Required</span>
    <span ng-show="myForm.site.$error.url" class="help-inline">
        Not a URL</span>
  </div>

  <label>Description</label>
  <textarea name="description" ng-model="editProject.project.description"></textarea>

  <br>
  <a href="#/" class="btn">Cancel</a>
  <button ng-click="editProject.save()" ng-disabled="myForm.$invalid"
          class="btn btn-primary">Save</button>
  <button ng-click="editProject.destroy()"
          ng-show="editProject.project.$id" class="btn btn-danger">Delete</button>
</form>

Create a component

Instructions

Instructions are a unique and powerful feature that is only available in Angular. Directives enable you to invent new HTML synths that are specific to your application.

Reusable components

We use instructions to create reusable components. C omponents allow you to hide complex DOM structures, CSS, and behaviors. This allows you to focus on what the application wants to do, or how the individual application looks.

Localization

An important part of serious applications is localization. AngularJS's local sniffing filters and blocking instructions enable you to build masks that make your application available everywhere.

index.html

<!doctype html>
<html ng-app="app">
  <head>
    <script src="https://atts.w3cschool.cn/attachments/image/wk/angularjs/angular.min.js"></script>
    <script src="components.js"></script>
    <script src="app.js"></script>
    <link rel="stylesheet" href="bootstrap.css">
  </head>
  <body>
    <tabs>
      <pane title="Localization">
        Date: {{ '2012-04-01' | date:'fullDate' }} <br>
        Currency: {{ 123456 | currency }} <br>
        Number: {{ 98765.4321 | number }} <br>
      </pane>
      <pane title="Pluralization">
        <div ng-controller="BeerCounter">
          <div ng-repeat="beerCount in beers">
            <ng-pluralize count="beerCount" when="beerForms"></ng-pluralize>
          </div>
        </div>
      </pane>
    </tabs>
  </body>
</html>

components.js

angular.module('components', [])

  .directive('tabs', function() {
    return {
      restrict: 'E',
      transclude: true,
      scope: {},
      controller: function($scope, $element) {
        var panes = $scope.panes = [];

        $scope.select = function(pane) {
          angular.forEach(panes, function(pane) {
            pane.selected = false;
          });
          pane.selected = true;
        }

        this.addPane = function(pane) {
          if (panes.length == 0) $scope.select(pane);
          panes.push(pane);
        }
      },
      template:
        '<div class="tabbable">' +
          '<ul class="nav nav-tabs">' +
            '<li ng-repeat="pane in panes" ng-class="{active:pane.selected}">'+
              '<a href="" ng-click="select(pane)">{{pane.title}}</a>' +
            '</li>' +
          '</ul>' +
          '<div class="tab-content" ng-transclude></div>' +
        '</div>',
      replace: true
    };
  })

  .directive('pane', function() {
    return {
      require: '^tabs',
      restrict: 'E',
      transclude: true,
      scope: { title: '@' },
      link: function(scope, element, attrs, tabsController) {
        tabsController.addPane(scope);
      },
      template:
        '<div class="tab-pane" ng-class="{active: selected}" ng-transclude>' +
        '</div>',
      replace: true
    };
  })

app.js

angular.module('app', ['components'])

.controller('BeerCounter', function($scope, $locale) {
  $scope.beers = [0, 1, 2, 3, 4, 5, 6];
  if ($locale.id == 'en-us') {
    $scope.beerForms = {
      0: 'no beers',
      one: '{} beer',
      other: '{} beers'
    };
  } else {
    $scope.beerForms = {
      0: '?iadne pivo',
      one: '{} pivo',
      few: '{} pivá',
      other: '{} pív'
    };
  }
});

bootstrap.css

// Uncomment this in Plunker or JSFiddle: @import '//netdna.bootstrapcdn.com/twitter-bootstrap/2.0.4/css/bootstrap-combined.min.css';

Testability is built in

Injectable

The AngularJS dependency injection allows you to state declaratively how your application is connected. T his means that your application does not need the main() method, which is usually a large heap that is difficult to maintain. D ependency injection is also a core of Angular JS. This means that any component that doesn't fit your needs can be easily replaced.

Testable

AngularJS is designed to be testable from the root. I t encourages behavior to separate from view, simulate with prebinding, and take full advantage of dependency injection. It is also equipped with an end-to-end scene sewer, which eliminates test layer sharing by understanding the internal workings of AngelJS.