How to use angularjs with greasemonkey to modify web pages?

﹥>﹥吖頭↗ 提交于 2019-12-03 03:31:48

There's a general answer about dynamically modifying AngularJS content in the DOM from JavaScript code here:

AngularJS + JQuery : How to get dynamic content working in angularjs

To sum up, when you put ng-* attributes into the DOM from JavaScript code, they won't automatically get hooked up; but AngularJS provides the $compile function for hooking up new HTML content with AngularJS attributes from JavaScript.

So what does this mean when it comes to Greasemonkey/Userscript?

For the purposes of this I'm assuming that your Greasemonkey script is modifying an existing page that already uses AngularJS, and the AngularJS content you want to add uses some of the variables or functions in AngularJS scopes already on that page.

For those purposes:

  1. Get a reference to $compile from AngularJS' dynamic injection system
  2. Get a reference to the AngularJS scope that you want your HTML code to be connected to
  3. Put your HTML code with ng-* attributes in a string and call $compile on it and the scope.
  4. Take the result of that and put it into the page using the usual jQuery-style ways.

To illustrate, here's a little script for CERN's Particle Clicker game, which adds a stat under the 'workers' section.

$(function () { // Once the page is done loading...

   // Using jQuery, get the parts of the page we want to add the AngularJS content to
   var mediaList = $('ul.media-list');      
   var medias = $('li.media', mediaList);

   // A string with a fragment of HTML with AngularJS attributes that we want to add.
   // w is an existing object in the AngularJS scope of the
   // <li class="media"> tags that has properties rate and cost.
   var content = '<p>dps/MJTN = <span ng-bind="w.rate / w.cost * 1000000 | number:2"></span></p>';

   // Invoke a function through the injector so it gets access to $compile **
   angular.element(document).injector().invoke(function($compile) {

       angular.forEach(medias, function(media) {

           // Get the AngularJS scope we want our fragment to see
           var scope = angular.element(media).scope();

           // Pass our fragment content to $compile,
           // and call the function that $compile returns with the scope.
           var compiledContent = $compile(content)(scope);

           // Put the output of the compilation in to the page using jQuery
           $('p', media).after(compiledContent);

       });
   });

});

** NB: Like any AngularJS function that uses its dependency injection, .invoke uses the parameter names of the function you pass to it determine what to inject, and this will break if you're using a minifier that changes the parameter names.

To avoid this you can replace

.invoke(function($compile) { ... });

with the form

.invoke(['$compile', function($compile) { ... }]);

which won't break if the minifier changes the parameter name to something other than $compile.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!