2015年11月18日 星期三

How to Include AngularJS On Your Existing Website

Angular is a great framework for building Single Page Applications (SPA), especially if you're starting a new project from scratch. Often times, however, we are working with an existing codebase that may have been around for years. In this post I'll describe how we can take advantage of Angular in an existing non-Angular project.

Easy Mode

Angular allows you to specify which part of the DOM it should be managing with the ng-app directive. So one of the easiest ways to Angularize part of the page is to add the ng-app attribute to a top-level DOM element that you want managed by Angular:
1<div>
2  <p>This paragraph is not managed by Angular.</p>
3  <div ng-app>
4    <p>This paragraph is managed by Angular.</p>
5  </div>
6</div>
Most likely you'll need a controller, so specify one via the ng-controller attribute. Note: most likely your app won't play nicely with angular routes, so using the $routeProvider service along with ng-view is not going to be a good idea. Keep it simple and assign a controller manually any of the elements under your ng-app element:
1<div>
2  <p>This paragraph is not managed by Angular.</p>
3  <div ng-app>
4    <p>This paragraph is managed by Angular.</p>
5    <div ng-controller="MyController">
6      <p>This paragraph is managed by Angular and its scope is tied to the MyController controller.</p>
7    </div>
8  </div>
9</div>
At this point, you are now ready to code up MyController:
1function MyController($scope) {
2  // controller logic goes here
3}

Modularizing your Angular Code

Once your app starts to grow in complexity, you may benefit from using Angular modules. To use modules with an existing website, simple specify the module you want to load using the ng-appattribute:
1<div>
2  <p>This paragraph is not managed by Angular.</p>
3  <div ng-app="CoolModule">
4    <p>This paragraph is managed by Angular.</p>
5    <div ng-controller="MyController">
6      <p>This paragraph is managed by Angular and its scope is tied to the MyController controller.</p>
7    </div>
8  </div>
9</div>
In JavaScript, you can wire up your module like this:
1var module = angular.module('CoolModule', []);
2module.controller('MyController'function($scope) {
3  // controller logic goes here
4});

Advanced Angularizations

Sometimes you won't want to load the angular module immediately on page load. For example, if you have a tabbed interface and one of the tabs needs to be powered by Angular, then you might not want to run any of the Angular code until that tab is selected. To do that, you'll need to fire up your favorite JavaScript editor and manually bootstrap your Angular module when the tab is selected.
To demonstrate this, let's assume a simple tabbed interface where the first tab (non-Angular) is shown by default and the second tab needs to be powered by Angular. A simple jQuery implementation might look something like this:
01<ul class="tabs">
02  <li id="tab1">Tab 1 (non-Angular)</li>
03  <li id="tab2">Tab 2 (Angular)</li>
04</ul>
05<div class="tab" rel="tab1">
06  Some non-Angular stuff
07</div>
08<div class="tab" rel="tab2">
09  Some Angular stuff
10</div>
11 
12<script>
13$('div.tab').hide(0);
14$('ul.tabs > li').click(function(event) {
15  var id = $(this).attr('id');
16  $('div.tab:visible').hide(0);
17  $('div[rel="' + id + '"]).show();
18}).eq(0).click();
19</script>
With this code, we have a basic working tabbed interface but tab2 is not managed by Angular like it should. To Angularize tab2 and only when it's selected, the code above can be updated like this:
01<ul class="tabs">
02  <li id="tab1">Tab 1 (non-Angular)</li>
03  <li id="tab2">Tab 2 (Angular)</li>
04</ul>
05<div class="tab" rel="tab1">
06  Some non-Angular stuff
07</div>
08<div class="tab" rel="tab2">
09  <div ng-controller="MyController">
10    Some Angular stuff
11  </div>
12</div>
13 
14<script>
15$('div.tab').hide(0);
16$('ul.tabs > li').click(function(event) {
17  var id = $(this).attr('id');
18  $('div.tab:visible').hide(0);
19  $('div.tab[rel="' + id + '"]).show();
20 
21  // Angularize the tab if tab2 was clicked
22  if ('tab2' === id') {
23    var $tab = $('div.tab[rel="tab2"]');
24    // Only bootstrap this tab if it has not already been bootstrapped
25    if (!$tab.hasClass('ng-scope')) {
26      angular.bootstrap($tab[0], ['coolModule']);
27    }
28}).eq(0).click();
29</script>
The main changes include:
  • Add a child DIV with an ng-controller attribute to bind it with an Angular controller
  • Manually bootstrap the div via angular.bootstrap(). This method accepts a DOM node and an array of Angular modules as arguments.
  • Add logic to only bootstrap the DIV once. We can take advantage of the fact that Angular adds the class ng-scope to the element after it is bootstrapped, so we need only check the presence of this class to determine if we need to bootstrap the element.

Communicating with Angular apps from outside of Angular code

Sometimes you'll need to hint to Angular to enter a digest phase from your non-Angular code. If you are within Angular code, you can always use $scope.$apply() or $rootScope.$apply(), but how do you get access to those variables from outside of Angular code?
To get access to the $scope, simple call angular.element() and pass in the element that has your ng-controller attribute. That will return an object with a scope() method, which will return the $scopefor that element:
1var elem = $('div[ng-controller]')[0];
2var $scope = angular.element(elem).scope();
3$scope.$apply();
To get the $rootScope, you can use the same technique, but this time pass in the element that has your ng-app attribute:
1var elem = $('div[ng-app]')[0];
2var $rootScope = angular.element(elem).scope();
3$rootScope.$apply();

Conclusion

Angular isn't just for fresh new green field projects. You can easily introduce your existing website to Angular and take advantage of all its two-way binding, clear separation of concerns, and declarative markup one section at a time.

reference : http://www.virgentech.com/blog/2013/08/how-to-include-angularjs-on-your-existing-website.html

沒有留言:

wibiya widget