How to change Toggle Value for only 1 row not all - javascript

I have a mat-toggle as a column in Mat-table.I am changing values on toggle on/off. However the issue is if I change the value then the value changes for all the rows. I want to do it only for the particular row. How can I do it.
HTML Code:
<ng-container matColumnDef="active">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Reschedule</th>
<td mat-cell *matCellDef="let element">
<mat-slide-toggle (change)="setMessage($event)">{{
message
}}</mat-slide-toggle>
</td>
</ng-container>
Typescript Code:
// Toggle Button Code
message = 'Disabled!';
setMessage(e) {
if (e.checked) {
this.message = 'Running';
} else {
this.message = 'Disabled!';
}
}

You need a property for every row to bind your toggle state to.
E.g.:
Component data:
....
const ELEMENT_DATA: PeriodicElement[] = [
{ position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H', activate: true, role: '1' },
...
Template:
...
<!-- toggle olumn -->
<ng-container matColumnDef="toggle">
<th mat-header-cell *matHeaderCellDef> toggle </th>
<td mat-cell *matCellDef="let element" >
<mat-slide-toggle [checked]="element.activate" (change)="updateActiveStatus(element)"></mat-slide-toggle>
</td>
</ng-container>
...
Check this Stackblitz for a working version.

Related

Mat-Table from angular materials not displaying data from firebase

I'm using Angular, NgRedux and firebase (real time database). I'm trying to display my fetched data into a mat-table from Angular/material. I can see the data in the console, but not in the table. I can only display my local data in the table as you can see in my events.component.html temple down bellow.
I'm quite new with Angular. Any help will be highly appreciated.
here is my events.component.ts file
import { NgRedux } from '#angular-redux/store';
import { Component, OnInit } from '#angular/core';
import { MatTableDataSource } from '#angular/material/table';
import { Router } from '#angular/router';
import { Event } from '../entities/Event';
import { EventeActions } from '../store/actions/EventAcitons';
import { AppState } from '../store/Store';
#Component({
selector: 'app-events',
templateUrl: './events.component.html',
styleUrls: ['./events.component.scss']
})
export class EventsComponent implements OnInit{
public events: Event[];
private availableEvents: Event[] = [
{
event: 'Picnic',
date: '12/02/2021',
location: 'Rådhusstrædet',
status: 'published'
},
{
event: 'Surfing',
date: '11/04/2021',
location: 'København V',
status : 'draft'
},
];
displayedColums = ['event', 'date', 'location', 'status'];
dataSource = new MatTableDataSource<Event>();
getAvailableEvents() {
return this.availableEvents.slice();
}
constructor(
private router: Router,
private ngRedux: NgRedux<AppState>,
private eventActions: EventeActions
) { }
ngOnInit(): void {
this.eventActions.readEvent();
// this.dataSource.data = this.getAvailableEvents();
this.ngRedux.select(state => state.events).subscribe(res => {
this.events = res.events;
})
}
editPost(id: any) {
this.router.navigate(['neweditevent', {myId: id}])
}
}
and here is my events.component.html file
<h1 class="title">Planned Events</h1>
<div class="flexHeader">
<button mat-raised-button color="primary" routerLink="/neweditevent" id="newEditBtn">New Event</button>
</div>
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<ng-container matColumnDef="event">
<th mat-header-cell *matHeaderCellDef> Event </th>
<td mat-cell *matCellDef="let element"> {{element.event}} </td>
</ng-container>
<ng-container matColumnDef="date">
<th mat-header-cell *matHeaderCellDef> Date </th>
<td mat-cell *matCellDef="let element"> {{element.date | date}} </td>
</ng-container>
<ng-container matColumnDef="location">
<th mat-header-cell *matHeaderCellDef> Location </th>
<td mat-cell *matCellDef="let element"> {{element.location}} </td>
</ng-container>
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef> Status </th>
<td mat-cell *matCellDef="let element"> {{element.status}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColums"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColums;"></tr>
</table>
Thank you in advance...
Try something like this
ngOnInit(): void {
this.eventActions.readEvent();
// this.dataSource.data = this.getAvailableEvents();
this.ngRedux.select(state => state.events).subscribe(res => {
this.events = res.events;
this.dataSource.data = this.events;
})
}

How to push FormArray without new fields than in existing fields

How to push new values at the click of a button in formArray without adding new fields. Fields already exist, which means I don't need new ones, I just need new values from those fields entered.
Look at my code:
<form [formGroup]="form" (submit)="submit()">
<div *ngFor="let data of contactFormGroup.controls; let i = index;" formArrayName="data">
<div [formGroupName]="i">
<mat-form-field>
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Pretraži prozivod...">
</mat-form-field>
<table mat-table [dataSource]="productSource" matSort class="mat-elevation-z8">
<!-- Position Column -->
<ng-container matColumnDef="id">
<th mat-header-cell mat-sort-header *matHeaderCellDef> Broj Proizvoda </th>
<td mat-cell *matCellDef="let element" > {{ element.id }} </td>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<th mat-header-cell mat-sort-header *matHeaderCellDef> Naziv proizvoda </th>
<td mat-cell *matCellDef="let element"> {{ element.name }} </td>
</ng-container>
<!-- Weight Column -->
<ng-container matColumnDef="description">
<th mat-header-cell mat-sort-header *matHeaderCellDef> Opis proizvoda </th>
<td mat-cell *matCellDef="let element"> {{element.description}} </td>
</ng-container>
<!-- quantity Column -->
<ng-container matColumnDef="images" class="test" >
<th mat-header-cell mat-sort-header *matHeaderCellDef> quantity</th>
// i need this values but on click add new object in formArray
<td mat-cell *matCellDef="let element" class="test"> <input formControlName="quantity" type="text"> </td>
</ng-container>
<ng-container matColumnDef="images2">
<th mat-header-cell mat-sort-header *matHeaderCellDef> Add new </th>
<td mat-cell *matCellDef="let element"> <button mat-raised-button color="primary">Add new</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr (click)="test(row.id)" mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSizeOptions]="[5,10,20]" showFirstLastButtons></mat-paginator>
<div class="button-submit">
<button (click)="openDialog2()" mat-raised-button color="warn">
Posalji narudzbu
</button>
</div>
</div>
</div>
</form>
Ts file:
ngOnInit() {
this.productSource.sort = this.sort;
this.productSource.paginator = this.paginator;
this.getProducts();
this.form = this.fb.group({
deliveryDate: [''],
data: this.fb.array([this.createContact()]),
note: [null]
});
this.contactList = this.form.get('data') as FormArray;
}
createContact(): FormGroup {
return this.fb.group({
id: ['', Validators.required],
quantity: ['', Validators.required]
});
}
addContact() {
this.contactList.push(this.createContact());
}
This code works well when I set fields and add function addContact(). When click show new fields and work good but in this situation, I don't want new fields. I have existing fields only to enter a quantity and push id and quantity in new FormArray.
This is an example what I need: https://ibb.co/1Tj2HNc
ON click button add new. If you have any question just ask
The current code works on principle when I add the first product:
console.log(my form.values)
data: Array(1)
0: {id: "", quantity: "99"}
And this is good only need id but ok... But when I add new quantity for new fields example 15 for another field and console.log my form values:
data: Array(1)
0: {id: "", quantity: "15 "}
override the old value and enter the new value.
It should add a new object in array with that value.
Example:
data: Array(2)
0: {id: "", quantity: "99"}
1: {id: "", quantity: "15"}
Also i need id :)
EDIT:
I forgot a piece of code:
get contactFormGroup() {
return this.form.get('data') as FormArray;
}
just create new function that accepts the index you want to insert the data into and the object you want to insert and it should do what you want.
assignContactForm(index: number, data: any): void {
// data is object of type {id: number, quantity: number }
this.contactFormGroup.controls[i].patchValue(data);
}

Why I can't get result from parent component in Angular

I want child components in angular to separate Material Table(child) from other elements(parent), but the weird thing is that it seems I cannot get data from the parent or I get initialized data from parents and cannot refresh.
Here is the Code:
firstly, the parent .ts file:
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss']
})
export class DashboardComponent implements OnInit{
ticketList: Ticket[] = [];
originalTicketList: Ticket[] = [];
filterAllForm: FormGroup;
labelList: string[];
homeLabelList: string[];
currentTicketId: string;
searchBy: string = '';
maxall : number = 100;
isLoading :boolean = true;
showRelatedTickets = true;
constructor(private ticket: TicketService,
private formBuilder: FormBuilder) { }
ngOnInit() {
this.filterAllForm = this.formBuilder.group({
startDate: [''],
endDate: ['']
});
this.getAllTicket();
}
get filterFormControls() { return this.filterAllForm.controls; }
getAllTicket() {
let queryParams = '';
console.log(this.currentTicketId) + " " + this.searchBy;
if (this.searchBy === 'id') {
queryParams = 'id=' + this.currentTicketId;
this.showRelatedTickets = true;
}else if(this.searchBy !== ''){
queryParams = this.searchBy + '=' + this.currentTicketId;
this.showRelatedTickets = false;
}
this.ticket.getAllTicket(queryParams).then((res: Ticket[]) => {
this.isLoading = false;
this.ticketList = res;
this.originalTicketList = this.ticketList;
});
}
searchTicket() {
this.isLoading = true;
this.getAllTicket();
}
}
the parent html like this:
<div class="ticket-container">
<mat-card *ngIf="isLoading" class="mat-card-style">
<mat-progress-spinner color="primary" mode="indeterminate">
</mat-progress-spinner>
</mat-card>
<div *ngIf="showRelatedTickets">
<app-dashboard-related-tickets-table [tablesource]="ticketList">
</app-dashboard-related-tickets-table>
</div>
<div *ngIf="!showRelatedTickets">
<app-dashboard-non-related-tickets-table [tablesource]="ticketList">
</app-dashboard-non-related-tickets-table>
</div>
</div>
and there are two children you can see, one is app-dashboard-related-tickets-table and another one is app-dashboard-non-related-tickets-table, they have a different format and changed by the button
showRelatedTickets. Here I will show the first one
the child(app-dashboard-related-tickets-table) .ts file:
#Component({
selector: 'app-dashboard-related-tickets-table',
templateUrl: './dashboard-related-tickets-table.component.html',
styleUrls: ['./dashboard-related-tickets-table.component.scss']
})
export class DashboardRelatedTicketsTableComponent implements OnInit, AfterViewInit{
dataSource: any;
displayedDetailColumns = ['id', 'caseStatus', 'anchorPoint', 'findingSourceSystem','caseCreateTimestamp', 'resolvedBy', 'resolution', 'resolutionNote'];
maxall: number = 100;
#Input() tablesource: Ticket[];
#ViewChild(MatPaginator, {static: false}) paginator: MatPaginator;
#ViewChild(MatSort, { static: true }) sort: MatSort;
applyFilter(filterValue: string) {
this.dataSource.filter = filterValue.trim().toLowerCase();
}
constructor() { }
ngOnInit() {
console.log(this.tablesource);
this.dataSource = new MatTableDataSource(this.tablesource);
}
ngAfterViewInit(){
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
this.getPageSizeOptions();
}
getPageSizeOptions(): number[] {
if (this.dataSource.data.length>this.maxall){
return [20, 50, this.dataSource.data.length];
}else{
return [20, 50, this.maxall];
}
}
}
then the child(app-dashboard-related-tickets-table) .html file:
<table mat-table matTableExporter [dataSource]="dataSource" matSort class="mat-elevation-z8"
#exporter="matTableExporter">
<!-- Ticket Column -->
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef mat-sort-header class="mat-column-id-source"> SIR ID </th>
<td mat-cell *matCellDef="let element" class="mat-column-id-source">
<a href='ticket/{{element.id}}'>{{element.id}}</a>
</td>
</ng-container>
<!-- Type Column event source -->
<ng-container matColumnDef="findingSourceSystem">
<th mat-header-cell *matHeaderCellDef mat-sort-header class="mat-column-id-source"> Source </th>
<td mat-cell *matCellDef="let element" class="mat-column-id-source"> {{element.findingSourceSystem}} </td>
</ng-container>
<!-- Type Column Related Event count -->
<ng-container matColumnDef="anchorPoint">
<th mat-header-cell *matHeaderCellDef class="mat-column-related-ticket-num"> Related Cases </th>
<td mat-cell *matCellDef="let element" class="mat-column-related-ticket-num">
{{element.relatedVertices}} </td>
</ng-container>
<!-- Type Column event source -->
<ng-container matColumnDef="caseStatus">
<th mat-header-cell *matHeaderCellDef mat-sort-header class="mat-column-case"> Case Status </th>
<td mat-cell *matCellDef="let element" class="mat-column-case"> {{element.caseStatus}} </td>
</ng-container>
<!-- Type Column event source -->
<ng-container matColumnDef="caseCreateTimestamp">
<th mat-header-cell *matHeaderCellDef mat-sort-header class="mat-column-date"> Case Created </th>
<td mat-cell *matCellDef="let element" class="mat-column-date">
{{element.caseCreateTimestamp | date:'MMM d, y, h:mm:ss a'}}
</td>
</ng-container>
<ng-container matColumnDef="resolvedBy">
<th mat-header-cell *matHeaderCellDef class="mat-column-resolvedBy"> Resolved By </th>
<td mat-cell *matCellDef="let element" class="mat-column-resolvedBy"> {{element.resolvedBy}}
</td>
</ng-container>
<ng-container matColumnDef="resolution">
<th mat-header-cell *matHeaderCellDef class="mat-column-closeCode"> Close Code </th>
<td mat-cell *matCellDef="let element" class="mat-column-closeCode"> {{element.resolution}}
</td>
</ng-container>
<ng-container matColumnDef="resolutionNote">
<th mat-header-cell *matHeaderCellDef class="mat-column-closeNote"> Close Note </th>
<td mat-cell *matCellDef="let element" class="mat-column-closeNote"> {{element.resolutionNote}}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSizeOptions]="getPageSizeOptions()" showFirstLastButtons></mat-paginator>
<button mat-raised-button (click)="exporter.exportTable('csv')" class="export-button">Export Results</button>
So in the child component, I use #input tablesource, and display dataSource. but the result is like this:
The child component seems loaded because the export result button is already there, but the table didn't show. I just to do
console.log(tablesource)
I got []
This is the browser console log:
Any Idea what happened?
I was trying to reproduce here: https://stackblitz.com/edit/angular-hbzpvr
but I am sorry, I am not good at angular, so I am not sure how to load parent to page.
According to your console output, you use tablesource in your child component before it has been updated by the parent component. Instead of creating datasource in ngOnInit of the child component, define the tablesource property as a setter and create datasource in that setter:
#Input() set tablesource(value: Ticket[]) {
console.log(value);
this.dataSource = new MatTableDataSource(value);
}
See this stackblitz for a demo.

How to connect form with outside button and extract data without refreshing page

I have such issue I need to extract data from:
<ng-container matColumnDef="title">
<th mat-header-cell *matHeaderCellDef> Title </th>
<td mat-cell *matCellDef="let row"><div id="{{'make_editable' + row.title}}">{{row.title}}</div></td>
</ng-container>
...
<ng-container matColumnDef="buttonEdit">
<th mat-header-cell *matHeaderCellDef> buttonEdit </th>
<td mat-cell *matCellDef="let row"><button (click)="makeEditable(row.title)" class="mat-raised-button" form="myform">Edit</button></td>
/ng-container>
makeEditable(title){
console.log(this.checkOutForm.value.title);
let id:string="make_editable"+title;
if(this.toggleEdit()){
document.getElementById(id).innerHTML = `<form id="myform" (ng-submit)="extractFormValues()" [formGroup]="checkOutForm"><input type="text" value="${title}"></form>`;
}
else {
document.getElementById(id).innerHTML = title;
console.log(this.checkOutForm.controls.title.value);
}
The button is outside the function. If edit button is clicked then input wraps data and make it active. I need to do it without refreshing all page.The button Edit is outside of the form
You could create on the type, that the rows have, a boolean property - isEdited.
makeEditable(title) would find the correct row and toggle its isEdited value. It would also set:
checkOutForm.setValue({title: title});
(if isEdited was set to true).
In the template you would wrap the whole block in
<form id="myform" (ng-submit)="extractFormValues()" [formGroup]="checkOutForm"</form>
and change the td for a title:
<td mat-cell *matCellDef="let row">
<div *ngIf="!row.isEdited">{{row.title}}</div>
<input *ngIf="row.isEdited" type="text" formControlName="title">
</td>
This only works if just one row is edited at once.

Color cell from mat table angular

I've got this:
Array of objects:
users : User [];
average = 5;
compareValue (value){
...}
And im printing a table: like this:
<table mat-table [dataSource]="users">
<ng-container matColumnDef="nome">
<th mat-header-cell *matHeaderCellDef >Name</th>
<td mat-cell *matCellDef="let element" > {{element.name}} </td>
</ng-container>
<ng-container matColumnDef="num_aval">
<th mat-header-cell *matHeaderCellDef >Number of Works</th>
<td mat-cell *matCellDef="let element"> {{element.works.length}} </td>
</ng-container>
<ng-container matColumnDef="comparaMedia">
<th mat-header-cell *matHeaderCellDef >Stats</th>
<td *matCellDef="let element" > HELP HERE </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
What I wanna do is the following:
I wanna grab the number of works from an user, compare with the value average (with the function compareValue), and if the value is under some value, color the cell with blue; if it's above, color the cell with red.
I have no ideia how to do it. Some help?
You can add a class conditionally to your td as
<td mat-cell *matCellDef="let element" [class.red]="element.works.length > average"> {{element.works.length}} </td>
And add styles to your component as
td {
background-color: blue; /* the default color is blue for the cells */
}
td.red {
background-color: red; /* more specific style to override color to red */
}
I assume compareValue func returns true if value in cell is higher than average and false when it isn't, so I would use
and than use it to setting background color for number of works value cell
<td mat-cell *matCellDef="let element"
[style.background-color]="compareValue(element.works.length) ? 'blue' : 'red'">
{{element.works.length}}
</td>

Categories

Resources