Change the style of specific items inside ngFor - html

I have a set of icons that are displayed using ngFor like this:
<mat-chip *ngFor="let category of categories" (click)="selected(category)" [selected]="category.selected" [matTooltip]="category.name">
<mat-icon id="iconBar"> {{category.icon}} </mat-icon>
</mat-chip>
and I am trying to change the color of one specific icon on a button press, my trial is to have this function executes when the button is pressed:
recolorRequired(){
var loopedIcon = document.getElementById("iconBar");
console.log(loopedIcon.textContent);
var requiredIcon = loopedIcon.textContent;
//recolor
}
The result of console.log(loopedIcon.textContent); is the first icon only, from my understanding that because I am using same id for multiple elements? is there a way I can obtain information about the whole icon collection from ngFor?

Yea it is because you are using an id in a loop, id is usually not meant to be used on multiple items, you can use a class instead.
<mat-chip *ngFor="let category of categories" (click)="selected(category)" [selected]="category.selected" [matTooltip]="category.name">
<mat-icon class="iconBar"> {{category.icon}} </mat-icon>
</mat-chip>
your function becomes
recolorRequired(){
var iconBars = document.getElementsByClassName("iconBar");
//iconBars will be an array of elements who has iconBar as class
//loop through iconBars and find the element you want
//recolor
}

Related

Is there any way to add href link for mat-chips component as property or attribute

I am trying to add a new icon and possibly a href on the mat-chip component but I want it as properties and not to hardcode into that.
So the idea is to have it as a component so I can call it from another component and give data.
For example links, and icons are on the left side and right sides.
Icons on left should be an edit icon and the right will be default remove.
But at the hovering, both of them need to be highlighted.
So let's say if from another component we define the left icon then it will be shown and if not then will be not shown.
Or can it be done within a directive too?
I have till now created like this but I think I need more to do on that.
See stackblitz.
Maybe instead of ngIf is any other way to use it.
But I want for example that in the child component to send the index so then I can use it into href.
But in the child, I cannot use the index so I can iterate through the components and use the href for each of them and I want to use this component for different data.
see components in stack blitz.
users and group components.
1 of them has a variable name and the other one has a username.
https://stackblitz.com/edit/angular-3vp4xw-a9jeot?file=src/app/chips-autocomplete-example.ts
What about somethin like that :
You create a component like 'mat-chip-link':
<mat-chip *ngFor="let fruit of fruits" (removed)="remove(fruit)">
<ng-content select="[.beforeLink]"></ng-content>
<a
[href]="link"
class="mat-standard-chip"
target="_blank"
style="margin: 0; padding: 0"
>My link</a
>
<ng-content select="[.afterLink]"></ng-content>
</mat-chip>
(I am not sure about the ng-content selector, check the doc here for more info. https://angular.io/guide/content-projection).
Which has an input like #Input link: string;
Then from the parent you can call this component like that
<mat-chip-link *ngFor="let fruit of fruits" (removed)="remove(fruit)" [link]="test">
<mat-icon matChipRemove class="beforeLink" *ngIf="editable">cancel</mat-icon>
<mat-icon matChipRemove class="afterLink" *ngIf="removable">cancel</mat-icon>
</mat-chip>
It might be done easier, for example (Typescript):
Template of custom component mat-chip-link
<mat-chip-link (click)="this.clickEventHandler($event)"/>
<mat-chip>
<ng-content>
</ng-content>
</mat-chip>
</mat-chip-link>
Component
private _href: string | null = null;
#Input('href') public set href(value: string | null) {
this._href = value;
}
public clickEventHandler(e: MouseEvent) {
if(this._href !== null) {
window.open(this._href, '_blank');
} else {
console.log('No href specifief');
}
}
Usage
<mat-chip-link [href]="https://www.stackoverflow.com">
Jump to StackOverflow 🙌🏼
</mat-chip-link>

Bind id to Angular mat-checkbox

I want to bind id to Angular material checkbox.
I have an object item.
When I inspect html I have item.id + '-input'
But when I bind name it's okay: item.id
This is my code:
<mat-checkbox [id]="item.id"[name]="item.id">
i havent worked with Material yet but in native angular you can assign IDs via a component by [id]="{{item.id}}".
If your using an obejct array[] of items, you can also try iterating through your array to create Mutliple entrys like so.
<div class="subbox text-center"
*ngFor="let i of item">
<mat-checkbox [id]="{{i.id}}" [name]="{{i.name}}">
</div>

How to disable item from different component in Angular

So I have Tags component and I imported that component in my Chart-details component. In my Chart Details component I have a checkbox that will disable all the input box, drop down box, buttons that are located inside chart-details page but some reason my imported tags component is not disabling when I click the checkbox. Any suggestion or help on how to fix this so that a user cannot add or remove tags when the checkbox is clicked will be really appreciated.
Chart Details Component. HTML
//Check box to disable all the input, drop down, buttons
<mat-checkbox *ngIf="chart && workspace" color="primary" [disabled]="this.workspace.type === WorkspaceType.user"
[(ngModel)]="chart.isPublished" (ngModelChange)="publishChange($event)">Published</mat-checkbox>
//Example Button
<button color="primary" mat-flat-button (click)="saveClick()" [disabled]="this.chart.isPublished">Save</button>
// Imported Tags Component
<mc-tags [_normalTags]="chart.tags" [removable]="true" [selectable]="true"
(added)="tagAdded($event)" (removed)="tagRemoved($event)" [disabled]="this.chart.isPublished" >
</mc-tags>
I have added [disabled]="this.chart.isPublished" but I got an error saying "Can't bind to 'disabled' since it isn't a known property of 'mc-tags'. ". Also I tried (disabled) but still not working and user can still add or remove tags even though checkbox is checked.
Tags Component.HTML
<mat-chip-list #chipList [disabled]="true">
<mat-chip *ngFor="let chip of normalTags" [selectable]="selectable"
[removable]="removable"
(removed)="removeTags(chip)">
{{chip.tag}}
</mat-chip>
<input matInput #input [(ngModel)]="tagIn" [formControl]="tagCtrl2"
[matAutocomplete]="auto" />
</mat-chip-list>
Right now I have to do [disabled]="true" on mat-chip-list in Tags component.html so that user can't add or remove it. I don't want to hard code this and want to control this using Chart Detail Component Checkbox.
The disable matchip and input look like this (PIC)
It's not gonna run but I've attached the whole code for these two component over here https://stackblitz.com/edit/angular-ivy-wwfcai . thanks
Have you declared "#Input() disabled" in your child component class?
In Child.component.ts
#Input() disabled: any;
ngOnInit() {
if(disabled){
//set properties to true/false accordingly
}
}
In Parent.component.html
[disabled]="this.workspace.type === WorkspaceType.user"

Change selected mat-chips within/after selectionChange

The concept is that I want to filter displayed information on a page based on which mat-chips are selected.
The HTML:
<mat-chip-list [multiple]="true">
<mat-chip
class="item-filter-mat-chip"
*ngFor="let itemFilter of itemFilters"
[selectable]="true"
[selected]="itemFilter.selected"
[value]="itemFilter"
(selectionChange)="updateItemFilter($event)"
(click)="chip.toggleSelected()"
#chip="matChip">
{{itemFilter.displayValue}}
</mat-chip>
</mat-chip-list>
The TypeScript item:
export interface ItemFilter {
itemType: ItemType[];
displayValue: string;
selected: boolean;
}
However I want one of the mat-chips to be the "default" that is selected if all other chips are not selected. However it seems like the logic to do the selection change has to happen in updateItemFilter, which then creates an ExpressionChangedAfterItHasBeenCheckedError. This is because I'm trying to change the selection values inside of the selectionChange method called.
The situation is this. The default filter is selected. Once a different filter is selected, the default filter should be de-selected. Multiple other filters can be selected. If the default filter is selected, all other filters should be de-selected.
After digging in, the fix appears to be no longer use (selectionChange) on the mat-chip and instead change the selection AND update the filter inside a custom (click) method.
<mat-chip-list [multiple]="true">
<mat-chip
class="item-filter-mat-chip"
*ngFor="let itemFilter of itemFilters"
[selectable]="true"
[selected]="itemFilter.selected"
[value]="itemFilter"
(click)="updateItemFilter(chip)"
#chip="matChip">
{{itemFilter.displayValue}}
</mat-chip>
</mat-chip-list>

Displaying hidden Div element at specific index using Angular Material table

I have a mat-table which has the following functionality: -
(1) Add / Remove rows
(2) Add data into a row using various controls (combo-box, text box, etc).
One of the controls (Addition Information) is a text box that when a ? is entered displays a hidden 'div' element that will eventually be used to hold a list of data.
The issue I have is that if I add say 3 rows and enter a ? into the 3rd row the hidden 'div' display on all 3 rows.
I need a way to somehow index each row added to the table and only display the 'div' element of that row.
Unfortunately my knowledge of HTML is limited and I am fairly new to Angular as well.
I have created a StackBlitz solution demoing my issue. demo
HERE'S A WORKING STACKBLITZ I created an array expandedCols : boolean[] = []; that keeps track of the state (expanded or not) of your div, when you add a row, I also add one to that array with default value false, when you put ? I just change the value at index i to true.
<ng-container matColumnDef="additionalCode" class="parent" >
<th mat-header-cell *matHeaderCellDef>Additional Code</th>
<td mat-cell *matCellDef="let element; let i = index" class="parent" >
<mat-form-field class="type">
<input matInput (keyup)="toggleLookup($event, i)" autocomplete="off" (keydown.ArrowDown)="onDown()" placeholder="Enter ?">
</mat-form-field>
<div *ngIf="expandedCols[i] == true" class="child">Yah it expanded
<button (click)="expanded = false">Close</button>
</div>
</td>
</ng-container>
TS:
addRow() {
this.doAddRow();
this.expanded = false;
this.expandedCols.push(false);
}
toggleLookup(event: any, i): void {
if (event.target.value !== '?') {
return;
}
event.target.value = '';
this.expanded = true;
this.expandedCols[i] = true;
}
You should also pay attention to removing rows, do splice, you get the idea.
The proper way to solve your issue is to use row local state - so put your attribute inside column collection (new column is hidden). This way you will have an opportunity to manage expanded property of specific row. Here is your updated stackblitz.