最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Multiple Angularjs Applications (Driving Portlets) - Stack Overflow

programmeradmin3浏览0评论

I have a use case that requires the loading of separate angular applications.

Based on several stack overflow questions and this google thread, it's doable. However, I can't get it to work.

Looking at the documentation:

.bootstrap

It looks like you need to provide the element (what is the right way to get a handle on the element?), and then how to tie it back to config, controllers, etc. And how would this work with routes? IE how does collision work, ie app a and app b map /foo to /fooa.html and /foob.html respectively... or each app describes its own .otherwise?

Thanks!

I have a use case that requires the loading of separate angular applications.

Based on several stack overflow questions and this google thread, it's doable. However, I can't get it to work.

Looking at the documentation:

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

It looks like you need to provide the element (what is the right way to get a handle on the element?), and then how to tie it back to config, controllers, etc. And how would this work with routes? IE how does collision work, ie app a and app b map /foo to /fooa.html and /foob.html respectively... or each app describes its own .otherwise?

Thanks!

Share Improve this question edited Jun 5, 2013 at 22:46 Robert Christian asked May 24, 2013 at 0:00 Robert ChristianRobert Christian 18.3k20 gold badges76 silver badges90 bronze badges 4
  • Are these really two distinct applications or are they different routing paths/different views within one application. I ask because this is much talked about subject and has lead to the creation of a great alternative router github./angular-ui/ui-router which handles plex route and control flows. As well as parallel view sets through those route paths. – Paul Ryan Commented Jun 1, 2013 at 3:58
  • I'd be happy to walk you through how to use this for the case you present in your answer below. Unless your requirements are pletely about loading of the individual applications. – Paul Ryan Commented Jun 1, 2013 at 4:00
  • This is literally multiple apps. Imagine a SOA environment where services are deployed to varying hosts, each with a relatively simple angular UI app (for configuration of that particular service). And a centralizing application (think admin portal/system console) that knows about each one, and can dig into (run) its application without a redirect. Done this way, a service can be directly managed, and also managed via a master interface. – Robert Christian Commented Jun 1, 2013 at 4:43
  • Can these services live on different subviews? That is can they be viewed without the others but still have all the requirements listed? I'm envisioning an admin application that allows you to drill to the sub services subviews while maintaining a mon admin parent. I'm just not seeing a way to do this with a portal perspective until github./angular-ui/ui-router/issues/84 is fixed. I've started a portion of this fix at github./angular-ui/ui-router/pull/115. – Paul Ryan Commented Jun 1, 2013 at 6:15
Add a ment  | 

4 Answers 4

Reset to default 8 +100

So given the requirement that this be a service driven content the only way I can see to do this is kind of a mix between angular and standard html practices. Effectively you'll want to take a page from the plunker book and use Iframes to contain each individual portlet.

<!doctype html> <html lang="en">

<body ng-app="plunker" ng-controller="MainCtrl">

<!-- define foo -->

<div>
    <ul class="menu">
        <li><a href="#" ng-click="fooRoute='#/foo1'">foo1</a></li>
        <li><a href="#" ng-click="fooRoute='#/foo2'">foo2</a></li>
    </ul>
    <iframe seamless="true" ng-src="foo.index.html{{fooRoute}}"></iframe> </div>

<div>
    <ul class="menu">
        <li><a href="#" ng-click="barRoute='#/bar1'">bar1</a></li>
        <li><a href="#" ng-click="barRoute='#/bar2'">bar2</a></li>
    </ul>
    <iframe seamless="true" ng-src="bar.index.html{{barRoute}}"></iframe> </div>


<script src="https://ajax.googleapis./ajax/libs/angularjs/1.0.6/angular.min.js"></script> <script src="app.js"></script> </body> </html>

Then on each of these portlets you'll want to have a pletely separate application (including the loading of resources).

<!doctype html>
<html lang="en">

<body ng-app="fooApp">

<div ng-view></div>


<script src="https://ajax.googleapis./ajax/libs/angularjs/1.0.6/angular.min.js"></script>
<script>
  var app = angular.module('fooApp', ['fooApp.controllers']);

    // Configure the app
    app.config(['$routeProvider', function ($routeProvider) {
        $routeProvider.when('/foo1', {template: '<h1>Foo</h1><h2>foo1</h2>', controller: 'MyCtrl1'});
        $routeProvider.when('/foo2', {template: '<h1>Foo</h1><h2>foo2</h2>', controller: 'MyCtrl2'});
    }]);

    angular.module('fooApp.controllers', []).
            controller('MyCtrl1', [function () {
                console.log("fooApp.MyCtrl1 invoked.");
            }])
            .controller('MyCtrl2', [function () {
                console.log("fooApp.MyCtrl2 invoked.");
            }]);
</script>
</body>
</html>

This is a little less efficient for loading than utilizing a mon application base but at the moment this isn't feasible. There is talk at the angular-ui's ui-router team about controlling independent views which may be a workable solution for you but it is currently not implemented, you can follow the discussion at https://github./angular-ui/ui-router/issues/84 and chime in with your need. There is also now an issue specifically for this on the ui-router issues list at https://github./angular-ui/ui-router/issues/160.

Working plunker of this design: http://plnkr.co/edit/sPoK3I?p=preview

Ok so I figured out how to do this using the angular ui-router the key es down to the ability of the angular ui-router to transition states without effecting the URL.

The steps to get this working

  • First instantiate each application as a stand alone application using a manual bootstrap to an ID'd element.
  • Attach the ui-router $stateProvider to each application to drive the internal state transitions (routes).
    • You must leave off the url key here for each defined state or you'll reset the page by changing the url on each state transition.
  • Setup a state function in a main controller to drive state changes.

The following is the code to get this working:

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="[email protected]" src="http://code.angularjs/1.0.7/angular.min.js" data-semver="1.0.7"></script>
    <script src="angular-ui-states.min.js"></script>
    <script src="app.js"></script>
  </head>
<!-- define foo -->

<div id="fooApp" ng-controller="MainCtrl">

    <ul class="menu">
        <li><a href="#" ng-click="state('foo1')">foo1</a></li>
        <li><a href="#" ng-click="state('foo2')">foo2</a></li>
    </ul>
    <div ui-view>
    </div>

</div>

<script>
    // Declare app level module which depends on filters, and services
    var app = angular.module('fooApp', ['fooApp.controllers', 'ui.state']);

    // Configure the app
    app.config(['$stateProvider', function ($stateProvider) {
        $stateProvider
          .state('foo1',
          {
            template: '<h1>Foo</h1><h2>foo1</h2>', 
            controller: 'MyCtrl1'
          })
          .state('foo2',
          {
            template: '<h1>Foo</h1><h2>foo2</h2>', 
            controller: 'MyCtrl2'
          });
    }]);

    angular.module('fooApp.controllers', [])
            .controller('MainCtrl', ['$scope', '$state', function($scope, $state){
              $scope.state = function(name){
                console.log('Transition to state ' + name);
                $state.transitionTo(name);
              }
            }])
            .controller('MyCtrl1', [function () {
                console.log("fooApp.MyCtrl1 invoked.");
            }])
            .controller('MyCtrl2', [function () {
                console.log("fooApp.MyCtrl2 invoked.");
            }]);

    // manually bootstrap
    var div = document.getElementById('fooApp');
    console.log(div);
    angular.bootstrap(div, ['fooApp']);


</script>


<!-- define bar -->

<div id="barApp" ng-controller="MainCtrl">

    <ul class="menu">
        <li><a href="#" ng-click="state('bar1')">bar1</a></li>
        <li><a href="#" ng-click="state('bar2')">bar2</a></li>
    </ul>
    <div ui-view>
    </div>

</div>

<script>
    // Declare app level module which depends on filters, and services
    var app = angular.module('barApp', ['barApp.controllers', 'ui.state']);


    app.config(['$stateProvider', function ($stateProvider) {
        $stateProvider
          .state('bar1',
          {
            template: '<h1>Bar</h1><h2>bar1</h2>', 
            controller: 'MyCtrl1'
          })
          .state('bar2',
          {
            template: '<h1>Bar</h1><h2>bar2</h2>', 
            controller: 'MyCtrl2'
          });
    }]);

    angular.module('barApp.controllers', [])
            .controller('MainCtrl', ['$scope', '$state', function($scope, $state){
              $scope.state = function(name){
                console.log('Transition to state ' + name);
                $state.transitionTo(name);
              }
            }])
            .controller('MyCtrl1', [function () {
                console.log("barApp.MyCtrl1 invoked.");
            }])
            .controller('MyCtrl2', [function () {
                console.log("barApp.MyCtrl2 invoked.");
            }]);

    // manually bootstrap
    var div = document.getElementById('barApp');
    console.log(div);
    angular.bootstrap(div, ['barApp']);
</script>


</body>

</html>

Working plunker of this solution at http://plnkr.co/edit/bXSN8qSMdioZJLYs2zyk?p=preview

Please see my previous answer for a discussion currently occurring to make portlet support more intrinsic in the ui-router.

Figured it out. Here's how to successfully load two angular applications in parallel. Also see that I named the controllers the same for each app to show that dependencies will not collide (since they are scoped within each respective app via module):

<!doctype html>
<html lang="en">

<body>

<script src="lib/angular/angular.js"></script>

<!-- define foo -->

<div id="fooApp">

    <ul class="menu">
        <li><a href="#/foo1">foo1</a></li>
        <li><a href="#/foo2">foo2</a></li>
    </ul>
    <div ng-view>
    </div>

</div>

<script>
    // Declare app level module which depends on filters, and services
    var app = angular.module('fooApp', ['fooApp.controllers']);

    // Configure the app
    app.config(['$routeProvider', function ($routeProvider) {
        $routeProvider.when('/foo1', {template: '<h1>Foo</h1><h2>foo1</h2>', controller: 'MyCtrl1'});
        $routeProvider.when('/foo2', {template: '<h1>Foo</h1><h2>foo2</h2>', controller: 'MyCtrl2'});
    }]);

    angular.module('fooApp.controllers', []).
            controller('MyCtrl1', [function () {
                console.log("fooApp.MyCtrl1 invoked.");
            }])
            .controller('MyCtrl2', [function () {
                console.log("fooApp.MyCtrl2 invoked.");
            }]);

    // manually bootstrap
    var div = document.getElementById('fooApp');
    console.log(div);
    angular.bootstrap(div, ['fooApp']);


</script>


<!-- define bar -->

<div id="barApp">

    <ul class="menu">
        <li><a href="#/bar1">bar1</a></li>
        <li><a href="#/bar2">bar2</a></li>
    </ul>
    <div ng-view>
    </div>

</div>

<script>
    // Declare app level module which depends on filters, and services
    var app = angular.module('barApp', ['barApp.controllers']);

    // Configure the app
    app.config(['$routeProvider', function ($routeProvider) {
        $routeProvider.when('/bar1', {template: '<h1>Bar</h1><h2>bar1</h2>', controller: 'MyCtrl1'});
        $routeProvider.when('/bar2', {template: '<h1>Bar</h1><h2>bar2</h2>', controller: 'MyCtrl2'});
    }]);

    angular.module('barApp.controllers', []).
            controller('MyCtrl1', [function () {
                console.log("barApp.MyCtrl1 invoked.");
            }])
            .controller('MyCtrl2', [function () {
                console.log("barApp.MyCtrl2 invoked.");
            }]);


    // manually bootstrap
    var div = document.getElementById('barApp');
    console.log(div);
    angular.bootstrap(div, ['barApp']);
</script>


</body>

</html>

The only remaining question is how to deal with routing collisions.

Well you have 2 choices here: if you create them as angular.module() there would not be a way atm to connect the modules with each other.

if you create directives with a templateURL to lazyload your ponents you could broadcast shared attributes and listen to them and you could use the same services in your app. Probably that would be the best for you.

发布评论

评论列表(0)

  1. 暂无评论