将在“n"上调用 angular.bootstrap多个DOM节点,实例化“n个"AngularJS应用程序? [英] Will invoking angular.bootstrap on "n" multiple DOM nodes, instantiate "n "AngularJS applications?

查看:19
本文介绍了将在“n"上调用 angular.bootstrap多个DOM节点,实例化“n个"AngularJS应用程序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

说调用 angular.bootstrap 会创建一个新的 AngularJS 实例,以及一个单独的摘要循环、根作用域、注入器等是否正确?

如果是这样,是否可以嵌套此类应用程序(即在由另一个 AngularJS 应用程序管理的 DOM 内的 DOM 节点上调用引导程序)?(我认为没有!)

解决方案

它将创建一个新的 Angular 实例 injector 服务,负责依赖注入并控制应用生命周期.因此,它还创建了应用程序中使用的服务的新实例(包括来自 ng 模块的那些:$rootScope, $compile等).

您可以将其视为应用程序的一个新实例(即模块的集合).Angular 本身(angular 对象)没有被实例化.

angular.bootstrapangular.injector(后者只是创建一个新的注入器实例)的不同之处在于它通过$rootElement<将注入器实例链接到DOM元素/代码>服务.这样这个元素及其子元素就与特定的注入器实例相关联(它可以通过 angular.element(someElement).injector() 获取).

不可能在引导元素(或其子元素)上引导应用程序,Angular 将保护它不被弄乱.

然而,Angular 并不是真的万无一失,它可以通过反向引导应用程序 来完成:

angular.bootstrap(nestedAppElement, ['nestedApp']);angular.bootstrap(appElement, ['app']);

看起来我们终于把事情搞砸了.没有什么可以阻止 app 中编译自己的指令,并且它使用自己的注入器和作用域(它是 app> 这里的根作用域)来编译它们,而不是属于当前 DOM 元素的作用域和注入器.如果嵌套应用程序将被某些父应用程序指令重新编译,事情会变得更加混乱.

绕过用于双重引导的 Angular 万无一失的绕过非常简单.由于 Angular 使用 inheritedData 以分层方式获取元素的注入器(当element.data('$injector') 在引导元素上未定义,它会自动从父元素中检索),它必须被覆盖:

angular.module('app').directive('nestedAppContainer', function () {返回 {编译:函数(元素){element.data('$injector', null);}};});

现在应用可以以任何顺序安全引导.但是让 app 远离 的问题仍然存在.可以通过将 nestedAppContainer 指令标记为终端

来解决

angular.module('app').directive('nestedAppContainer', function () {返回 {优先级:100000,终端:真的,...};});

或将嵌套应用程序放入shadow DOM

nestedAppContainer = nestedAppContainer.createShadowRoot();

专门用于隔离 DOM 部分(Chrome 原生支持,其他浏览器使用 polyfill).

<小时>

TL;DR:Angular 中嵌套应用的解决方案

因为它是 此处显示:

 <div app-dir><nested-app-container></nested-app-container>

var appElement = document.querySelector('body');var nestedAppContainer = document.querySelector('nested-app-container');//nestedAppContainer = nestedAppContainer.createShadowRoot();varnestedAppElement = angular.element('<nested-app>')[0];angular.element(nestedAppContainer).append(nestedAppElement);angular.element(nestedAppElement).append('<div app-dir>(app-dir)</div>').append('<divnested-app-dir>(nested-app-dir)</div>');angular.element().ready(function () {angular.bootstrap(appElement, ['app']);angular.bootstrap(nestedAppElement, ['nestedApp']);});angular.module('nestedApp', []).directive('nestedAppDir', function () {返回 {控制器:函数($scope){$scope.app = '嵌套应用';},编译:函数(元素){element.prepend('嵌套的应用程序是{{ app }}"');}}});angular.module('app', []).directive('appDir', function () {返回 {控制器:函数($scope){$scope.app = 'app';},编译:函数(元素){element.prepend('app is "{{ app }}"');}}});angular.module('app').directive('nestedAppContainer', function () {返回 {优先级:100000,//'terminal' 是多余的 NestedAppContainer.createShadowRoot()终端:真的,编译:函数(元素){//元素注入器不再是未定义",//所以它不会从父元素继承element.data('$injector', null);}};});

虽然它看起来很整洁,但请小心操作.与利用未记录内容的任何其他黑客一样,此黑客可能会隐藏不利的副作用或被新框架发布所破坏.

可能需要 hack 的案例并不多.大多数情况下,您有一种与框架抗争的冲动,但您做错了.

Is it correct to say that invoking angular.bootstrap will create a new instance of AngularJS, together with a separate digest cycle, root scope, injector and so on?

If so, is it possible to nest such applications (i.e. invoke bootstrap on DOM nodes inside the DOM managed by another AngularJS app)? (I presume no!)

解决方案

It will create a new instance of Angular injector service, which is responsible for dependency injection and controls application life cycle. Consequently, it also creates new instances of the services which are used in the application (including the ones from ng module: $rootScope, $compile, etc).

You may think of it as of a new instance of the application (which is the collection of modules). Angular itself (angular object) isn't instantiated.

The thing that differs angular.bootstrap from angular.injector (the latter just creates a new injector instance) is that it links an injector instance to DOM element by means of $rootElement service. This way this element and its children are associated with specific injector instance (it can be acquired with angular.element(someElement).injector()).

It is not possible to bootstrap an app on bootstrapped element (or its children), Angular will protect it from being messed up.

However, Angular is not really fool-proof, it can be done by bootstrapping the apps in reverse:

angular.bootstrap(nestedAppElement, ['nestedApp']);
angular.bootstrap(appElement, ['app']);

Looks like we finally messed the things up. Nothing prevents app from compiling its own directives in <nested-app-container>, and it uses its own injector and scope (it is app root scope here) to compile them, not scope and injector that belong to current DOM element. And the things will become even more messy if nested app will be re-compiled by some parent app directive.

Bypassing Angular fool-proof bypass for double bootstrapping is quite straightforward. Since Angular uses inheritedData to get element's injector in hierarchical manner (when element.data('$injector') is undefined on bootstrapped element, it is automatically retrieved from parents), it has to be overwritten:

angular.module('app').directive('nestedAppContainer', function () {
  return {
    compile: function (element) {
      element.data('$injector', null);
    }
  };
});

Now the apps can be safely bootstrapped in any order. But the problem with keeping app away from <nested-app-container> is still there. It can be solved either with marking nestedAppContainer directive as terminal

angular.module('app').directive('nestedAppContainer', function () {
  return {
    priority: 100000,
    terminal: true,
    ...
  };
});

or by putting nested app into shadow DOM

nestedAppContainer = nestedAppContainer.createShadowRoot();

which is specifically intended to isolate DOM parts (natively supported by Chrome and polyfilled in other browsers).


TL;DR: the solution to nested apps in Angular

As it is shown here:

  <body>
    <div app-dir>
      <nested-app-container></nested-app-container>
    </div>
  </body>

and

var appElement = document.querySelector('body');

var nestedAppContainer = document.querySelector('nested-app-container');
// nestedAppContainer = nestedAppContainer.createShadowRoot();

var nestedAppElement = angular.element('<nested-app>')[0];
angular.element(nestedAppContainer).append(nestedAppElement);

angular.element(nestedAppElement)
  .append('<div app-dir>(app-dir)</div>')
  .append('<div nested-app-dir>(nested-app-dir)</div>');

angular.element().ready(function () {
  angular.bootstrap(appElement, ['app']);
  angular.bootstrap(nestedAppElement, ['nestedApp']);
});

angular.module('nestedApp', []).directive('nestedAppDir', function () {
  return {
    controller: function ($scope) {
      $scope.app = 'nested app';
    },
    compile: function (element) {
      element.prepend('nested app is "{{ app }}"');
    }
  }
});

angular.module('app', []).directive('appDir', function () {
  return {
    controller: function ($scope) {
      $scope.app = 'app';
    },
    compile: function (element) {
      element.prepend('app is "{{ app }}"');
    }
  }
});

angular.module('app').directive('nestedAppContainer', function () {
  return {
    priority: 100000,
    // 'terminal' is redundant with nestedAppContainer.createShadowRoot()
    terminal: true,
    compile: function (element) {
      // element injector is not 'undefined' anymore,
      // so it won't be inherited from parent elements
      element.data('$injector', null);
    }
  };
});

While it may look quite neat, proceed with care. As any other hack that exploits undocumented stuff, this one may conceal adverse side-effects or be broken by new framework release.

There are not so many cases that may be in need of hacks. Most times you have an urge to fight the framework, you're doing it wrong.

这篇关于将在“n"上调用 angular.bootstrap多个DOM节点,实例化“n个"AngularJS应用程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆