Angular/Javascript - Hide button with id onclick - javascript

I have multiple buttons on one page, "Add to cart" buttons where each button has a unique id attribute.
I want to hide a particular button when the user clicks on it.
The issue:
What's happening currently is that when a user clicks on a button 1 it hides, then clicks on button 2 it hides but on the same time it shows button 1
The expected behavior:
When the user clicks on button 1 it should hide and keep hiding even after clicking on button 2
P.S. the information of the buttons (products) gets added to an array.
Current code:
Html:
<div *ngFor="let product of products; let i = index">
<div *ngIf="hideButton != i" [attr.id]="i" class="addButton" (click)="addToCart(product, i)">ADD</div>
</div>
JS
addToCart(itemDetails, index) {
this.hideButton = index;
}

You need an array of hidden buttons and you need to add the index to that array:
JS:
// at the top
hiddenButtons = [];
addToCart(itemDetails, index) {
this.hiddenButtons.push(index);
}
HTML:
<div *ngFor="let product of products; let i = index">
<div *ngIf="hiddenButton.indexOf(i) === -1" [attr.id]="i" class="addButton" (click)="addToCart(product, i)">ADD</div>
</div>

If you have a cart to which products are being added, you can look in the cart to check whether the product already exists in it, and use that to decide whether to display the ADD button.
If your product objects can have more properties to them, you can do away with indexes completely.
HTML
<div *ngFor="let product of products">
<div *ngIf="productInCart(product)" [attr.id]="product.id" class="addButton" (click)="addToCart(product)">ADD</div>
</div>
JS
productInCart(product) {
return this.products.findIndex(p => p.id==product.id)!=-1;
}
addToCart(product) {
this.products.push(product);
}

<div *ngFor="let product of products; let i = index">
<div *ngIf="!product.isHidden" [attr.id]="i" class="addButton" (click)="addToCart(product, i)">ADD</div>
</div>
In component
addToCart(itemDetails, index) {
itemDetails.isHidden = true;
this.products[index] = itemDetails;
}
Logic behind this is to create a new property in product when it clicked for add to cart. Initially there will be no property with name isHidden. SO, it will return undefined and undefined will treat as false.

I would suggest the following:
<div *ngFor="let product of products; let i = index">
<div *ngIf="!isInCart(product)" [attr.id]="i" class="addButton" (click)="addToCart(product, i)">ADD</div>
</div>
private hiddenProducts = new Set<FooProduct>();
products: FooProduct[] = [];
loadProducts(){
this.products = // some value
hiddenProducts = new Set<FooProduct>();
}
isInCart(product: FooProduct): boolean {
return this.hiddenProducts.has(product);
}
addToCart(product: FooProduct, index: number){
// optional: check if the element is already added?
this.hiddenProducts.add(product);
// rest of your addToCart logic
}
Why using a set instead of a simple array?
Performance: access time is constant.
Why not use the index as identifier?
Weak against list mutations (filter, reorder, etc)

Related

while deleting the particular items from iteration of items in click event first item is deleting instead of clciked one

In my angular application I have some iteration items and saving the items based on adding the items.
.component.html
<ng-container *ngFor="let categoryDetail of selectedCategoryDetails">
<div class="__header">
<div>
<b>{{ categoryDetail.category }}</b>
</div>
</div>
<div
class="clinical-note__category__details"
*ngIf="categoryDetail.showDetails">
<ul>
<li class="habit-list"
*ngFor="let habits of categoryDetail.habitDetails" >
<div class="target-details">
<b>{{ clinicalNoteLabels.target }}: </b
><span class="habit-list__value">{{ habits.target }}</span>
</div>
</li>
</ul>
<div class="habit-footer">
<span class="m-l-10"
[popoverOnHover]="false"
type="button"
[popover]="customHabitPopovers"><i class="fa fa-trash-o" ></i> Delete</span>
</div>
<div class="clinical-note__popoverdelete">
<popover-content #customHabitPopovers [closeOnClickOutside]="true">
<h5>Do you want to delete this habit?</h5>
<button
class="btn-primary clinical-note__save" (click)="deletedata(index);customHabitPopovers.hide()">yes </button>
</popover-content></div>
</div>
</ng-container>
.component.ts
public saveHealthyHabits() {
let isCategoryExist = false;
let categoryDetails = {
category: this.clinicalNoteForm.controls.category.value,
habitDetails: this.healthyHabits.value,
showDetails: true,
};
if (this.customHabitList.length) {
categoryDetails.habitDetails = categoryDetails.habitDetails.concat(
this.customHabitList
);
this.customHabitList = [];
}
if (this.selectedCategoryDetails) {
this.selectedCategoryDetails.forEach((selectedCategory) => {
if (selectedCategory.category === categoryDetails.category) {
isCategoryExist = true;
selectedCategory.habitDetails = selectedCategory.habitDetails.concat(
categoryDetails.habitDetails
);
}
});
}
if (!this.selectedCategoryDetails || !isCategoryExist) {
this.selectedCategoryDetails.push(categoryDetails);
}
this.clinicalNoteForm.patchValue({
category: null,
});
this.healthyHabits.clear();
}
public deletedata(index:number){
if (this.selectedCategoryDetails) {
this.selectedCategoryDetails.forEach((selectedCategory) => {
this.selectedCategoryDetails.splice(index, 1);
}}
From the above code I have saved the data based on adding the items as above and my requirement is when we click on the delete(it will show the popup having the button yes implemented in anbove code).
when we click on the yes button from list of items, I have to remove the particular item
When I tried removing ,It is only deleting the first item instead of clicked one
Can anyone help me on the same
The logic for deletion is incorrect. The splice mutates the original array, and you are applying the loop for deletion, which keeps on iterating over the array and deleting the array elements based on index, instead of deleting single matched index element.
Example -
const categories = [
1,
2,
3,
4
];
function removal(i) {
categories.forEach((category, index) => {
categories.splice(i, 1);
});
console.log('----Categories-->', categories);
}
removal(0);
Categories Array
First Iteration [index = 0]
[1,2,3,4]
Loop Starts Iterating from 1
Second Iteration [index = 1]
[2,3,4]
Loop Starts Iterating from 3
Third Iteration [index = 2]
[3,4]
Stop
Instead you can use filter function.
public deletedata(index:number){
this.selectedCategoryDetails = this.selectedCategoryDetails.filter((_, i) => i! == index);
}
Note - I would recommend to delete the categories based on some identifier like id instead of index because the array elements position can get changed.
Instead of passing index to deleteData method, you can pass the category object.
public deletedata(category){
this.selectedCategoryDetails = this.selectedCategoryDetails.filter((c) => c.id! == category.id);
}

Delete product with filter in Localstorage

I'm working on a shopping cart project and I'm stuck at the product removal stage.
I tried to work it with the filter method and it works without really working in the sense that what I defined works only in the case where the product having a dataset id and equivalent to the id of the localstorage but that the color is different then there the deletion of the selected product works and the localStorage is updated.
On the other hand when I want to delete a product having a different id but which has the same color as the product selected previously it deletes both products.
An example :
If I have a sofa that has an id 001 and a blue color and I have another sofa that has an id 002 and a blue color and I press the delete button then both products disappear...
How can I avoid this?
I think the definition of the condition I wrote here is a little shaky but I don't know yet how to fix it:
const deleteProduct = function ()
{
let deleteButton = document.querySelectorAll('.deleteItem');
let localStorageProducts2 = localStorage.getItem('Produits')
// Loop to get all buttons
for (let i = 0; i < deleteButton.length; i++)
{
// More clear for the syntax
let buttons = deleteButton[i];
// Link each button to his article
let myActualProduct = deleteButton[i].closest('article');
let getStorageProducts2 = JSON.parse(localStorageProducts2);
buttons.addEventListener("click",() =>
{
getStorageProducts2 = getStorageProducts2.filter(productsInLocalStorage => productsInLocalStorage.id === myActualProduct.dataset.id && productsInLocalStorage.colors !== myActualProduct.dataset.color);
// Update the localStorage
localStorage.setItem('Produits',JSON.stringify(getStorageProducts2));
myActualProduct.remove()
alert('Le produit a bien été supprimé')
// Reload the page
window.location.href ="cart.html";
// Update the productsInLocalStorage
})
}
}
deleteProduct()
<section id="cart__items">
<article class="cart__item" data-id="{product-ID}" data-color="{product-color}">
<div class="cart__item__img">
<img src="../images/product01.jpg" alt="Photographie d'un canapé">
</div>
<div class="cart__item__content">
<div class="cart__item__content__description">
<h2>Nom du produit</h2>
<p>Vert</p>
<p>42,00 €</p>
</div>
<div class="cart__item__content__settings">
<div class="cart__item__content__settings__quantity">
<p>Qté : </p>
<input type="number" class="itemQuantity" name="itemQuantity" min="1" max="100" value="42">
</div>
<div class="cart__item__content__settings__delete">
<p class="deleteItem">Supprimer</p>
</div>
</div>
</div>
</article>
</section>
The HTML part doesn't work here in JSFiddle , I'm working with an API on local.
I find the solution by myself thanks to an article teaching how to use findIndex on array of object and the splice method.

To highlight the selected row in mat-selection list and show its corresponding data by default

When we hover over the first column of the table a tooltip appears and then on clikcing on the button presnt in the tooltip mat dialog opens up.
The data loads but for the first time when the dialog opens up the row is not selected by default.
Note: (after the dialog has opened then on selecting any row its corresponding data loads and the row gets higlighted ,so this part works, but default highlighting of the left section row does not work when the popup opens for the first time)
The dialog contains 2 sections left and Edit json and. In the left whichever row is selected its corresponding data on the right side as json is shown.
alert-dialog.component.html
<div class="row align-items-center">
<div class="col-6 d-flex flex-column">
<span class="sub-section p-t-26 p-b-10">Predefined Alerts</span>
<div class="alert-select">
<mat-selection-list #preDefAlertList (selectionChange)="selectionChanged($event)">
<mat-list-option #option *ngFor="let preDef of data.data; let i = index" [value]="i" [ngClass]="option.selected ? 'selected-option' : ''">
{{preDef.alert}}
</mat-list-option>
</mat-selection-list>
</div>
<span class="sub-section p-t-10 p-b-10">Custom Alerts</span>
<div class="alert-select">
Lorem ipsum
</div>
</div>
</div>
alert-dialog.component.ts
export class AlertDialogComponent {
#ViewChild(MatSelectionList) preDefAlertList: MatSelectionList;
jsonform: FormGroup;
constructor( public dialogRef: MatDialogRef<AlertDialogComponent>,
#Inject(MAT_DIALOG_DATA) public data: DialogData, private alertService: AlertService,
private fb: FormBuilder) {
console.log(data);
this.jsonform = this.fb.group({
json: [data['data'][0].conditionals]
});
}
ngOnInit(){
this.jsonform.statusChanges.subscribe(() => {
if(!this.jsonform.valid && this.jsonform.dirty){
console.log("form is dirty and not valid")
}else{
console.log("form is dirty but valid")
}
});
this.preDefAlertList.selectionChange.subscribe((s: MatSelectionListChange) => {
this.preDefAlertList.deselectAll();
s.option.selected = true;
});
}
selectionChanged(event: MatSelectionListChange) {
this.jsonform.setValue({
json: this.data['data'][event.option.value].conditionals
});
}
onAddNewAlert(){
if(!this.jsonform.valid && this.jsonform.dirty){
console.log("final validation")
}
}
}
stackblitz link
https://stackblitz.com/edit/angular-mat-tooltip-uwsbqa?file=app/alert-dialog/alert-dialog.component.html
This below link is the older version before I did the changes where data was loading in mat dialog and the row was getting highlighted
https://stackblitz.com/edit/angular-mat-tooltip-qxxgcp?file=app%2Falert-dialog%2Falert-dialog.component.html
What I quickly can propose to you is to add ngAfterViewInit lifecycle hook and here mark the first option as selected.
ngAfterViewInit() {
this.preDefAlertList.options.first.selected = true;
}
EDIT - according to your comment
Please look at this example. Now I preselect element which was clicked and display its details on the right side.
https://stackblitz.com/edit/angular-mat-tooltip-ki4r2q?file=app/alert-dialog/alert-dialog.component.ts
try to use (selected) as input in mat-selection-list tag and then pass the parameter in the selectionChange Methode
If you want "mark as selected" a row, you can has a variable
selected:number=-1;
when you defined the mat-row, you add let i=index and you can change the style.background if i==selected, e.g.
<tr mat-row *matRowDef="let row; let i=index columns: displayedColumns;" [style.background-color]="i==selected?'red':null"></tr>
The last step if give value to the variable selected. For this, in a td, you can pass the row (futhermore the element)
<td mat-cell *matCellDef="let element;let i=index"
(click)="selected=i">
{{element.position}}
</td>
in this stackblitz if you "click" on "position", you see the row "selected".
In your case just in button you can add selected=i
<button (click)="selected=i;
onClick($event,(this.paginator.pageIndex == 0 ? i :
i + this.paginator.pageIndex * this.paginator.pageSize))">
Click
</button>
Don't forget if you want "des-select" equal the variable to -1
dialogRef.afterClosed().subscribe(result => {
this.selected=-1;
});

Remove the selected option from select box

I am making angular application with angular form.
Here i have given a form with input fields first name and last name which will always showing..
After that i am having children which will be displayed upon clicking the add button and the children will get removed on click remove button.
As of now everything works fine.
Here i am making patching of data to the inputs on click option from select box.. The neccessary inputs gets patched..
HTML:
<div>
<form (ngSubmit)="onSubmit()" [formGroup]="form">
<div *ngFor="let question of questions" class="form-row">
<ng-container *ngIf="question.children">
<div [formArrayName]="question.key">
<div *ngFor="let item of form.get(question.key).controls; let i=index" [formGroupName]="i">
<div *ngFor="let item of question.children">
<app-question [question]="item" [form]="form.get(question.key).at(i)"></app-question>
</div>
</div>
<select multiple (change)="changeEvent($event)">
<option *ngFor="let opt of persons" [value]="opt.key">{{opt.value}}</option>
</select>
</div>
</ng-container>
<ng-container *ngIf="!question.children">
<app-question [question]="question" [form]="form"></app-question>
</ng-container>
</div>
<div class="form-row">
<!-- <button type="submit" [disabled]="!form.valid">Save</button> -->
</div>
</form> <br>
<!-- Need to have add and remove button.. <br><br> -->
<button (click)="addControls('myArray')"> Add </button>
<button (click)="removeControls('myArray')"> Remove </button><br/><br/>
<pre>
{{form?.value|json}}
</pre>
</div>
TS:
changeEvent(e) {
if (e.target.value == 1) {
let personOneChild = [
{ property_name : "Property one" },
{ property_name : "Property two" },
]
for (let i = 0; i < personOneChild.length; i++) {
this.addControls('myArray')
}
this.form.patchValue({
'myArray': personOneChild
});
}
if (e.target.value == 2) {
let personTwoChild = [
{ property_name : "Property three" },
{ property_name : "Property four" },
{ property_name : "Property five" },
]
for (let i = 0; i < personTwoChild.length; i++) {
this.addControls('myArray')
}
this.form.patchValue({
'myArray': personTwoChild
});
}
}
addControls(control: string) {
let question: any = this.questions.find(q => q.key == control);
let children = question ? question.children : null;
if (children)
(this.form.get(control) as FormArray).push(this.qcs.toFormGroup(children))
}
removeControls(control: string) {
let array = this.form.get(control) as FormArray;
array.removeAt(array.length - 1);
}
Clear working stackblitz: https://stackblitz.com/edit/angular-x4a5b6-fnclvf
You can work around in the above link that if you select the person one option then the value named property one and property two gets binded to the inputs and in select box the property one is highlighted as selected..
The thing i am in need is actually from here,
I am having a remove button, you can see in demo.. If i click the remove button, one at last will be got removed and again click the last gets removed..
Here i am having two property one and two, if i remove both the inputs with remove button, the the highlighted value person one in select box needs to get not highlighted.
This is actually my requirement.. If i remove either one property then it should be still in highlighted state.. Whereas completely removing the both properties it should not be highlighted..
Hope you got my point of explanation.. If any needed i am ready to provide.
Note: I use ng-select for it as i am unable implement that library, i am making it with html 5 select box.. In ng-select library it will be like adding and removing the option.. Any solution with ng-select library also appreciable..
Kindly help me to achieve the result please..
Real time i am having in application like this:
Selected three templates and each has one property with one,two,three respectively:
If choose a dropdown then the property values for the respective will get added as children.
Here you can see i have deleted the property name three for which the parent is template three and the template three still shows in select box even though i removed its children
Firstly, get a reference to the select, like so:
HTML:
<select multiple (change)="changeEvent($event)" #mySelect>
<option *ngFor="let opt of persons" [value]="opt.key">{{opt.value}}</option>
</select>
TS:
import { ViewChild } from '#angular/core';
// ...
#ViewChild('mySelect') select;
Then, in your remove function, check if all elements have been removed, and if they have, set the value of the select to null
if (array.length === 0) {
this.select.nativeElement.value = null;
}
Here is a fork of the StackBlitz

Hide other elements in list

I have the below code:
<li *ngFor="let item of Array let i = index">
<span>
<label (dblclick)="editTag($event,i)">
{{item.tag}}
</label>
<input type="text" #tagInput />
</span>
</li>
The code is in a for loop. When I click on a label, all labels should be hidden and the input should be visible. Currently, when I click on each label, the other remain open. How do I hide the other span when clicking on any item?
I have below code in .ts
#ViewChild('tagInput') tagNameTextInput: ElementRef;
editTag(event: any,index: any) {
//console.info(event);
this.tagNameTextInput.nativeElement.hidden = true;
this.tagNameTextInput.nativeElement.previousElementSibling.hidden = false;
let initialValue = event.target.childNodes[0].nodeValue.trim();
event.target.hidden = true;
event.target.nextElementSibling.hidden = false;
event.target.nextElementSibling.value = initialValue;
console.log(index);
// this.checkListNameHidden = true;
// this.checkListNameTextInput.nativeElement.value = initialValue;
// this.checkListNameTextInput.nativeElement.focus();
event.stopPropagation();
}
How to solve this?
You have multiple children, So you need to use #ViewChildren instead of #ViewChild.
Also in your ngFor loop you do not have unique template reference #tagInput. Use QueryList with ElementRef.
Try : #ViewChildren('tagInput') tagNameTextInput: QueryList<ElementRef>;
instead of
#ViewChild('tagInput') tagNameTextInput: ElementRef;.
Import QueryList from #angular/core.
Like this import { Component, QueryList } from '#angular/core';
the best aproach is add a new property to "item", (e.g. called "editing") so
<li *ngFor="let item of Array let i = index">
<span>
<label *ngIf="!item.editing" (dblclick)="item.editing=true;">
{{item.tag}}
</label>
<input *ngIf="item.editing" [(ngModel)]="item.tag" type="text" (blur)="item.editing=false" />
</span>
</li>
See several things:
1.-in a click of label, the variable becomes true, so the inpùt is showed
2.-in blur of item, the variable becomes false, so the label is showed
3.-Use [(ngModel)] to relation between the input and the value

Categories

Resources