0

I would like to be able to select a button using querySelector and set an attribute of "ng-click=doSomething()"

I have tried selecting the button and then setAttribute("ng-click", "doSomething()") but its not working

my DOM:

<body>
    <div ng-app="myApp" ng-controller="mainCtrl">

        <button id="myBtn">click Me</button>

    </div>
    <script src="./js/app2.js"></script>
</body>

my javascript:

(function() {
    "use strict";

    angular.module("myApp", []).controller("mainCtrl", mainCtrl);

    /** @ngInject */
    function mainCtrl($scope) {

      init();
      function init() {
          $scope.doSomething = () => {
              console.log("doing something");
          }
          let btn = document.querySelector('#myBtn');
          btn.setAttribute("ng-click", "doSomething()");
      }
    }
  })();

when I click the button it should console log something.

Evan
  • 2,327
  • 5
  • 31
  • 63
  • Why not use `btn.addEventListener("click",$scope.doSomething)`? – georgeawg May 21 '19 at 13:14
  • is it possible to add argument on doSomething if I do it this way? – Evan May 22 '19 at 04:38
  • Yes it is possible but I am not going to write an answer. With the AngularJS framework, controllers should not be doing DOM manipulation. DOM manipulation should only be done in directives. Controllers should only manipulate the model. Directives connect the model to the view and the view to the controller. Tangling the roles makes the code difficult to understand, test, debug, and maintain. See [Don't design your page, and then change it with DOM manipulations](https://stackoverflow.com/a/15012542/5535245). – georgeawg May 22 '19 at 06:31
  • in my real project I am using components and I use it in the components controller. the above code is just a sample. – Evan May 22 '19 at 07:03

2 Answers2

1

Generally speaking, if you dynamically add "AngularJS-ified" stuff to a document after it's created - such as dynamically creating <button> elements and then adding ng-click attributes to them - those elements will neither be tracked by watchers, nor be part of the normal digest cycle. So, for example, consider the following simple example:

const myApp = angular.module('stuff', [])
  .controller('stuff-cont', function($scope) {
    const targ = document.querySelector('#target');
    for (let i = 0; i < 10; i++) {
      let newBtn = document.createElement('button');
      newBtn.setAttribute('ng-click', 'sayRandNum()');
      newBtn.innerText = `Button ${i}`
      targ.append(newBtn);
    }
    $scope.sayRandNum = () =>{
      alert('Your random number is '+Math.ceil(Math.random()*100));
    }
  })
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app='stuff' ng-controller='stuff-cont'>
  <div id='target'>
  </div>
  The buttons above are clickable, they have an appropriately "structured" ng-click, but they <i>don't trigger</i>!
</div>

Here, we're (for some reason...) creating 10 nearly-identical buttons. However, because of when we built these ng-click'ed buttons (namely, after the initial compilation phase), and specifically when we added the ng-click attributes (also after the initial compilation phase), the buttons are effectively not "known" to the AngularJS cycle".

Looked at another way, when AngularJS is first "loaded" on a page, it first walks through the HTML on that page, and looks for any databinds ({{likeThis}}; we'll ignore these for now) or directives. ng-click, ng-repeat, and other Babbys First AngularJS stuff are just standardized directives, so they're part of that "looking for directives" procedure. When AngularJS finds said directives, it says "Okay, you've got an ng-click on this element; I'll keep an eye on that".

To actually add new AngularJS-ified elements - or add AngularJS behavior to existing elements, as I believe is more the case with you - you'll need to use the $compile function, which basically says "hey, AngularJS! I made a new thing and want you to watch it!"

This SO answer -- Working with $compile in angularjs has a pretty decent explanation of how to use the $compile function.

georgeawg
  • 48,608
  • 13
  • 72
  • 95
Newms
  • 124
  • 1
  • 6
0
(function() {
    "use strict";
        var btn = document.querySelector('#myBtn');
    btn.setAttribute("ng-click", "doSomething()");
    angular.module("myApp", []).controller("mainCtrl", mainCtrl);
        function mainCtrl($scope){
        $scope.doSomething = function(){
        alert('abc');
      }

    }
    angular.bootstrap(document, ['myApp']);         
})();

Please check the JSFiddle , the difference is you have to modified the html before angular bootstrapped so your modified html and js code can be compiled properly. Here is a AngularJS Developer Guide - Bootstrap with more infomation of angularjs bootstrap

georgeawg
  • 48,608
  • 13
  • 72
  • 95
lucas
  • 503
  • 2
  • 13