AngularJS: How to nest applications within an angular app

后端 未结 5 1923
梦毁少年i
梦毁少年i 2020-12-02 09:50

i\'ve been working on a project that is more like a framework, and has several apps / modules you can install. See it like a basic appstore or google.play store. It\'s sort

相关标签:
5条回答
  • 2020-12-02 10:16

    well if each sub-app is in its own module, you can just use angular.bootstrap to load that module dynamically. when the url for a specific app loads, you can fetch the necessary script(s), then when the promise resolves, you can do something along the lines of:

    // grab a reference to the element where you'll be loading the sub-app
    var subapp = document.getElementById('subapp-id');
    
    // assuming the script you get back contains an angular module declaration named
    // 'subapp', manually start the sub-app
    angular.bootstrap(angular.element(subapp), ['subapp']);
    

    hope this helps

    0 讨论(0)
  • 2020-12-02 10:23

    I know this is quite old now but I was looking for a way to embed an AngularJS app within an Angular app and used the answers from this post to do just that so I thought I'd post up the plunker here for anyone else looking for a similar solution.

    There were two ways that I found to do it, both used manual bootstrapping of the angularjs app within the ngOnInit of an Angular component:

    ngOnInit(): void {
      // manually bootstrap the angularjs app
      angular.bootstrap(document.getElementById('ngListApp'), ['list-app']);
    }
    

    Either set the ngNonBindable attribute on the element that will be bootstrapped:

    <div ngNonBindable #insert>
      <!-- can insert the angular js template directly here, inside non-bindable element -->
      <div id="ngListApp" ng-controller="ListController as list">
        <input ng-model="inputValue" />
        <ul>
          <li ng-repeat="item in items">{{ item }}</li>
        </ul>
      </div>
    </div>
    

    Or inject the angularjs template html into the element in the ngOnInit event handler within an Angular component so that Angular doesn't try to interpret the AngularJS code (especially interpolation of AngularJS properties in the DOM with curly brackets) during compilation.

    ngOnInit(): void{
      // insert angularjs template html here
      this.div.nativeElement.innerHTML = this.htmlTemplate;
    
      // then manually bootstrap the angularjs app
      angular.bootstrap(document.getElementById('ngListApp'), ['list-app']);
    }
    

    The Plunker is here:

    http://plnkr.co/plunks/0qOJ6T8roKQyaSKI

    0 讨论(0)
  • 2020-12-02 10:24

    Similar to UnicodeSnowman's answer above, another potential solution that appears to be working for my needs (I built a live Angular editor on a documentation site) is to manually handle the bootstrap process by having a <div id="demos"> that is separate from the main <div id="myApp">.

    This article was very helpful to get it working correctly.

    General Process

    • Create your main app (I chose to manually bootstrap, but you may be able to use ng-app for this part)
    • Create a new HTML structure/app (in my case the demo app):
    • Append it to the demos div with a custom id: someCoolDemoContainer
    • Boostrap the newly created app
    • Move it back into the original app (for layout/positioning purposes)

    Code Example (not tested; just shows basic process)

    <div id="myApp">
        <h1>Demo</h1>
    
        <p>Click the button below to checkout the cool demo!</p>
    
        <button ng-click="showDemo()">Show Demo</button>
    
        <div class='insertion-point'></div>
    </div>
    
    <div id="demos">
    </div>
    
    <script type="text/javascript">
        /*
         * Init/bootstrap our main app
         */
        var appContainer = document.getElementById('myApp');
    
        angular.module('myApp', ['myDependency']);
        angular.bootstrap(appContainer, ['myApp']);
    
        // Do lots of other things like adding controllers/models/etc.
    
        /*
         * Init/bootstrap our demo app when the user clicks a button
         */
        function showDemo() {
          // Append our demo code
          $('#demos').append('<div id="someCoolDemoContainer">Angular app code goes here</div>');
    
          // Bootstrap the new app
          var demoContainer = document.getElementById('someCoolDemoContainer');
          angular.module('someCoolDemo', ['myDependency']);
          angular.module('someCoolDemo').controller('myController', function() { ... });
    
          angular.bootstrap(demoContainer, ['someCoolDemo']);
    
          // Re-insert it back into the DOM where you want it
          $('#myApp').find('.insertion-point').append($('#someCoolDemoContainer'));
        }
    </script>
    
    0 讨论(0)
  • 2020-12-02 10:35

    You can't bootstrap a module inside another bootstrapped module. Bootstrapping compiles the view and binds a rootScope to it, traversing it's way through the DOM and setting up scope bindings and executing directive linking functions all the way through. If you do that twice, you're going to run into problems.

    You're probably going to have to rethink your architecture. I think perhaps the word "module" or "app" as it pertains to Angular is a misnomer and is leading you down the wrong path.

    Each "user installed app" in your application should probably really be controlled by a controller in your app module, or registered to a module referenced by your app module. So you wouldn't be "starting up multiple apps", you'd really just be starting one, referencing the other modules, then using Controllers from those modules to control parts of your view on the screen.

    What you'd do is when a new "widget" was installed, you're register it's module file (.js) with the system, which would contain a controller named WidgetCtrl, then when your page loaded, you'd reference the widget's module on your app module. From there it should be available for dynamic assignment to elements using ng-controller and/or ng-include.

    I hope that makes sense.

    0 讨论(0)
  • 2020-12-02 10:41

    Contrary to currently accepted answer, It is actually possible.

    I was working on a similar problem and suggested answer was not acceptable in my case. I had previously written pages with multiple applications but it was years ago and apps were independent of each other. There are two things to do basically:

    • Tell main application to ignore a child element.
    • Bootstrap the child element.

    There is an ng-non-bindable attribute which simply tells AngularJS to ignore the element. This handles our first problem.

    However when you try to bootstrap the child element; AngularJS will throw an error, telling you that it is already bootstrapped (at least to me, version 1.2.13). Following trick does the job:

    <div ng-non-bindable data-$injector="">
      <div id="bootstrap-me">
        <script src="/path/to/app.js"></script>
        <div ng-include="'/path/to/app.html'"/>
      </div>
    </div>
    

    This solution is not perfect. Ideally, ng-non-bindable attribute can add required data-$injector attribute to element. I am going to make a feature and hopefully a pull request to AngularJS.


    I did not have the chance to make a pull request. Apparently and expectedly I should say, some internals have changed but ng-non-bindable is still working at version 1.3.13 using Ventzy Kunev's demo code (thanks again, see link below).

    0 讨论(0)
提交回复
热议问题