How do I select "this" in angular? - javascript

I have 5 buttons using the same ng-click function. Basically each of the buttons operate similarly to a tabbed navigation, where you click one of the buttons and it takes you to that tab's pane. Each of these buttons can be repeatable and are housed in a template. The tab panes are also all in a template but aren't all active until a user clicks one of the buttons and creates a page. So basically there are multiple click functions nested within click functions that do different things depending on what user has activated.
In jQuery, I could just use "this" and select the object that was clicked and do all my manipulations to that object easily; however, it doesn't appear there's a way to do that using just angular. Currently, when you click one of these buttons it does the same thing to all of them. I figure I could create 5 separate functions, but I don't want to do that for scalability reasons.
So to summaraize:
Is there a way to select "this" in Angular?
I'd like a solution that is just using Angular and no jQuery
Is there an efficient way of dealing with click functions within click functions?
<nav class="block--menu">
<section class="content--menu" ng-controller="ActiveCtrl">
<div class="menu" >
<button class="menu__item" ng-click="showConfirm()"></button>
<button class="menu__item" ng-click="showConfirm()"></button>
<button class="menu__item" ng-click="showConfirm()"></button>
<button class="menu__item" ng-click="showConfirm()"></button>
<button class="menu__item" ng-click="showConfirm()"></button>
</div>
</section>

You can access jQuery event object using $event in angular events check the documentation for details but if you are sending that to your controller it most likely means you are not doing it in angular way.
the usage is
<button class="menu__item" ng-click="showConfirm($event)"></button>
and in the controller
$scope.showConfirm = function($event){
//$event.target should be your link
};

You should stop thinking in a jQuery way and don't try to manipulate the DOM directly. In your controller you should only manipulate the data, which is then reflected in the view. When you think Angular-way, your code usually looks as follows:
HTML
<section ng-controller="ActiveCtrl as ctrl">
<div class="menu" >
<button ng-repeat="button in ctrl.buttons track by $index"
ng-click="ctrl.showConfirm(button)"
ng-class="{'menu__item_active':button.active, 'menu__item':true}"
>{{button.name}}</button>
</div>
</section>
JavaScript
angular.module('app',[]).
controller('ActiveCtrl', ['$window', function($window) {
this.buttons = [{
name: 'First'
}, {
name: 'Second'
}, {
name: 'Third'
}];
this.showConfirm = function(button) {
button.active = !button.active;
$window.alert(button.name);
}
}]);
Plunker
http://plnkr.co/edit/Dg10cXqFxEKgEt7jWQ7Z?p=preview

Related

How to bind a class on click event of elements obtained through a loop?

I go through an array of objects to display in my html some information boxes that are selectable. For it I bind a class in the event click, but as I obtain the elements through a v-for, when I select one it bind the class to all of them.
How can I differentiate only the selected one?
I have seen several examples with jquery but I would like to know if there is any other method.
My template:
<div class="list-services">
<div class='column-service'
v-for='estimation in filteredEstimation'
v-bind:key="estimation.name"
:class="{ focusService }"
#click="focusService = !focusService"
>
<div class="service-name">
{{estimation.name}}
</div>
<div class="service-description">
{{estimation.description}}
</div>
<div class="service-price">
{{estimation.price}}
<span class="price-currency">€</span>
</div>
</div>
</div>
Thank you very much for your time and help.
I was trying to make a jsfiddle to answer your question, but then I found this jsfiddle on the vue.js forum: https://jsfiddle.net/mogtfpze/2/
It offers three different options for highlighting content by clicking.
li v-for="item in items"
:class="{highlight:item.id == selected}"
#click="selected = item.id">
{{item.id}}
</li>
Although it's an old answer, I believe it should still be compatible with the current Vue version.
If not, or if something is not clear, just let me know and I'll try to help you out!
The method that I use personally (If I understand your question correctly) is the this keyword.
For example:
index.html
<ul id="myList">
<li>a</li>
<li>b</li>
<li>c</li>
</ul>
script.js (Vanilla JavaScript)
var myList = document.getElementById("myList");
myList.addEventListener("click", function () {
console.log(this);
console.log(this.innerText);
});
script.js (jQuery)
var myList = $("#myList").on("click", function() {
console.log(this);
console.log(this.innerText);
});
In this case, using the this keyword allows us to get the innerText of the li element that was clicked by only attaching the event listener to the parent element. innerHtml is only one of many ways to use this keyword. You can see more of them by doing console.log(this) in your event listener function.
Let me know if this helps!

bind click event to the element in ng-repeat angular

I have menu and use ng-repeat for loop to the my category and in this loop i have a link tag and I want to when clicked on this link do something in js file.
But I can't access to the tag a in javascript and add click event to this element.
Here is my ng-repeat code:
<li class="has-children" ng-repeat="category in categories |filter:{ level: 1 } : true" ng-if="$index < 5">
<a class="parent-link">{{category.categoryName}}</a>
<ul class="is-hidden">
<li class="go-back"><a>{{category.categoryName}}</a></li>
<li ng-repeat="submenu in categories |filter:{ parentID: category.categoryID } : true"><a>{{submenu.categoryName}}</a></li>
</ul>
</li>
Here is my js file (this code doesn't fire):
$(".parent-link").on("click", function(e) {
console.log("clicked");
e.prenvetDefault()
});
Use ng-click. It can be used as attribute of element. Example usage:
HTML:
<div ng-click="changeWord()">
{{word}}
</div>
Controller:
$scope.changeWord = function () {
$scope.word = 'I am changed';
}
See http://jsfiddle.net/ax6k3z1e/
Possible reason could be that you Javascript is getting executed before the DOM is ready. You should use ng-click as It's good to build through Angular way when you are using AngularJS in you application.
ng-Repeat have the tendency to bind your iterating object as well. Below is the example for the same.
<div ng-repeat='ele in elements'>
<p ng-click='ShowAlert(ele)'>{{ele.name}}</p>
</div>
Specify below mentioned code in your linked controller.
$scope.ShowAlert=function(element){
alert(element.Name);
}

Exchange information between controllers inside directive

I try to register events like window-close, minimize, maximize and use it inside my controller inside content so I can clean up some things before window is closed. I've just an stupid idea with random ids and broadcast. Anything better?
Window Controller
<div class="window">
<div class="header">
<a ng-click="minimize()">Minimize</a>
<a ng-click="maximize()">Maximize</a>
<a ng-click="close()">Close</a>
<div class="content" ng-include="Controllers/someWindow.html"></div>
</div>
Controllers/someWindow.html
<div ng-controller="SomeWindowCtrl">
</div>
You can wrap the div.window element into a directive (say, my-window) and expose a controller from it. Then, directives inside it can require my-window as parent, getting its controller as the fourth argument of the link function.
A concise example can be found here.
You can use
$rootScope.$broadcast('EVENT_ID', data);
and
$rootScope.$on('EVENT_ID', function($event, data) {
//event handler
});

Alter template source programmatically with angularJS

I have this simple piece of code, that replace the ng-include tag with a proper template based on the button that I click (here is the Plunker):
<button ng-click="template='page1'">Show Page 1 Content</button>
<button ng-click="template='page2'">Show Page 2 Content</button>
<ng-include src="template"></ng-include>
<script type="text/ng-template" id="page1">
<h1 style="color: blue;">This is the page 1 content</h1>
</script>
<script type="text/ng-template" id="page2">
<div id="testanglr" ng-controller="PhoneListCtrl">
<ul>
<li ng-repeat="phone in phones">
<span>{{phone.name}}</span>
<p>{{phone.snippet}}</p>
</li>
</ul>
</div>
</script>
What I want to do is to replicate the same behaviour of Show Page 2 Content button with a javascript function (rather than Angular's HTML helper tag).
Regarding the Plunker linked above, I would that the third button will act exactly as the second button, but this behavior should be executed inside the onClickHandler function in place of alert.
If I understood correctly, you want to change angular from outside of angular world. You can do it this way:
function onClickHandler() {
var appElement = document.querySelector('[ng-app=plunker]');
var appScope = angular.element(appElement).scope();
appScope.template = 'page2';
appScope.$apply();
}
http://plnkr.co/edit/WKLJ45yRYu1583C2ZnfT
I don't know why you want like this but there is a way to achieve this.
JS
function onClickHandler() {
var ele = document.getElementById("main");
angular.element(ele).scope().template='page1';
angular.element(ele).scope().$apply();
}
If you are using jQuery then directly you can use $("#main") instead of angular.element. In angular.element, we need to use DOM element only. we can't use ID selector or class selector as it has been removed from jqlite by angular.
Updated Code

performance of angularjs ng-click inside ng-repeat

It's more a suspicion than an verified problem but..
I've worked with knockoutjs for a while and there it was a performance issue to create lots of ko click bindings - the better way was to use much fewer jQuery .on('click', ...) to handle these.
Now that I'm diving into angularjs I have a ng-repeat within ng-repeat and inside this second one I have a few buttons with ng-click..
<ul>
<li ng-repeat="el in collection">
<button ng-click="someFn()">click me</button>
<button ng-click="someFn2()">click me</button>
<button ng-click="someFn3(el)">click me</button>
</li>
</ul>
Doesn't this create a lot of click event bindings? Or does angular optimise this somehow?
It's hardly any optimization in this case. What if you have several nested ngRepeats. Against which one should optimization be performed? Not easy to answer indeed. Moreover, repeated items can be controlled by another controller.
I see the following a bit hackish way of accomplishing the task.
We can apply ngClick to the parent element calling some method and passing the value allowing to identify clicked item.
<ul ng-click="itemClicked(itemIdentifier)">
<li ng-repeat="el in collection">
<button>click me</button>
</li>
</ul>
The only question left to answer is how we get this identifying value. We need our own directive to apply to repeated DOM element which attaches this value to the element. After that we can get the value from $event object.
<ul ng-click="itemClicked($event.target.itemIdentifier)">
<li ng-repeat="el in collection">
<button click-optimiztation="el">click me</button>
</li>
</ul>
Sure, you've to check for undefined values.
This approach must be adapted to your needs cause you want to have several clickable elements inside each repeated template. Nonetheless, I hope the idea is clear.

Categories