Pass a reference to DOM object with ng-click
Asked Answered
M

2

70

I have multiple elements with the same callback on ng-click:

<button ng-click="doSomething()"></button>
<button ng-click="doSomething()"></button>
<button ng-click="doSomething()"></button>
<button ng-click="doSomething()"></button>
// In controller:
$scope.doSomething = function() {
  // How do I get a reference to the button that triggered the function?
};

How can I get the reference to the object which made the call to doSomething? (I need to remove an attr from it)

Masqat answered 21/6, 2013 at 16:49 Comment(2)
What are you trying to accomplish? Why do you need to remove an attribute? The whole point of AngularJS is the fact you don't have to do DOM manipulation.Borlase
Each button toggles the readonly attribute on different inputsMasqat
B
23

The angular way is shown in the angular docs :)

https://docs.angularjs.org/api/ng/directive/ngReadonly

Here is the example they use:

<body>
    Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
    <input type="text" ng-readonly="checked" value="I'm Angular"/>
</body>

Basically the angular way is to create a model object that will hold whether or not the input should be readonly and then set that model object accordingly. The beauty of angular is that most of the time you don't need to do any dom manipulation. You just have angular render the view they way your model is set (let angular do the dom manipulation for you and keep your code clean).

So basically in your case you would want to do something like below or check out this working example.

<button ng-click="isInput1ReadOnly = !isInput1ReadOnly">Click Me</button>
<input type="text" ng-readonly="isInput1ReadOnly" value="Angular Rules!"/>
Borlase answered 23/6, 2013 at 4:9 Comment(8)
Why the down vote? If there is something that is wrong I would love to learn what it is.Borlase
You're right, in general - but with any overbearing framework like angular sometimes you want to know how to hack around it, which is what the other answer offers :)Peruzzi
I understand wanting to use a different approach. I don't understand a down vote for a completely valid and IMHO a better approach.Borlase
+1 for pointing out the better approach. I'm kind of new to angular and it'll take some time to get things done using your approach. Unfortunately I'll have to use the other answer until I migrate my code..Leavy
upvoted for a different approach. But still is there a way to find out which elements button was clicked.Inextinguishable
This helps the SO, but it doesn't answer this question, and therefore should not be the accepted answer, even though it was the solution to the SO's problem. I came here looking for an answer to the same question for a completely valid reason and was not helped by your answer, as it addresses the problem, not the question. For the sake of the readers, please answer the question asked. If you feel there is a better solution, provide a suggestion for that solution in the comments section and continue your discussion with the SO in chat.Incredible
Lol, what if I want to use information about the element of current button inside of function, just like declared in very question? Your answer is for the other question and it has no sence to speak about "IMHO better approach" in this case. Possible example: My buttons are created dynamically with ng-repeat and I want to know the position in the document of just clicked button or it's siblings. So, how the better approach can be applicable there?Cymose
Sometimes you need the event in order to find another element. Not always to manipulate the DOM. This is true in components which are used multiple times on the same page. One does not simply select by class or id in that scenario.Leena
B
224

While you do the following, technically speaking:

<button ng-click="doSomething($event)"></button>
// In controller:
$scope.doSomething = function($event) {
  //reference to the button that triggered the function:
  $event.target
};

This is probably something you don't want to do as AngularJS philosophy is to focus on model manipulation and let AngularJS do the rendering (based on hints from the declarative UI). Manipulating DOM elements and attributes from a controller is a big no-no in AngularJS world.

You might check this answer for more info: https://mcmap.net/q/142875/-accessing-clicked-element-in-angularjs

Barehanded answered 21/6, 2013 at 16:54 Comment(8)
How should I accomplish this in Angular's way? Each button toggle the readonly attribute in different inputsMasqat
@Masqat Impossible to help you precisely without live code example. I guess the answer is in using the ng-readonly directive. But I would suggest opening another question with a live code example in plnkr.coBarehanded
I guess $event.currentTarget gives the current dom elementWerbel
In regards to your comment about no DOM manipulating in a controller, it's perfectly acceptable in a directive's controller.Appointed
@Appointed I would say that there are cases where doing DOM manipulation in directive controllers is justifiable / the only way. But it doesn't mean that directive controllers are free to do any DOM manipulations! We still should be adhering to AngularJS principles and do minimal set of DOM manipulations "by hand". See: youtube.com/watch?v=TGmPbWY7gYwBarehanded
"Manipulating DOM elements and attributes from a controller is a big no-no in AngularJS world." Except when you have to, of course...Brougham
Note: You don't actually have to pass $event. You can merely reference event in your function (without the $) to pull the event info eg event.currentTargetTrumpery
Sometimes you need the event in order to find another element. Not always to manipulate the DOM. This is true in components which are used multiple times on the same page. One does not simply select by class or id in that scenario.Leena
B
23

The angular way is shown in the angular docs :)

https://docs.angularjs.org/api/ng/directive/ngReadonly

Here is the example they use:

<body>
    Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
    <input type="text" ng-readonly="checked" value="I'm Angular"/>
</body>

Basically the angular way is to create a model object that will hold whether or not the input should be readonly and then set that model object accordingly. The beauty of angular is that most of the time you don't need to do any dom manipulation. You just have angular render the view they way your model is set (let angular do the dom manipulation for you and keep your code clean).

So basically in your case you would want to do something like below or check out this working example.

<button ng-click="isInput1ReadOnly = !isInput1ReadOnly">Click Me</button>
<input type="text" ng-readonly="isInput1ReadOnly" value="Angular Rules!"/>
Borlase answered 23/6, 2013 at 4:9 Comment(8)
Why the down vote? If there is something that is wrong I would love to learn what it is.Borlase
You're right, in general - but with any overbearing framework like angular sometimes you want to know how to hack around it, which is what the other answer offers :)Peruzzi
I understand wanting to use a different approach. I don't understand a down vote for a completely valid and IMHO a better approach.Borlase
+1 for pointing out the better approach. I'm kind of new to angular and it'll take some time to get things done using your approach. Unfortunately I'll have to use the other answer until I migrate my code..Leavy
upvoted for a different approach. But still is there a way to find out which elements button was clicked.Inextinguishable
This helps the SO, but it doesn't answer this question, and therefore should not be the accepted answer, even though it was the solution to the SO's problem. I came here looking for an answer to the same question for a completely valid reason and was not helped by your answer, as it addresses the problem, not the question. For the sake of the readers, please answer the question asked. If you feel there is a better solution, provide a suggestion for that solution in the comments section and continue your discussion with the SO in chat.Incredible
Lol, what if I want to use information about the element of current button inside of function, just like declared in very question? Your answer is for the other question and it has no sence to speak about "IMHO better approach" in this case. Possible example: My buttons are created dynamically with ng-repeat and I want to know the position in the document of just clicked button or it's siblings. So, how the better approach can be applicable there?Cymose
Sometimes you need the event in order to find another element. Not always to manipulate the DOM. This is true in components which are used multiple times on the same page. One does not simply select by class or id in that scenario.Leena

© 2022 - 2024 — McMap. All rights reserved.