Binding button to element inside ng-repeat - javascript

I'm trying to bind a button inside ng-repeat to that unique element for the button within the same repeat, pretty hard to word for me so I'll give a code snippet.
<li ng-repeat="thing in listOfThings track by $index">
<div ng-model="text"> text < /div>
<button ng-click="highlightText()" />
</ li>
Although not exact, that's the idea. The problem is that when I click the button, it will highlight all the texts inside the listOfThings.
Note: assume that the text is given a ng-class that highlights when a boolean is true, and not highlighted when it's false, toggled by the button.
Any idea how to "bind" that button to only that one text so it doesn't highlight everything else?
I've tried to google for it, it might be a duplicate question but not sure how to search for something this specific so please link the answer if it's a duplicate.

If I understand your example correctly, your ng-class is going to apply the class to all items inside of your repeat based on the click event.
You need to track the button selection individually, by each element in the list. Something like:
HTML:
<li data-ng-repeat="thing in listOfThings track by $index">
<div data-ng-model="text" data-ng-class="{ 'highlighted': thing.Selected }"> < /div>
<button data-ng-click="highlightText(thing)" />
</li>
JS:
$scope.highlightText = function(thing){
thing.Selected = true;
}
CSS:
.highlighted{
background-color: yellow;
}
EDIT: Good suggestion made by skyboyer, this could be made cleaner by moving the highlighted function and not tracking the flag on the thing variable.
HTML:
<li data-ng-repeat="thing in listOfThings track by $index">
<div data-ng-model="text" data-ng-class="{ 'highlighted': selected }"> < /div>
<button data-ng-click="selected = true" />
</li>

Related

Angular 2+ switching betweens elements, based on click

So, I'm trying to use a angular way to send the buttons created to either the #start or #finish divs, based on click on the buttons selected, so in a way they would send themselves if you may if they follow a condition, which in this case is to be either inside of the #start or #finish divs. With Jquery, I just check what's the parent of certain element, if matches one, I send it to the other, and vice versa. Now with angular, I have been looking into the whole, rendering and stuff, but my head can't just understand the overall picture, and I even though I was able to click and send the element clicked to a different div, I couldn't do it with the other buttons created, and also with the button that was first clicked, in the other div.
<div class="ui raised very padded text container segment"
#finish>
</div>
<div class="ui raised very padded text container segment" #start>
<button
*ngFor='let word of ge_array'
(click)="goToNext()"
>{{word}}</button>
</div>
Does anybody know how to tackle this situation?
Renan, I would change all your plan. I have an array of element. this elements have a property "place". I will show in two div one for "plan1" and the other for "plan2".
//the .ts is like
items:any[]=[{word:'uno',place:1},{word:'dos',place:1},{word:'tres',place:2}]
get items1(){
return this.items.filter(it=>it.place==1);
}
get items2(){
return this.items.filter(it=>it.place==2);
}
//the .hmtl like
<h2>place 1</h2>
<button *ngFor="let item of items1" (click)="item.place=2">{{item.word}}</button>
<h2>place 2</h2>
<button *ngFor="let item of items2" (click)="item.place=1">{{item.word}}</button>
I would prefer using a getter and have "item1" and "item2". the click make that the property "place" of the item becomes 2 in place 1 and becomes 1 in place2
You can make two *ngFor over the same array also using a *ngIf like
<h1>place 1</h1>
<div *ngFor="let item of items">
<button *ngIf="item.place==1" (click)="item.place=2">{{item.word}}</button>
</div>
<h1>place 2</h1>
<div *ngFor="let item of items">
<button *ngIf="item.place==2" (click)="item.place=1">{{item.word}}</button>
</div>
and forget the getters

Stopping a click event on a div if a condition is met -- Angular 5

I have a loop that generates let's say 20 divs. Each div is an object from my local objects array. Here's the code:
<div *ngFor="let item of userInventory"
class="col-2 c-pointer"
(click)="addItemToArray(item)">
<img src="{{item.image}}" class="img-fluid"/>
<span class="d-block">{{item.name}}</span>
</div>
When a user clicks on the div(item) it will add the item to an array:
addItemToArray(item) {
this.itemsToSend.push(item);
item.isAdded = true;
}
The user under no circumstances is allowed to add the same item twice in the array, but I do not want to mutate the userInventory array (or splice() it). I want it to still be visible, just change some styles on it so it looks disabled. Also as you can see, when the item is clicked, item.isAdded becomes true.
What I want to do is, when item.isAdded is true, disable the (click) event listener on the div (and add some styles), so that the user cannot add the same item twice, despite clicking on it multiple times.
Is this doable in the current Angular implementation?
try it with a condition:
(click)="!item.isAdded && addItemToArray(item)"
For that, you can add a class for each items which are added in the cart as below:
<div *ngFor="let item of userInventory"
class="col-2 c-pointer"
[class.disabled]="item.isAdded" <!-- Add this class, and customize its look -->
(click)="addItemToArray(item)">
<img src="{{item.image}}" class="img-fluid"/>
<span class="d-block">{{item.name}}</span>
</div>
Then, in your .ts component file, add this condition:
addItemToArray(item) {
if (!item.isAdded) {
this.itemsToSend.push(item);
item.isAdded = true;
} else {
// add some error flash message
}
}
Hope it helps! :)
For the class, you can use this :
<div *ngFor="let item of userInventory" [class.disabled]="item.isAdded">
(I removed attributes for the sake of readability)
For the click, you can use a ternary :
<div *ngFor="let item of userInventory" (click)="item.isAdded ? null : addItemToArray(item)">
But the best solution would simply be to use a condition in your click handler I think.
You can simply use disabled property to achieve this:
<div *ngFor="let item of userInventory"
class="col-2 c-pointer"
(click)="addItemToArray(item)"
[attr.disabled]="item.isAdded">
<img src="{{item.image}}" class="img-fluid"/>
<span class="d-block">{{item.name}}</span>
</div>

How do I move these elements in DOM

I don't want to change HTML because I want to leave the display the way it is for default view and want to move them in second view. I want to know how I can dynamically order the class of a div.
I want to do this via button click. I have adEventListener() for 'click' where I am doing something and the move logic would go inside this event listener.
I understand that I can get these divs, remove from their parents and place it where I want. But I do not know how to do these for each of them since I have multiple lis. I am struggling with the loop so that I can do these for each li. I need to do this using pure JS and not jQuery.
<ul>
<li>
<div>
<div class="a">
<div class="b">
<a class="c">
<div class="d"></div>
<div class="e">
<div class="f"></div> // this is the first item that I want to move
</div>
<div class="g"></div> // this is the second item that I want to move
</a>
</div>
<div class= "h"></div> // I want above mentioned divs to be before this div
</div>
</div>
</li>
//There are multiples lis
<li></li>
Assuming you would like to do this on load of the page, you could solve your problem with the following JQuery DOM manipulations:
$(document).ready(function(){
$("ul .a").each(function(index, element){
$current_div_a = $(element);
$div_h = $current_div_a.find(".h");
$div_f = $current_div_a.find(".f");
$div_f.clone().insertBefore($div_h);
$div_f.remove();
$div_g = $current_div_a.find(".g");
$div_g.clone().insertBefore($div_h);
$div_g.remove();
})
});
You can test it out on this demo.
I strongly advise against this way of doing it though. I guess it's also the reason why your question got some downvotes too. Just modifying your HTML keeps your code clean, maintainable and clearer for anyone else starting to work on your project. Keeping backwards compatibility for your code as much as possible will cause maintainability problems later.
I ended up using
var list = document.querySelectorAll("ul li");
for (var item of list) {
let fClass = item.querySelector(".f");
fClass.parentNode.removeChild(fClass);
let parentOfFirstChildAfterWhichIwantMyF = item.querySelector(//selector for parentOfFirstChildAfterWhichIwantMyF);
parentOfFirstChildAfterWhichIwantMyF.insertAdjacentElement("beforeend", fClass);
}

Register single click on list item child elements

I have the following HTML structure:
<li class="is_tab" id="geometry_tab">
<a data-toggle="collapse" href="#geometry_tab_collapse">
<i class="pe-7s-plugin"></i>
<p>Geometry
<b class="caret"></b>
</p>
</a>
<div class="collapse" id="geometry_tab_collapse">
<ul class="nav">
<li class="is_tab" id="pipe_geometry_tab">Pipe Geometry</li>
</ul>
</div>
</li>
Using jQuery, my objective is to retrieve the <li> id on click, irrespective of whether the user clicks li.is_tab, li.is_tab > a, li.is_tab > a > p, or li.is_tab > a > i. Moreover, I would like the same event handler to be capable of distinguishing between clicks on #pipe_geometry_tab and #geometry_tab, i.e., simply returning a single, correct id when one or the other is clicked.
My question is this:
Given the following snippet,
$(<selector>).on("click", function(){...})
is there a <selector> that will register a single click on li.is_tab regardless of whether it or its a, i, or p children is clicked?
If not, I would appreciate any recommendations on how to go about this.
PS I've tried quite a few things, but rather than bloat this post with them, I'm hoping someone more experienced feels this has an obvious solution.
$('li.is_tab').on("click", function(e){...});
^^ that should work fine and anything that is clicked on the li will be handled.
If you want the li that was clicked you can look at e.currentTarget if you want to see the actual element that was clicked you can use e.target
So if you want the id of the li that was clicked you can use e.currentTarget.id

ng-show, toggle right element on click [Angularjs]

I wana toggle elements but not all elements i need just one on which is clicked.
for example if I have 3 form elements and 3 buttons if I click on button 1. I just wana toggle 1. form element.
This is my current code:
angular:
$scope.formWhat = false;
$scope.formShow = function(item){
$scope.formWhat = !$scope.formWhat;
};
html:
<div ng-repeat="x in comments">
replay
<form id="<%x.id%>" ng-show="formWhat">
blbllblblbl
</form>
</div>
This code will open all forms, but i need just on which is clicked, any idea?
One of the helpful things here is that ng-repeat creates a child scope for each item repeated.
So you can use a local variable inside that child scope that controller knows nothing about. This won't close any of the others but that could be accomplished also. Criteria you gave wasn't very specific
<div ng-repeat="x in comments">
<a ng-click="showForm = !showForm">replay</a>
<form ng-show="showForm"></form>
</div>

Categories

Resources