Integrating AngularJS in a Tight Spot

Another title for this post might have been “Using AngularJS with ASP.NET Update Panels” as that was the circumstance I found myself in. However, the method of manually bootstrapping AngularJS framework applies to just about any tight spot you would like to fit in the framework.

The first question you’re asking is “what the heck are you doing integrating AngularJS into Web Forms with Update Panels”. Well, the answer is that sometimes legacy code and libraries cannot be so easily disregarded. In my case, I was attempting to retrofit and use AngularJS JavaScript Library in a section of my code after the Update Panel had finished updating. While I am in a legacy application, I still want to use the latest and greatest if I can.

Bootstrapping Angular

The first problem I ran into with this integration was that all my angular markup and content was simply not present on the page on first load. The content itself would show up dynamically after a partial post from the Update Panel. This meant that the default bootstrapping process of Angular will not run as no “ng-app” or HTML is even available to run, and it automatically will not initialize when the update panel adds “ng-app” from the server post. So what to do?

AngularJS actually provides just the thing for this situation, with a special “bootstrapping” method:

http://docs.angularjs.org/api/angular.bootstrap

Yay, for Angular. With this method, I can manually initialize AngularJS in any tricky situation I may find myself in for legacy code. With the scope usage of ng-app as well, I can use Angular on a specific portion of the page only! So to use the bootstrap event, the biggest challenge is finding a spot to make the initialization request. In my scenario, I need to bootstrap right after the partial post returns. I am using a framework that wraps the update panel so I already have an event as follows:

pic1 

However, this would just as easily work by hooking into the Page Request Manager like the following:

 pic2

In this example, I declare my application module (as “program”). Then call the bootstrapping angular function and pass in the HTML element that is to represent your ng-app (no need to declare ng-app anywhere in your markup, this takes over for that). In my example, I then pass in my program module, which has reference to all the controllers used in that application. All should work normally from here on out.

Integrating Non-Angular Components

The second main item to deal with in integrating AngularJS for usage with server side components (or other non-angularized components) is how to handle DOM manipulation and other javascript events since you should not be touching the DOM manually from your controller, and you didn’t create the markup that got injected onto the page. In my scenario, I had several server side controls from ASP.NET injecting some ugly markup. To handle it, I used a directive as a proxy, and put any ugly gluing code in the directive.

For my scenario, I had server side Html Table Generator. So, I created a new directive and added the directive to a div wrapper around the control:

 pic3

In the above example, you can see the directive as “clickable-table”. This directive takes an attribute argument of “row-click” which is a function that will get called whenever the user clicks on a row in the table. The messy manual manipulation and jQuery usage remains within the directive, and your controller remains clean:

 pic4

This is a simple example, but you can see how to easily extend it from here. Keep in mind if you end up inside a JQuery event to bring the Angular Scope back into context by manually wrapping the “rowClick” event in a scope.$apply.

4 Comments

  1. Chris says:

    Very nice post. I normally work in MVC, but am converting a Web Forms project from VB to C#, and I am wondering about using your method for solving at least one of the issues (Typeahead) outlined in my ASP.NET forum post:

    http://forums.asp.net/p/1992260/5717872.aspx?p=True&t=635385503111550378&pagenum=1

    Lack of code generation control is what has kept me away from Web Forms.

    Any thoughts?

    • travis says:

      You would only need to bootstrap the AngularJS Framework in the method described above if its going to be reset in relation to an update panel or some other dynamic DOM elements. In my scenario, every time a particular button was hit, it would use an update panel to reload 60% of the page. Every time that reload occured, the page request manager would trigger the bootstrapping routine. If your web forms page is loading up and then fairly static throughout its lifecycle, then likely bootstrapping it manually would not be required.

      Another reason you may want to programmatically bootstrap Angular would be if you don’t have access to the markup itself that you want to initialize your module onto.

      In terms of solving your issue on the typeahead control, looks like some good feedback as already been provided!

  2. Serban says:

    Thanks Travis,
    You saved me the time of having to figure this out all by myself.

  3. Guy Segev says:

    Thanks!
    I searched for an answer for 3 days…
    I also have an old ASP.NET application with update panel, that is now hosted in an iframe (and the iframe is inside an Angular page).

    If the module is already loaded in a js file, this will be enough:
    angular.bootstrap($(‘.myDiv’), [‘myNgModule’]);

    Without this first line:
    angular.module(myNgModule, []);