bind click event to the element in ng-repeat angular - javascript

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);
}

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!

How to use $index in ng-repeat angular js

I have posted my question
How to create check box from multidimensional array using angular js
But I have not gotten any response. I have debug my code when I am going to add second ng-repeat I am getting
Error: ngRepeat:dupes Duplicate Key in Repeater
When I am adding repeat by $index I am getting single character as key and value too
Please help me I am new in angular js :(
This is my fiddle of code http://jsfiddle.net/ashishoft/03L3faq5/2/
Here is example:
ng-repeat="i in items track by $index"
Pretty simple really. You can even use it in combination with custom directives etc. Its basically an index of where you are in the loop.
There are some flaws with using it though. If your creating an ng-repeat list, and then passing the $index into some click function or something, then you can have issues if your also using filtering on that same list. The $index can fall out of sync with the filters and leave you wondering why its giving you wrong data.
for example:
<li ng-repeat="page in links | someFilter:filter">
<a ng-click="someFunction($index)">{{ someData }}</a>
</li>
vs the better way of:
<li ng-repeat="itemX in someData | someFilter:filter">
<a ng-click="someFunction(itemX)">{{ itemX.name }}</a>
</li>
So although I use the $index in my example below, its often best just to pass the whole object in when doing more complex functions per row.
HTML:
<div ng-app="myApp" ng-controller="MainCtrl">
<ul>
<li ng-repeat="page in links">
<a ng-class="{ testClass: $index == pageNumber }" ng-click="setPageNumber($index)">{{ page }}</a>
</li>
</ul>
</div>
Javascript:
var app = angular.module('myApp', []);
app.controller('MainCtrl', function($scope) {
$scope.links = [
'Link One',
'Link Two',
'Link Three'
];
$scope.pageNumber = 0;
$scope.setPageNumber = function(index) {
$scope.pageNumber = index;
}
});
CSS:
.testClass {
background: black;
color: white;
}
This is a sample of how it could be written, although using $index is just fine. Might I suggest using something else like the element id or title, here is an article that talks about ng-repeat.
<div class="favorite-children" ng-repeat="photo in ctrl.favorties track by $index">
<div class="card"></div>
</div>
//or
<div class="favorite-children" ng-repeat="photo in ctrl.favorties track by photo.title">
<div class="card"></div>
</div>
Update
Try this FIDDLE for a preview of a comprehensive JSON, with your same code previewed on how you can use it. Hope it helps.

Initialize accordion with angularjs and materializecss

I've got this accordion made using materializecss framework:
<ul class="collapsible" data-collapsible="accordion">
<li id="licollapse" ng-repeat="single in packageNames">
<div class="collapsible-header">{{single.name}}</div>
<div class="collapsible-body"><p>{{single.name}}</p></div>
</li>
</ul>
and really i tried in several ways to init this accordion but without success! I tried to write in the html view:
<script>$('.collapsible').collapsible();</script>
and it not worked, i tried create in my controller
$scope.collapsible = function() {
$('.collapsible').collapsible({
accordion : false // A setting that changes the collapsible behavior to expandable instead of the default accordion style
});
};
and call collapsible function in ng-init of the accordion and it not worked. The only one solution i found is call that function in ng-click in the collapsible-header but it's not best way because it works only at the second click.. How can i solve?
When you are forced against your dying wish to call external jQuery frameworks or use jQuery in your Angular Application, then the best approach would be to do so in a directive!!!
The DOM should never be touched in your controller, instead, the state of your data in the controller should update the view.
So in this case we can create a simple directive that will have access to that element and call the function in question:
app.directive('collapsify', [collapsifyFn]);
function collapsifyFn(){
return {
restrict: 'A',
compile: function(element, attrs) {
return {
pre: function preLinkFn(scope, element, attrs) {
//if executed here collapsable only is called on an empty <ul>
},
post: function postLinkFn(scope, element, attrs) {
function linkFn(scope, element, attributes) {
debugger;
$(element).collapsible({accordion: true});
}
}
}
}
}
}
An important thing to note here:
Use case for Pre and Post Link:
So because you are generating your <li>'s via an ng-repeat, you need to ensure that you are calling .collapsible in your link function after ng-repeat has rendered the <li>'s to the DOM.
Because of rendering priority, a simple link: would cause the ng-repeat link: to execute after, making your collapsable function not work properly. The purpose of post: is that it executes the linkFn after its children's linkFn has already executed.
Therefore you are accurately calling .collapsible on a "completely rendered dom".
Now that we have created our superfancy collapsify directive, we can attach it to the dom.
<ul collapsify class="collapsible" data-collapsible="accordion">
<li id="licollapse" ng-repeat="single in packageNames">
<div class="collapsible-header">{{single.name}}</div>
<div class="collapsible-body"><p>{{single.name}}</p></div>
</li>
</ul>
Example From Codepen:
<p data-height="268" data-theme-id="0" data-slug-hash="meoWEK" data-default-tab="result" data-user="TheLarkInn" class='codepen'>See the Pen <a href='http://codepen.io/TheLarkInn/pen/meoWEK/'>Using Collapsible MaterializeCSS</a> by Sean Larkin (<a href='http://codepen.io/TheLarkInn'>#TheLarkInn</a>) on <a href='http://codepen.io'>CodePen</a>.</p>
<script async src="//assets.codepen.io/assets/embed/ei.js"></script>
You should wait with calling your materialize code like this:
$(document).ready(function(){
$('.collapsible').collapsible({
accordion : false
});
});
Do it in this way
<ul class="collapsible" data-collapsible="accordion">
<li id="licollapse" ng-repeat="single in packageNames">
<div class="collapsible-header">{{single.name}}</div>
<div class="collapsible-body"><p>{{single.name}}</p></div>
</li>
<script>
//Instert this just after closing </li>
$(document).ready(function() {
$('.collapsible').collapsible({
accordion: true
});
});
</script>
</ul>
It will work for sure :)

How do I select "this" in angular?

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

apply css on menu item click

I have a little test application here...
http://jsfiddle.net/poppypoop/LMCC2/
I was wondering how I would accomplish the same functionality with angular js. Ultimately adding the 'active' class to the selected menu item while applying the name to the header below. In the fiddle I've done it with jquery, but now I'm wondering how this would be accomplished through angularjs
var app = angular.module("app", []);
function ctrl($scope, Data)
{
}
Would it be best to do it in a directive or controller?
You don't want to be setting the class and modifying the HTML within angular at all. Instead, the angular model should represent the data of your application and use databinding to change view-related properties such as classes, etc.
In your case, the scope could have a list of menu items and a property that holds the currently active item. And when a menu item is clicked on, the active item changes. All the changes in the view are handled by angular databinding...
$scope.items = ['Home', 'Tickets', 'Direct Deposit', 'activity',
'Pay Rate Inquiry', 'Templates'];
$scope.activeItem = 'Home';
$scope.setActive = function (activeItem) {
$scope.activeItem = activeItem;
};
View
<div class="menu-container">
<ul id="menu-ul" class="nav">
<li ng-repeat="item in items">
<a ng-class="{ active: item === selectedItem }" href="#"
ng-click="setActive(item)">{{ item }}</a>
</li>
</ul>
</div>
<div class="nav-selection">
<span>{{ activeItem }}</span>
</div>
JsFiddle: http://jsfiddle.net/xx7KF/
In angular you can use ng-class for adding a class with a boolean condition:
AngularJS - ng-class
You can bind the class to a boolean var in your scope, and when you click on the button, update it with the value you need.

Categories