简体   繁体   中英

Embedding AngularJS in existing jquery/bootstrap based website

We've got an existing application where the client-side is jQuery / Bootstrap. It consists of many tabs where each tab is defined in a module imported via. require.js. The tab javascript is handed a parent DOM element and is in charge of drawing itself inside of that element.

We'd like to start building new functionality (tabs) in AngularJS and running into some problems doing that.

My thinking is that we could tag the body with ng-app and in the main page code conjur up an app module window.app = angular.module('ourApp', []); and later, as tabs are loaded, create and wire-up the controllers.

I've built a simple single-page example that exhibits the problem we are having (below or here http://jsfiddle.net/p4v3G/1/ ).

The only way I've been able to get the example to work is manually calling angular.bootstrap which I'm pretty sure is wrong. Also, that only works the first time so if I click the button twice (equivalent to navigating to the tab, away from it, and back again within our app), Angular isn't wired up properly.

I'd appreciate any help.

<body ng-app='testApp'>
    <div id="main" style="border: 1px solid #000; background: #ffdddd;">Click button to replace template and wire up controller...</div>
    <button id="button1">Load</button>
    <script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.14/angular.min.js"></script>
    <script>
        var app = angular.module('testApp', []);
        jQuery(function() {
            $("button").click(function() {
                // controllers are wired up in click handler to simulate environment where we
                // are looking to embed angular inside of an existing bootstrap/jquery application 
                // where new tabs (loaded as separate modules through require) are loaded on-demand.
                app.controller('TestController', function($scope) {
                    $scope.message = 'Hello World, from Controller #1';
                });

                $("#main").html('<div ng-controller="TestController">{{message}}</div>');

                // Bootstrap works the first click but not subsequent clicks
                angular.bootstrap(document, ['testApp']);
            });
        });
    </script>
</body>

To chunk up your appliation so that only the relevant parts are instantiated etc. what you need is angular ui-router . You would then set up a parent state for your tab-control with child states for each of your tabs. That way you both get deep linking and the performance you want with loading only the relevant tab.

As for requirejs, I encourage you to firstly consider if you really need it. In my opinion the javascript making up an angular application is usually much terser than a jquery application due to the declarative nature of the technology. Therefore loading all of the javascript at boot-time is ok. Your templates however may not be as simple, but by using templateUri references to templates they may be loaded as needed. (Personally I prefer compiling them to javascript and placing them in the $templateCahce at the cost of boot-time, but that's another matter.)

That being said, if my observations do not hold for your scenario/application/codebase, then others have had great success incorporating requirejs with angularjs. For a nice introductory talk on that subject see this nice ng-conf video .

Best of luck!

Could you be more precise, what type of errors appears. You don't need use jquery. Check this code and compare http://jsfiddle.net/pokaxperia/3w6pb/1/

HTML

<body ng-app='testApp'>
    <div ng-controller="TestController">    
        <span id="main" style="border: 1px solid #000; background: #ffdddd;">{{message}}</span>
        <button ng-click="loadMessage();" id="button1">Load</button>
    </div>   
    <script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
</body>

script

var app = angular.module('testApp', []);
app.controller('TestController', ['$scope',function($scope) {
    $scope.message = "Click button to replace template and wire up controller...";
    $scope.loadMessage = function(){
        $scope.message = 'Hello World, from Controller #1';
    };
}]);

Or check your code on jsfiddle, but with few variants http://plnkr.co/edit/fUQDpO?p=preview

HTML

<body>
    <example-tabs></example-tabs>
    <div class="panel" ng-show="isSelected(1)">Panel One</div>
    <div class="panel" ng-show="isSelected(2)">Panel Two</div>
    <div class="panel" ng-show="isSelected(3)">Panel Three</div>
</body>

Main script:

var app = angular.module('tabsExample', ['tabDirectives']);

Directive to load Tabs

var app = angular.module('tabDirectives', []);
app.directive('exampleTabs', [
  function() {
    return {
      restrict: 'E',
      templateUrl: 'example-tabs.html',
      controller: function($scope) {
        $scope.tab = 1;
        $scope.selectedTab = function(setTab) {
          $scope.tab = setTab;
        };
        $scope.isSelected = function(checkTab) {
          return $scope.tab === checkTab;
        };
      }
    };
  }
]);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM