Angular 2+ switching betweens elements, based on click - javascript

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

Related

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 can I have arbitrary content inside an ng-repeat with Angular?

I have an ordered list of items that I want to be displayed. Getting this done with Angular is trivial:
<p>Filter a game: <input type="text" ng-model="search.name" /></p>
<game-card ng-repeat="game in games | filter:search" game ="game" size="large"></game-card>
This outputs an ordered list of games that has been sorted from the database. However, I want to show a few snippets of arbitrary content inside this ng-repeat. This diagram below indicates what I'm after. The lefthand side shows how it should look in the unfiltered state, the righthand side if a search term as present.
As you can see, I want to highlight the first item with a "Next up" heading, and following that, an "After that" heading. When a search is present, I don't want these headings at all as they won't be relevant.
I'm completely new to Angular ("you lost me at service" new, by the way), but have come from a Knockout.js background. What is the "Angular way" of solving this?
Stack up ng-if's on the headings and compare with $index? Does $index even care about the filter being applied?
Kind of dirty solution: within the ng-repeated element, put something like
<div ng-if="$index === 0">
<h2>Next up</h2>
</div>
<div ng-if="$index === 1">
<h2>After that</h2>
</div>
<div>
<!-- Your content goes here, unconditionally -->
</div>
And the obvious problem with this is that two tests are performed for each "instantiation" of the content of the ng-repeated element, and they are useless except for the first and second.
Otherwise you could place your first two bits of contents with headers outside the ng-repeat and then start repeating from index 2, but I'm not sure that's possible with ng-repeat.
If it's not, then split your data into firstElement, secondElement and rest where rest is Array.prototype.slice.call(/* your initial list of elements */, 2).
The problem with this last solution is that it requires you to adapt your data to how you present it, which is undesirable for obvious reasons.
edit: OK here's something better, not tested:
<div ng-if="elements.length > 0">
<h2>Next up</h2>
<div><!-- First content goes here, it uses elements[0] --></div>
</div>
<div ng-if="elements.length > 1">
<h2>After that</h2>
<div><!-- Second content goes here, it uses elements[1] --></div>
</div>
<div ng-repeat="element in elements.slice(2)">
<!-- The rest goes here, unconditionally -->
</div>
Instead of doing your ng-repeat in the game-card tag, do it in a wrapping div and then use ng-repeat special variables:
<p>Filter a game: <input type="text" ng-model="search.name" /></p>
<div ng-repeat="game in games | filter:search">
<div ng-if="$first">NEXT UP</div>
<div ng-if="$index === 1">AFTER THAT</div>
<game-card game="game" size="large"></game-card>
</div>
My solution was to ng-show the titles only if the length of the results passed through the filter equaled the total number of games:
<h2 ng-show="games.indexOf(game) == 1 && search.length == games.length">More Games</h2>

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>

Find instance following given element

I have a question about dom navigation with jquery. I'm trying to find an element with a given class that is closest in the dom following a given element.
I have a table like structure, created through divs and styled in css. I have an element being edited, and when the user presses enter I want to focus the following editable element. However, it's not a sibling of the element being edited.
HTML
<div class="calendarEntry">
<div when="2014,9,18" class="when">Sep 18</div>
<div class="items">
<div class="item">
<div code="ABC" class="type">ABC123</div>
<div offered="2014,9,15" class="offered dateish">Sep 15
<div class="offer editable">10</div>
<div class="sku editable">TH1</div>
<button>Publish</button>
</div>
</div>
<div class="item">
<div code="DEF" class="type">DEF321</div>
<div offered="2014,9,14" class="offered dateish">Sep 14
<div class="offer editable">10</div>
<div class="sku editable">TH2</div>
<button>Publish</button>
</div>
</div>
<div class="item">
<div code="GHI" class="type">GHI852</div>
<div offered="2014,9,12" class="offered dateish">Sep 12
<div class="offer editable">10</div>
<div class="sku editable">TH3</div>
<button>Publish</button>
</div>
</div>
</div>
</div>
Note: There are multiple calendar entries on the page.
Say the user is editing the offer of the DEF312 item. When they hit enter I want to edit the offer of GHI852. I have the code to make the div editable, by replacing it with a text field with a class of offer editing. If they're editing the final offer in this calendar entry, then the enter key should focus the first editable offer of the following calendar entry, if there is one. If we're at the bottom of the list I don't want to wrap back to the top (which I think would overly complicate matters anyway).
The bit I'm stuck with is how to find the next offer (all offers are editable).
Here's what I've tried:
var nextOffer = $('.offer').find('.editing').next('.editable');
Clearly, this doesn't work. The problem is that the following editable offer isn't a sibling of the current offer being edited, so next() doesn't work for me. The following offer could be in the current calendar entry, or it's just as likely to be in the next calendar entry. Either way, it's a few divs away, at varying depths.
Can I even do this with jquery dom traversals, or am I better just brute forcing it through javascript (i.e. looping through all .editable instances and returning the one after .editing?
Adding the class 'editing' to simulate the the input:
<div class="item">
<div code="DEF" class="type">DEF321</div>
<div offered="2014,9,14" class="offered dateish">Sep 14
<div class="offer editable">10</div>
<div class="sku editable editing">TH2</div>
<button>Publish</button>
</div>
</div>
you can do:
function findEditable(currentItem) {
var nextEditable = undefined,
selectors = [".item", ".calendarEntry"];
$.each(selectors , function (idx, selector) {
var ref = currentItem.closest(selector);
nextEditable = ref.parent()
.children("div:gt(" + ref.index() + ")")
.find(".offer.editable")
.first();
return nextEditable.length === 0;
})
return nextEditable;
}
findEditable($(".editing")).css({
color: 'red'
});
jsfiddle demo
You can use parents() to get the .offered element which contains the .offer element like so:
var offered = $('.offer').find('.editing').parents('.offered');
From that you can use next() to get into the .offered element's sibling .item element, and find the .editable element within that:
offered.next('.item').find('.editable');
JSFiddle demo. Note that I've manually added this .editing element within your DEF321 item's .offer element - I assume this gets added dynamically on your side, but either way isn't included in your question.
Edit: The HTML in the question has now been changed. Based on this, instead of getting the .offered parent, you'd get the .item parent:
var item = $('.offer').find('.editing').parents('.item');
And proceed in the same way as before:
item.next('.item').find('.editable');
JSFiddle demo.
try this
var current=document.activeElement,
all=$(".editable"),
index=all.indexOf(current),
next=all[index+1]
It first finds the current element and the list of elements,
then it will find the current element in the list.
It will then add 1 to the index and select it from the list.
To extend the array with the indexOf function;
if(!Array.prototype.indexOf){
Array.prototype.indexOf=function(e/*,from*/){
var len=this.length>>>0,
from=Number(arguments[1])||0;
from=(from<0)?Math.ceil(from):Math.floor(from);
if(from<0)from+=l;
for(;from<len;from++){
if(from in this&&this[from]===e)return from;
}
return -1;
};
}

Switching between <div> elements using buttons

I have a specific goal in mind.
Please reference this page: http://cubancomplex.kodingen.com/test/MM/dashboard1.html
On the very bottom right, there is a <div> with two buttons on each side. The <div> currently has one google chart contained inside.
The goal is for a user to be able to use those two buttons to switch between charts for approximately eight cities.
I am not familiar with javascript or jQuery so I would appreciate any assistance! How should I go about achieving this?
Here is the code for that section:
<div id="footer">
<div class="markerNavLeft" title="Prev" id="prevMarker">‹</div>
<div id="markers">
<div id="chart">
<div id="auckland_chart_div"></div>
</div>
</div>
<div class="markerNavRight" title="Next" id="nextMarker">›</div>
</div>
Based on my experience, there's 2 option that you can use..
you can place your charts in your div id="chart". The first one add a class to mark it as a selected one (e.g. selected), of course the other is hidden… Please add a same class for all of the chart(e.g. chart-detail). Then, you can use
var temp = $(".selected").next(".chart-detail"); $(".selected").removeClass("selected"); temp.addClass("selected");
for the previous button, you can use .previous function.
You can use ajax ( .ajax function or .load function). Mark each chart with an ID so, you know what's the next or previous chart (within php).

Categories

Resources