已经使用的角度在页面上的扩展采用了棱角分明 [英] Using Angular in extension on a page that already uses angular

查看:150
本文介绍了已经使用的角度在页面上的扩展采用了棱角分明的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在写一个Chrome扩展(这里)为的我的媒体库 href=\"http://www.github.com/kentcdodds/ux-genie\">其UI 。它可以在不使用角页伟大的,但它会导致问题和那些有棱角的页面。例如,角文档页面上:

I'm writing a Chrome Extension (here) for my library that uses angular for its UI. It works great on pages that don't use angular, but it causes issues with pages that do have angular. For example, on the Angular docs page:

Uncaught Error: [$injector:modulerr] Failed to instantiate module docsApp due to:
  Error: [$injector:nomod] Module 'docsApp' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
  http://errors.angularjs.org/1.2.7/$injector/nomod?p0=docsApp
at chrome-extension://cfgbockhpgdlmcdlcbfmflckllmdiljo/angular.js:78:14
at chrome-extension://cfgbockhpgdlmcdlcbfmflckllmdiljo/angular.js:1528:19
at ensure (chrome-extension://cfgbockhpgdlmcdlcbfmflckllmdiljo/angular.js:1453:40)
at module (chrome-extension://cfgbockhpgdlmcdlcbfmflckllmdiljo/angular.js:1526:16)
at chrome-extension://cfgbockhpgdlmcdlcbfmflckllmdiljo/angular.js:3616:24
at Array.forEach (native)
at forEach (chrome-extension://cfgbockhpgdlmcdlcbfmflckllmdiljo/angular.js:302:13)
at loadModules (chrome-extension://cfgbockhpgdlmcdlcbfmflckllmdiljo/angular.js:3610:7)
at createInjector (chrome-extension://cfgbockhpgdlmcdlcbfmflckllmdiljo/angular.js:3550:13)
at doBootstrap (chrome-extension://cfgbockhpgdlmcdlcbfmflckllmdiljo/angular.js:1298:22)
http://errors.angularjs.org/1.2.7/$injector/modulerr?p0=docsApp&p1=Error%3A…xtension%3A%2F%2Fcfgbockhpgdlmcdlcbfmflckllmdiljo%2Fangular.js%3A1298%3A22) angular.js:78

奇怪的是,它似乎发生延长我是否真的使用的角度或没有。所有我需要重现该问题是包括角度在我的manifest.json为 content_script 而这个错误被抛出。没有搞乱角部位的我怎么会做这项工作的任何想法将不胜AP preciated。

The weird thing is that it seems to happen whether my extension actually uses angular or not. All I need to reproduce the issue is to include angular in my manifest.json as a content_script and this error is thrown. Any ideas of how I could make this work without messing up an angular site would be greatly appreciated.

就像我说的,它不会不管我实际使用的角度还是不行,但是这是我做的使用它:

Like I said, it doesn't matter whether I actually use angular or not, but this is all I'm doing to use it:

makeWishForAnchors(); // This just loads the global genie object. I don't believe it's related.

var lamp = '<div class="genie-extension"><div ux-lamp lamp-visible="genieVisible" rub-class="visible" local-storage="true"></div></div>';
$('body').append(lamp);

angular.module('genie-extension', ['uxGenie']);
angular.bootstrap($('.genie-extension')[0], ['genie-extension']);

谢谢!

推荐答案

只要角被注入,它解析DOM寻找具有 NG-应用指令的元素。如果找到一个角度会自动引导。这将成为当一个页面使用角度本身就是一个问题,因为(他们虽然有不同的JS执行上下文)的页面和内容脚本共享相同的DOM。

The problem

As soon as Angular is injected, it parses the DOM looking for an element with the ng-app directive. If one is found Angular will bootstrap automatically. This becomes a problem when a page uses Angular itself, because (although they have separate JS execution contexts) the page and the content script share the same DOM.

您需要prevent的的角度实例(由您的我的意思是一个由您的分机作为一个内容脚本注入)自动自举。通常你会只是省略 NG-应用指令,你会好到哪里去,但因为你没有对原来的DOM控制(也不是你想打破页面的功能),这是不是一种选择。

You need to prevent your Angular instance (by "your" I mean the one injected by your extension as a content script) from automatically bootstrapping. Normally you would just omit the ng-app directive and you would be good to go, but since you do not have control over the original DOM (nor do you want to break the page's functionality) this is not an option.

您有什么做到这一点使用 手动引导 作为结合的角度与应用的 推迟引导 (适用于prevent您的角度,从尝试自动引导页面的角度应用)。

What you can do it use manual bootstrapping for your Angular app in conjunction with deferred bootstrapping (to prevent your Angular from trying to automatically bootstrap the page's Angular app).

同时,你需要保护(即隐藏)从页面的角度实例应用程序的根元素。要做到这一点,你可以在 ngNonBindable 指令,所以页面的折角实例将独自离开。

At the same time, you need to "protect" (i.e. hide) your app's root element from the page's Angular instance. To achieve this, you can wrap your root element in a parent element with the ngNonBindable directive, so the page's Angular instance will leave it alone.

总结从上面的文档中的步骤,你需要做到以下几点:

Summarizing the steps from the above docs, you need to do the following:


  1. prePEND window.name NG_DEFER_BOOTSTRAP!之前,您的注入角。

    例如。

  1. Prepend window.name with NG_DEFER_BOOTSTRAP! prior to injecting your Angular.
    E.g. inject a tiny script (before angluar.js) containing just one line:

window.name = 'NG_DEFER_BOOTSTRAP!' + window.name;


  • 包装你的应用程序的根元素与父元素属性 NG-非绑定

    var wrapper = ...    // <div ng-non-bindable></div>
    wrapper.appendChild(lamp);   // or whatever your root element is
    document.body.appendChild(wrapper);
    


  • 在您的应用程序的主脚本,手动引导你的角度应用:

  • In your app's main script, manually bootstrap your Angular app:

    var appRoot = document.querySelector('#<yourRootElemID');
    angular.bootstrap(appRoot, ['genie-extension']);
    


  • <击> <子>
    印刷精美:我没有测试它自己,但我保证这么快呢!

    Fine print: I haven't tested it myself, but I promise to do so soon !

    的code下面旨在作为概念的用于上述方法的证明。基本上,它是一个加载角供电内容脚本到任何 HTTP演示扩展: / HTTPS:页只要浏览器的操作按钮被点击。

    The code below is intended as a proof of concept for the approach described above. Basically, it is a demo extension that loads an Angular-powered content-script into any http:/https: page whenever the browser-action button is clicked.

    扩展需要,为了不干扰所有必要的precautions(或得到由碎)的页面本身的角度实例(如果有的话)。

    The extension takes all necessary precautions in order not to interfere with (or get broken by) the page's own Angular instance (if any).

    最后,我不得不添加第三个要求(见上面的更新的解决方案的描述),以保护/隐藏页面的折角实例的内容脚本的角应用程序。结果
    (即我缠根元素的父元素与 ngNonBindable 指令。)

    Finally, I had to add a third requirement (see the updated solution description above) to protect/hide the content-script's Angular app from the page's Angular instance.
    (I.e. I wrapped the root element in a parent element with the ngNonBindable directive.)

    manifest.json的:

    {
      "manifest_version": 2,
      "name": "Test Extension",
      "version": "0.0",
    
      "background": {
        "persistent": false,
        "scripts": ["background.js"]
      },
    
      "browser_action": {
        "default_title": "Test Extension"
    //    "default_icon": {
    //      "19": "img/icon19.png",
    //      "38": "img/icon38.png"
    //    },
      },
    
      "permissions": ["activeTab"]
    }
    

    background.js:

    // Inject our Angular app, taking care
    // not to interfere with page's Angular (if any)
    function injectAngular(tabId) {
      // Prevent immediate automatic bootstrapping
      chrome.tabs.executeScript(tabId, {
        code: 'window.name = "NG_DEFER_BOOTSTRAP!" + window.name;'
      }, function () {
        // Inject AngularJS
        chrome.tabs.executeScript(tabId, {
          file: 'angular-1.2.7.min.js'
        }, function () {
          // Inject our app's script
          chrome.tabs.executeScript(tabId, {file: 'content.js'});
        });
      });
    }
    
    // Call `injectAngular()` when the user clicks the browser-action button
    chrome.browserAction.onClicked.addListener(function (tab) {
      injectAngular(tab.id);
    });
    

    content.js:

    // Create a non-bindable wrapper for the root element
    // to keep the page's Angular instance away
    var div = document.createElement('div');
    div.dataset.ngNonBindable = '';
    div.style.cssText = [
      'background:  rgb(250, 150, 50);',
      'bottom:      0px;',
      'font-weight: bold;',
      'position:    fixed;',
      'text-align:  center;',
      'width:       100%;',
      ''].join('\n');
    
    // Create the app's root element (everything else should go in here)
    var appRoot = document.createElement('div');
    appRoot.dataset.ngController = 'MyCtrl as ctrl';
    appRoot.innerHTML = 'Angular says: {{ctrl.message}}';
    
    // Insert elements into the DOM
    document.body.appendChild(div);
    div.appendChild(appRoot);
    
    // Angular-specific code goes here (i.e. defining and configuring
    // modules, directives, services, filters, etc.)
    angular.
      module('myApp', []).
      controller('MyCtrl', function MyCtrl() {
        this.message = 'Hello, isolated world !';
      });
    
    /* Manually bootstrap the Angular app */
    window.name = '';   // To allow `bootstrap()` to continue normally
    angular.bootstrap(appRoot, ['myApp']);
    console.log('Boot and loaded !');
    

    <子>
    印刷精美:结果
    我做过一些preliminary测试(与两个角和非角网页),一切似乎如预期工作。然而,我有没有彻底测试这种方法的手段!

    如果有人有兴趣, 这是什么了 以Angularize精灵的灯。

    Should anyone be interested, this is what it took to "Angularize" Genie's lamp.

    这篇关于已经使用的角度在页面上的扩展采用了棱角分明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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