Go back to the main page

Modify an existing page with a Chrome extension built using Angular and Yeoman Part 2

This article is over 2 years old. Proceed with caution.

Regards ♨ – Minimul

 

 


Code from screencast and tutorial is available on Github. The screencast has more detail and explanation than this tutorial.

More page altering experiences

I stopped off on Part 1 just when things were getting good. I leveraged Yeoman and Angular to quickly get a new Chrome extension project up and running. Follow along and we will finish getting this 'Search on Bing' button injected on the Google Search page.

  1. Go back to the browser and in Chrome web inspector find where to put the 'Search on Bing' button.
  2. Google's search page buttons are located under selector the .jsb center.
  3. Modify app/scripts/contentscript.js to place the button in the correct spot.
  4. 
      // omitted
      app.controller('MainController', function ($scope) {});
    
      var myDirective = document.createElement('div');
      myDirective.setAttribute('my-directive', '');
      viewport.appendChild(myDirective);
      document.querySelector('.jsb center').appendChild(myDirective);
    
      app.directive('myDirective', function() {
        return {
      // omitted
    
  5. Go back to the browser and in Chrome web inspector and copy the HTML of the "I'm Feeling Lucky" button.
  6. We are going to use that button's HTML as the starting point for the 'Search on Bing' button.
  7. Paste the HTML to app/scripts/contentscript.js and modify as in the below highlighted code.
  8. 
      // omitted
    
      app.directive('myDirective', function() {
        return {
          restrict: 'EA', 
          replace: true,
          template: '<input value="Search on Bing" name="btnB" type="submit">'
        };
    
  9. Go back to chrome://extensions and reload.
  10. This is mentioned in Part 1 but bares repeating: Every time you make a change to the extension code you must reload.
  11. Reload Google search page.
  12. Ok, that is a better looking button.
    We are going to need to add quite a bit of HTML to this directive so instead of doing it inline let's use a template.
  13. Make a new directory under the app directory called 'templates' and file called 'bing.html'.
  14. Using a template helps organize our directive.
  15. Use the code below within bing.html
  16. <form action="http://bing.com/search" method="GET">
      <input type="submit" name="btnB" id="" value="Search on Bing" />
      <input type="text" name="q" id="q" value="{{ search }}" />
    </form>
    
    Here a form tag has been added that submits a GET request to the bing.com/search url. Also, another input field was added to data bind to the Google search input field. More on that in a bit.
    Angular loads templates via AJAX requests so we need to do some fancy footwork to get this to work within a Chrome extension. For more explanation, check out the screencast right around the 4th minute.
  17. Modify app/scripts/contentscript.js with the below highlighted code.
  18. 
      // ..omitted
    
      app.directive('myDirective', [ '$sce', function($sce) {
        return {
          restrict: 'EA',
          replace: true,
          templateUrl: $sce.trustAsResourceUrl(chrome.extension.getURL('templates/bing.html'))
        };
      }]);
    
      // ..omitted
    
  19. Modify app/manifest.json to allow use of the bing.html template
  20. 
    // omitted
      ],
      "html": [ "templates/bing.html" ],
      "run_at": "document_end",
      "all_frames": false
    }
    ],
    "content_security_policy": "script-src 'self'; object-src 'self'",
    "web_accessible_resources": [
      "templates/bing.html",
      "bower_components/angular/*"
    ]
    
  21. Next, let's hook up the data binding that was introduced in the bing.html template.
  22. Go back to the browser and in Chrome web inspector find the id of the search input field.
  23. The id's name is lst-ib.
  24. Modify app/scripts/contentscript.js with the below highlighted code.
  25.   // ..omitted
      app.controller('MainController', function ($scope) {});
    
      var input = document.getElementById('lst-ib');
      input.setAttribute('ng-model', 'search');
    
      var myDirective = document.createElement('div');
      // ..omitted
    
  26. Reload the extension and the Google search page to see the changes.
  27. Start typing in 'Hilltown'
    The data binding is working but the Google auto suggest is getting in the way.
    To be better able to see what is going on, let's get rid of Google auto suggest. Removing auto suggest is not necessary as in its final state the input[id=q] from the bing.html template will be hidden, but this allows for a quick demonstration of Angular.element.
  28. Go back to the browser and in Chrome web inspector find the HTML responsible for the auto suggest menu.
  29. Using 'Inspect Element' we see that the td element with the class .gssb_e is the culprit.
  30. Modify app/scripts/contentscript.js to remove auto suggest.
  31. 
      // omitted
      app.controller('MainController', function ($scope) {});
    
      var autoCompleteWin = document.querySelector('.gssb_e');
      angular.element(autoCompleteWin).remove();
    
      var input = document.getElementById('lst-ib');  
      // omitted
    
    Angular ships with a lightweight version of jQuery called jqLite. Angular.element is an alias for jqLite or jQuery (if jQuery is installed). Using jqLite's .remove() saves me 2 steps over using vanilla Javascript in which I would have had to: (1) Go up the dom to find a parent element; (2) execute a .removeChild() from said parent element.
    Note: Google Instant predictions have been turned off in this browser.
  32. Reload the extension and the Google search page to see the changes.
  33. After removing Google's auto suggest we can clearly see that simple data binding is working.
  34. Modify app/templates/bing.html and the change the data-bound input element to hidden.
  35. <form action="http://bing.com/search" method="GET">
      <input type="submit" name="btnB" id="" value="Search on Bing" />
      <input type="hidden" name="q" id="q" value="{{ search }}" />
    </form>
    
  36. Reload the extension and the Google search page to see the changes.
  37. Put in your search term of choice and click on 'Search on Bing'.
    Sweet, it worked.

Conclusion

In this 2-part series we modified the Google home page using a Chrome extension built with Angular and Yeoman. It is my hope that this will help jumpstart your next Chrome extension project. Again, there is more explanation and commentary on the screencast, while the code is on Github.

Comment on this article?