Recipes: how to listen to DOM insertions

The technique described here (more details in there):

http://davidwalsh.name/detect-node-insertion

It basically involves putting a CSS animation to the elements that will be attached in the future. When they get inserted, they run the animation, and when the animation finish running, it throws an “animationstarts” event.

The last part involves attaching a listener to the parent DOM, so when the CSS animation thrown the event, it is catch and processed there:

parentEl.addEventListener("animationstart", insertListener, false); // standard + firefox

You could also use the ‘DOMNodeInserted’ event, but it will be deprecated:

currentBox.bind(‘DOMNodeInserted’, function(e){
currentBox.find(‘object’).attr(‘width’, currentBox.width()).attr(‘height’, currentBox.height());
});

Angular.js: the basics

$scope

$scope is what connects views and controllers.

Most logic goes in the controllers. Controllers shouldn’t know what view they are operating on, their job is to produce a $scope (to keep dependencies light)

The $scope can be considered a “quasi model”, it is the pure data variables and data objects that binds both the view and the controller.

Example (defining the controller, and then applying the variables in the view):

<script type=”text/javascript”>
function MyController($scope) {

$scope.musicList = [
{ title: ‘With or without you’, artist: ‘U2’ },
{ title: ‘Two princes’, artist: ‘Spin Doctor’ }
];

}
</script>
<div class=”container” ng-controller=”myController”>
<ul>
<li ng-repeat=”song in musicList”>{{song.title}} by {{song.artist}}</li>
</ul>
</div>

Note that each li will create it’s own internal $scope, but inherit from the parent $scope controller. Angular apps mirror the DOM in regards to parent DOM elements inheriting values down to their children elements.

Application flow

Routers take the URL from the browser, and call an specific controller. The controller will have the logic to handle the URL request, and pass the data to the corresponding view, via the $scope.

Controllers don’t do it all, usually they delegate work to services, factories, providers, or resources.

View also don’t do a lot on their own, they rely on directives and filters to make the DOM dance.

So, in summary: routes calls controllers, which in turn call services, factories, etc to complete tasks, and then load the final result into the $scope. Views take over from there.

Code organization

It’s always a good idea to encapsulate stuff in modules. The start line to do so in angular is:

var myApp = angular.module(‘myApp’, [ ‘someOtherModuleHere’ ]);

someOtherModuleHere is optional, you can chain any other helper modules you need here for your ‘myApp’ module. Kind of the requireJS of angular.

So now that you have your myApp module namespaced, you can start attaching controllers to it:

myApp.controller(‘MyMusicController’, function ($scope) {

$scope.musicList = [
{ title: ‘With or without you’, artist: ‘U2’ },
{ title: ‘Two princes’, artist: ‘Spin Doctor’ }
];

});

So now, the way to put that controller to use, is to mark what DOM element of the HTML will be controlled by it, by means of the ng-controller directive:

<html ng-app=”myApp”>

<div ng-controller=”myMusicCtrl“>

<!— everything here will have access (and be binded) to the variables defined in $scope –>

</div>

By convention, you usually name your controllers [something]Ctrl. Each controller can support multiple views, so it can be used to get things synched. A view can also hold more than one controller.

This is how you declare it:

myApp.controller("dayCtrl", function ( $scope) {

Regarding code organization, it is better to keep everything separate. Usually you put the kickstarterd of the application on app.js (defining the namespace and the routers), and then controllers and services in their own space (for definition of services, see factories / services below). They can be tested separately, and called for different controllers this way, in a more modular fashion.

 Defining routes

Since angular 1.2, router functionality exist separate from the angular library itself, you would need to download separately from:

https://github.com/angular-ui/ui-router

Using config, you can define what URLs load what templates:

demoApp.config(function ($routeProvider) {
$routeProvider
.when(‘/’,
{
controller: ‘myMusicController’,
templateUrl: ‘View1.html’
})
.when(‘/someURL’,
{
controller: ‘anotherController’,
templateUrl: ‘View2.html’
}).
otherwise({ redirectTo: ‘/’ });

The html files that are being called out are off the root directory, but you can organize them in folders.

The app page has a “ng-view” container, that will automatically receive the template specified in the URL via the router above, the way that part is setup in the page is via a simple tag:

<div class=”container”>
<ng-view><!– the templates will dump their content here –></ng-view>
</div>

 Click events

They are handled in the view files via the ng-click directive, example:

<button ng-click=”doSomething()”>Click me</button>

And, inside the controller:

$scope.doSomething = function () {
// Things happening inside here
}

Reading form fields
It is also done via the $scope:
var localVarInsideController = $scope.objectName.objectVariable;
And in your view:

<input type=”text” data-ng-model=”objectName.objectVariable” />

Now the var localVarInsideController in your controller, and the input field in your view are binded.

To validate, you can add the following to the fields:

ng-disabled=“addForm.$invalid”

where addForms is the name=”addForms” attribute in your <form> tag. And then, in your input fields you mark ones required as:

<input type=“text” id=“name” class=“form-control” ng-model=“contact.name” required>

You can find some examples here

Data providers

In order to keep those modular and reusable, angular has some predefined objects for them. They all do sort of the same work, just in a different way:

1) Factories: creates a closure of methods and variables, which runs once, and expose certain methods so code can deal with its functionality. It is pretty much the thing you would usually do to envelop an object into a closure, with public and private methods.

This is an example of a factory that returns one value:

.factory('demoService', function demoServiceFactory(){
  return 'abc123';
});

In reality, factories are better off returning functions with methods instead of plain data.

2) Service: provides the functionality needed to create the data. Usually in the form of “this.someFunction = [anonymous function here] inside your controller. They are usually singletons that are accesible throughout the application, using the same data. The simplest form is creating constants via:

.value('demoService', 'abc123');

and then you can inject that service anywhere you need that value, like:

.controller('indexCtl', function($scope, demoService){
    $scope.demo = demoService;
});

3) provider: you define a $get inside of it that will contain the data to be returned. They can call other services to build upon.

Example of creating a factory for our app:

myApp.factory(‘simpleFactory’, function ($http) {

// In this case, we injected $http so we can call the data from backend

}

4) Directive: enclose functionality, the equivalent of web components. Example of setting one up:

myApp.directive(“highlight”, function () {
    returnfunction (scope, element, attrs) {
        if (scope.day == attrs[“highlight”]) {
            element.css(“color”, “red”);
        }
    }
});

You pass a factory function, so each time the directive gets called from the HTML, a copy of that factory function gets run (usually called a “worker”). Notice the $scope is passed via “scope” (without the $), element is the HTML element the directive was applied to (wrap in a jquery like object), and the attrs are the set of attributes on that element, including the directive one.

 Angular philosophy regarding UI architecture   

Angular === imperative! Meaning you build your static HTML as normal, and then you add directives to add the dynamic parts, and all the other fun event driven stuff on top of it

$rootScope

this is a global space in your app, that could be used to share data between components. To attach vars to it you could use something like

.controller('indexCtl', function($scope, $rootScope){
    $rootScope.contacts = [your array here...

and then call it on your views via:

<tr ng-repeat="contact in $root.contacts">

using global scope variables is a bad practice in general, use it sparingly

loose ends

Get a hold of angular elements from third party javascript code:

angular.element(document.getElementById(‘yourElement’)).scope().yourFunctionInsideThe$scopeVar();

ng-non-bindable // Use it to indicate an area of your HTML where you don't want the {{}} to be translated to a request for binding

Use $routeParams if you are using ngRoute, if you are using ui-router, use $stateParams instead