AngularJS tips and tricks

AngularJS logo
Are you working with AngularJS? Have you tried using the “documentation”? Have you banged your head into your keyboard trying to find out how seemingly simple methods works?

Yeah, I’ve been there. My trip into AngularJS has been filled with obstacles and trying to learn AngularJS from scratch is – in my humble opinion – very difficult. I find that AngularJS has a very steep learning curve and it’s probably mostly due to the fact that I’m not used to working with a Model-View framework. That being said, the documentation is not very user-friendly, and you find yourself using Google to look up examples and forum posts! I owe the community a lot for providing me with the necessary insight.

On this page I will try to sum up some of the things that I found was difficult to grasp. It is primarily for my own understanding and reference – I’m glad if you can use it also.

I will be adding to the page whenever I make new discoveries.

Remember to apply changes

In my attempt to create an app that utilizes IndexedDB, I quickly ran into the problem of asynchronous updates. My AngularJS-app would render all controls long before my queries was done. The result: no data!

Normally, AngularJS is able to watch variables for any changes. But not if the changes are being made in code outside of your controllers. Therefore, you have to tell AngularJS that changes have been made. You do this by using the following command:

$rootScope.$apply();

Of course, you can also just use $scope.$apply();

Import modules
In order to separate code, you can choose to put different modules into separate .js-files, and then import them into your app. This is done by using the following code:

var app = angular.module('mySuperDuperApp', ['NameOfExternalModule']);

and then in the external module, you write:

angular.module('NameOfExternalModule',[])

Remember to use ng-href instead of href
If you want to use AngularJS markup inside your links, you have to use ng-href instead of href. The reason is that it takes time for AngularJS to parse all HTML, and this means that if the user is quick he/she can click the link before it is actually parsed. This would result in a 404-page.

So, instead of writing this:

<a href="http://www.someurl.com/{{hash}}"/>

you should write this:

<a ng-href="http://www.someurl.com/{{hash}}"/>

Remember to use ng-src instead of src
This is similar to using ng-href instead of href. Whenever you insert images and want to use Angular-markup, you have to use ng-src. Just like this:

    <ul id="preview" ng-repeat="image in images">
        <li><img ng-src="{{image}}" /></li>
    </ul>

Use ng-show to show/hide elements
If you want HTML elements to be either hidden or shown based on some value or some function, you can use ng-show. An example would be:

<li ng-show="$route.current.params.ordernumber != null">

In the example above, the list-element will either be hidden or shown if the expression evaluates to either true or false.

Execute functions onload
Sometimes, you want to execute functions immediately when the app is loading. You can do this by inserting code like the following before the controllers are being executed:

var app = angular.module('mySuperDuperApp', ['SomeExternalModule']);

// Install database onload - config settings
app.run(function(globals, $rootScope) {
   // Your code here....

});

The app.run-function will execute immediately.

Execute global functions
Often you don’t want to execute functions immediately, but would like them to be available globally. You can do this by either storing functions in the rootScope or creating services. I normally prefer creating functions put in the rootScope because there’s less code to be written. 🙂

Functions in rootScope:

    var app = angular.module('mySuperDuperApp', ['SomeExternalModule']);

    // Your function
    app.run(function($rootScope) {
      $rootScope.fill = function(globals, serviceorders) {
      	// Your code here....

  		}
  	});

  	// call your function
  	$scope.fill(globals, serviceorders);

Services:

    var app = angular.module('mySuperDuperApp', ['SomeExternalModule']);
      app.service('acceptOrderService', function() {
      this.acceptorder = function($scope, globals, primarykey, callback) {
      	// Your code here....

    	}
    });

    // call your service
    acceptOrderService.acceptorder($scope, globals, $routeParams.ordernumber, function(status) {
        $location.path("/orderdetails/" + $routeParams.ordernumber);
        $scope.$apply();
    });

Global variables
Just as you create global functions, you can also create global variables. This is done by using code like the following:

    var app = angular.module('mySuperDuperApp', ['SomeExternalModule']);

    // Define global variables
    app.value('globals', {
            db : null,
            databasename : "serviceapp",
            table1 : "serviceorders",
            table2 : "photos",
            keypath1 : "primarykey",
            keypath2 : "data",
            index1 : "needsynchronization",
            index2 : "ordernumber",
            index3 : "timestamp",
            json_file : "/js/MobileServiceApp/data.json",
            db_version : 1,
            globalcounter : 0,
            loaded : false,
            serviceorders : {},
            hasdata : false,
            image_max_width: 620,
            image_max_height: 620,
            image_quality: 0.7
        }
    );

Avoid AngularJS escaping your HTML
Normally, AngularJS will escape HTML displaying e.g.

this is <br>escaped

To avoid this, you can use the following code:

<p ng-bind-html-unsafe=(article.content.IntroText)></p>

Of course, this ng-bind-html-unsafe can be used on all HTML-tags and also in ng-repeat.

Feeding values from backend to Angularjs
Sometimes, you need to send data from a backend-system to Angularjs. I know that the prober way of handling this is to load the data via a REST-interface, but sometimes this is just not possible. As in my case where I often need values coming directly from a CMS-product.

Here, you can use the ng-init method. You can see how in the following snippet. Here, I load an itemid into my AngularJS application. One important thing, though, is that if you want to make absolutely sure that your values are available for the controllers, you need to insert the ng-init BEFORE your ng-controller. Otherwise, you can’t be sure that the value will be available.

<div  class="container-fluid" id="article" ng-init="articleid= <!--@Item.Id-->">
	<div id="row-holder" ng-controller="ArticleCtrl">

After you have inserted this snippet, you can then access your value like this:

function ArticleCtrl($scope, mediaservice, $filter) {
    // Load videos related to the article - default
    mediaservice.preload($scope.articleid, $scope);
}

Does a form contain new data?
I needed to implement a functionality that would warn the user about changed data in a form when the user tried to navigate away from the form. Luckily, in AngularJS this is very easy. You just use the $dirty variable. Just like so:

  $scope.back = function($event, ConfirmBackText) {
    $event.preventDefault();
    if ($scope.mainform.$dirty) {
      if (confirm(ConfirmBackText)) {
        window.history.back();
      }
    } else {
      window.history.back();
    }
  };

Notice, that I check whether or not $scope.mainform.$dirty is true or false. If it is true, I pop the confirm dialogue.

That’s it for now. I will keep updating this blogpost whenever I discover new “features”. I hope that you can use it.

Advertisements

7 thoughts on “AngularJS tips and tricks

  1. Oh, and Peter, you saved the day for my AngularJS web app. I way trying to make my web app have settings sent through the URL Hash, so that people could bookmark the state of the image manipulating web app, and it did not work. Not until I read your first tip about $apply() ! Thanks Peter!
    Here is an example of a direct link to my web app: http://dl.dropbox.com/u/3260327/angular/CSS3ImageManipulation.html#/Greyscale=0/Sepia=69/Brightness=0.47/Saturation=100/Contrast=100/HueRotate=0/Invert=0/BorderRadius=50/BoxShadow=13/Rotate=0/Blur=0/ScaleX=1.01/ScaleY=1.01/Skew=0

    /Sten

  2. Pingback: JavaScript frameworks ~

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s