46

我一直在做一个更像框架的项目,并且有几个可以安装的应用程序/模块。将其视为基本的应用商店或 google.play 商店。它是一种内部网应用程序,所有模块都可以添加到您的用户帐户中。

该框架已经在开发中,但我现在正在考虑应用程序/模块的想法。(链接到开发中的概念证明,可以在这里找到

应用程序应该有点独立,并且不能突然包含框架中的脚本,这完全可以通过将它们构建在单独的模块中来实现,如下所示:

angular.module('myApp', []);

但是,一个应用程序可以有模板、脚本、css,它可以在单独的服务器上运行,所以我正在寻找获取脚本和 css 文件并将它们动态加载到应用程序中的最佳方法当用户app从框架内启动时。

  • 目前我正在构建应用程序,就好像它们有一个主模板一样www.framework.com/apps/myapp/views/app.html,为了简单起见,我将脚本捆绑到每个应用程序的 1 个脚本文件中,因此还有一个www.framework.com/apps/myapp/script.js要包含在内。

该框架包含一个加载应用程序的模板和一个appController. 该模板包含以下内容:

<div data-ng-controller="AppController" data-ng-include="app.appTemplate">
    <div>loading...</div>
</div>

这基本上绑定到$scope.app.appTemplate加载所有脚本时更新的,所以首先它显示一个加载模板,稍后在页面中包含脚本后,它更新app.appTemplate到上述应用程序的主模板。

在加载第一个索引模板时,这个模板当前是从框架加载的AppController,所以它使用的$scope是框架的而不是它自己的脚本。

我仍然必须以某种方式启动应用程序自己的角度模块,让它自己运行,而不在框架中运行任何东西来“让它工作”

我仍在研究如何最好地加载依赖的 javascript 文件(可能会使用 requrejs 或其他依赖加载器),但我目前不知道如何在不从框架内部工作的情况下“启动”应用程序AppController

编辑

我创建了一个小型演示项目来展示手头的问题,在 git-hub上可以看到完整的代码,目前这个项目做了一些硬编码的事情,我的想法是当我得到证明时我会减少那些硬编码正确的概念,现在都是关于在框架中加载应用程序。如果可能的话,我可以考虑从哪里获取 URL 和应用程序名称......

4

5 回答 5

37

您不能在另一个引导模块中引导模块。Bootstrapping 编译视图并将 rootScope 绑定到它,遍历 DOM 并设置范围绑定并一直执行指令链接函数。如果你这样做两次,你就会遇到问题。

你可能不得不重新考虑你的架构。我认为与 Angular 相关的“模块”或“应用程序”这个词可能是用词不当,会导致你走错路。

您的应用程序中的每个“用户安装的应用程序”都可能真正由您的应用程序模块中的控制器控制,或者注册到您的应用程序模块引用的模块。所以你不会“启动多个应用程序”,你实际上只是启动一个,引用其他模块,然后使用这些模块中的控制器来控制屏幕上的部分视图。

您要做的是在安装新的“小部件”时,向系统注册它的模块文件 (.js),其中将包含一个名为 WidgetCtrl 的控制器,然后当您的页面加载时,您将引用小部件的应用程序模块上的模块。从那里应该可以使用 ng-controller 和/或 ng-include 动态分配给元素。

我希望这是有道理的。

于 2013-08-19T15:00:31.773 回答
26

与当前接受的答案相反,实际上是可能的。

我正在研究类似的问题,建议的答案在我的情况下是不可接受的。我以前写过包含多个应用程序的页面,但那是几年前的事了,应用程序彼此独立。基本上有两件事要做:

  • 告诉主应用程序忽略子元素。
  • 引导子元素。

有一个ng-non-bindable属性,它只是告诉 AngularJS 忽略该元素。这解决了我们的第一个问题。

但是,当您尝试引导子元素时;AngularJS 会抛出一个错误,告诉你它已经被引导(至少对我来说,1.2.13 版)。以下技巧可以完成工作:

<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>

这个解决方案并不完美。理想情况下,ng-non-bindable 属性可以将所需的 data-$injector 属性添加到元素。我将制作一个功能,并希望对 AngularJS 提出拉取请求。


我没有机会提出拉取请求。显然,我应该说,一些内部结构发生了变化,但 ng-non-bindable 仍在使用 Ventzy Kunev 的演示代码在 1.3.13 版本中工作(再次感谢,请参见下面的链接)。

于 2014-03-05T15:57:19.797 回答
4

好吧,如果每个子应用程序都在自己的模块中,您可以使用 angular.bootstrap 动态加载该模块。当特定应用程序的 url 加载时,您可以获取必要的脚本,然后当 promise 解决时,您可以执行以下操作:

// 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']);

希望这可以帮助

于 2013-08-19T13:42:51.197 回答
3

与上面 UnicodeSnowman 的回答类似,另一个似乎可以满足我需求的潜在解决方案(我在文档站点上构建了一个实时 Angular 编辑器)是通过<div id="demos">与 main 分开来手动处理引导过程<div id="myApp">

这篇文章对于让它正常工作非常有帮助。

一般流程

  • 创建你的主应用程序(我选择手动引导,但你可以使用ng-app这部分)
  • 创建一个新的 HTML 结构/应用程序(在我的例子中是演示应用程序):
  • 使用自定义 id 将其附加到演示 div:someCoolDemoContainer
  • Boostrap 新创建的应用程序
  • 将其移回原始应用程序(用于布局/定位目的)

代码示例 (未测试;仅显示基本过程)

<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>
于 2015-05-07T16:41:04.457 回答
2

我知道这现在已经很老了,但我正在寻找一种将 AngularJS 应用程序嵌入到 Angular 应用程序中的方法,并使用这篇文章的答案来做到这一点,所以我想我会在这里为其他正在寻找的人发布 plunker类似的解决方案。

我发现有两种方法可以做到这一点,都在 Angular 组件的 ngOnInit 中使用手动引导 angularjs 应用程序:

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

在将被引导的元素上设置 ngNonBindable 属性:

<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>

或者将 angularjs 模板 html 注入到 Angular 组件内的 ngOnInit 事件处理程序的元素中,这样 Angular 就不会在编译期间尝试解释 AngularJS 代码(尤其是 DOM 中带有大括号的 AngularJS 属性的插值)。

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']);
}

Plunker在这里:

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

于 2018-05-01T10:09:09.250 回答