38

There is clearly something fundamental im not yet understanding.

Im trying to make user of the Modal module in Angular Ui.Bootstrap but im finding that my clicks are not activating the open() function -- So boiling it down to a very simple testcase, as below, im not seeing any calls when the ng-click points to a function (alert or console.log), but does work when the ng-click points to something which is just an expression

Why is the alert not called in the first example?

<div data-ng-app>
    <button data-ng-click="alert('Message 1');">
        ngClick -- not working, why not?
    </button>
    <button onclick="alert('Message 2');">
        Plain onclick
    </button>
    <button data-ng-click="count = (count + 1)">
          But this works, why ???
    </button>
    count: {{count}}
</div>

http://jsfiddle.net/H2wft/1/

Soren
  • 14,402
  • 4
  • 41
  • 67

5 Answers5

48

ng-click is meant for use with either a function in the current scope (so for example $scope.alert = window.alert would solve the problem of not being able to alert there) or an angular expression. it looks like angular does not allow you to use global scope methods in there (it might be looking them up in the current $scope, from which they are missing).

Community
  • 1
  • 1
orcaman
  • 6,263
  • 8
  • 54
  • 69
23

ng-click expects an angular expression. Internally, angular is using the $parse service to evaluate the expression in ng-click="expression".

An angular expression is not the same as regular javascript code. $parse uses string parsing to interpret the expression and it restricts your access to variables, functions, and objects to just those which are properties of the $scope object, or properties of any $parent scope objects which happen to be available further up the prototypical inheritance chain.

So in theory you could gain access to globals like this:

 $scope.window = window;
 $scope.alert = alert;

... and then in your template do ng-click="window.alert('hello!')"

...or... ng-click="alert('hello!')"


Or you could do this just once:

 $rootScope.window = window;
 $rootScope.alert = alert;

Then any scope that prototypically inherits from $rootScope will also have access to window and alert.


... but there are good reasons never to do either of the above, except possibly for debugging purposes. That's not to say that decorating the $rootScope is always a bad idea, there is at least one special case where decorating angular's scope can accomplish something that would be very difficult to do otherwise.

Community
  • 1
  • 1
Gil Birman
  • 35,242
  • 14
  • 75
  • 119
7

You cannot execute that kind of code in ng directives. They look for content in your local scope.

If you do this in your controller:

$scope.alert = function(){
  alert('alerted!');
};

and then in your template

ng-click="alert()"

It will execute the javascript alert properly.

JoakimB
  • 1,196
  • 2
  • 13
  • 19
4

For that to work, you have to define alert on your $scope:

$scope.alert = function(text) {
    alert(text);  
};

Relevant piece from documentation:

AngularJS restricts access to the Window object from within expressions since it's a known way to execute arbitrary Javascript code.

https://docs.angularjs.org/error/$parse/isecwindow

manojlds
  • 290,304
  • 63
  • 469
  • 417
0

https://docs.angularjs.org/guide/expression

 <div class="example2" ng-controller="ExampleController">
  Name: <input ng-model="name" type="text"/>
  <button ng-click="greet()">Greet</button>
  <button ng-click="window.alert('Should not see me')">Won't greet</button>
</div>