Tuesday, October 23, 2012

Angular JS - The Very Basics

As I'm all about Angular JS these days, and the four friends I have that read this blog have told me to do a blog entry about it, I figured I would finally write a blog entry about the basics of Angular JS.

What is Angular?


It's a JavaScript framework from Google that encompasses:
  • Two way binding
  • Dependency injection
  • Built-in handling of RESTful services
  • Handling of AJAX calls
  • Handling of hash-based routing (for single page applications)
  • Templating
  • Reusable controls
So... essentially it does everything that Knockout and Backbone do, and then some.

So enough of that, let's get to some code.

Here is the basic code required to do something simple. In this case, I've made a little "Hello World" app that allows the user to reverse the name with a click.

/* Declare your main module.
 * this is your angular application module*/
var app = angular.module('myApp', []);

/* register a controller */
app.controller('MainCtrl', function($scope) {
  /* $scope is what is used for two-way binding */
  $scope.name = 'World';
  
  /* declare a method to call from a click in our markup */
  $scope.reverseName = function () {
    $scope.name = $scope.name.split('').reverse().join('');
  };
});

And here's the markup required:

<!doctype html>
<html ng-app="myApp" >
<head>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js"></script>
  <script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
  <p>
    <label>Name</label>
    <input type="text" ng-model="name"/>
    <button ng-click="reverseName()">Reverse</button>
  </p>
  Hello {{name}}!
</body>
</html>


Here's a demo to try that out. (I used Plnkr for this, I recommend Plnkr for playing with Angular over JSFiddle because it works a little better for Angular)



Pretty straight forward, I think. That sums up the basics, really. The VERY basic basics. I'll be showing a lot more features as time goes on, but this is a good starting point I think.

Fears of Angular's "Custom HTML Tags"


One of the primary complaints I read online from developers that really don't understand angular is over it's use of "non-standard HTML" for directives. I'll address that a little more when I post about directives and reusable controls, but I wanted to make it a point to say something in my first post about Angular on the matter: Angular actually only uses "non-standard" HTML tags as placeholders. Those placeholders are in fact replaced by Angular with standard HTML tags (presuming the author of the Angular app in question is writing valid HTML). More on that to come, but it's really not as scary as it looks, and it's so powerful, it's definitely worth a look.

Sunday, October 14, 2012

Validating A Custom Control in Angular JS with Angular's Built-In Validations

So I recently ran into an issue where I wanted to create a custom control that was basically two inputs that output to one piece of data. The issue was that sometimes it was required, and other times it wasn't, but I didn't want to require just one field or the other. I wanted the whole control to register as required. The control in question was a month/year date control, which is was a little complicated, logic-wise. So to illustrate the basic idea, I put together a quick plunker of the idea with a custom addition control.


Here are the basic steps to follow:
  1. Create a new directive.
  2. The directive must require: 'ngModel', this does most of the angular wiring for you.
  3. The link function of the model must do two things:
    1. Set a $watch on the item in the directive's scope you want to use as the control's value and use $setViewValue() to set the value of the view for ngModel.
    2. Set the $name for ngModel. This is used for validation purposes like myForm.fieldName.$error.required

Here is the directive for the custom addition control.

app.directive('blCustomSum', function(){
  return {
    restrict: 'E',
    require: 'ngModel', //important!
    template: 
      '<div>' + 
        'A <input ng-model="a" ng-change="add()"/> +  ' + 
        'B <input ng-model="b" ng-change="add()"/> = ' +
        '{{c}}' +
      '</div>',
    controller: function($scope) {
      // just a controller method to add the numbers
      // and set the value of c.
      $scope.add = function(){
        if(!isNaN($scope.a) && !isNaN($scope.b)) {
          $scope.c = parseFloat($scope.a) + parseFloat($scope.b);
        } else{
          $scope.c = '';
        }
      };
    },
    link: function(scope, elem, attr, ctrl) {
      // ctrl is what has been set up by the ngModel directive.
      // wire up c to be the value of ngModel for this control
      scope.$watch('c', function(value) {
        ctrl.$setViewValue(value);
      });
      // set the name for ngModel and validation.
      ctrl.$name = attr.name;
    }
  };
});


And here is an example of how to use it in template markup:

<body ng-controller="MainCtrl">
<form name="myForm">  
  <bl-custom-sum ng-model="sum" name="sum" required></bl-custom-sum><br/>
  <span ng-show="myForm.sum.$error.required">required</span><br/>
  form valid: {{myForm.$valid}}
</form>
</body>