I need that when selecting several rows of a table in angular, it adds the amounts and shows them to me in the html.
I have managed to add the amounts after selecting the rows and pressing a button.
I need it to add the amounts as I select the rows (not when I press a button) and show it to me in a div in the html.
Can somebody help me?
This is what I have so far.
My html:
<tbody>
<tr *ngFor="let item of articulos; index as i" (click)="sumarCantidad(i)">
<td>{{item.articulo}}</td>
<td>{{item.cantidad}}</td>
<td>{{item.recogida}}</td>
</tr>
<br>
<button (click)="total()">CANTIDAD</button>
</tbody>
My ts:
export class EntryOrderLinesComponent implements OnInit {
selected: any;
articulos = ;
constructor(private datosService: DatosService, private fb: FormBuilder) {
this.articulos = [
{
articulo: ‘385/65X22.5 HANKOOK AH51 160K (3003836)’,
cantidad: ‘94’,
recogida: ‘0’,
},
{
articulo: ‘385/65X22.5 HANKOOK TH31 164K (3003309)’,
cantidad: ‘60’,
recogida: ‘0’,
},
];
this.selected = [];
}
sumarCantidad(i: number) {
const valor = this.articulos[i].cantidad;
this.articulos[i].cantidad = +valor;
this.selected.push(this.articulos[i]);
}
total() {
const total = this.selected.map((valor) => valor.cantidad);
console.log(
total.reduce((acumulado, valorActual) => acumulado + valorActual, 0)
);
}
My image
Thank you
Related
I have a form with some input fields.
When I submit the form I want to add a row to my table dataSource with the new data.
I have a component for the form that looks like that:
FORM HTML
<form (submit)="submitForm($event)">
<app-form-element align="center" *ngFor="let el of fields| keyobject" [value]="el.value.value" [type]="el.value.type">
</app-form-element>
<button>Save User</button>
</form>
FORM TS
#Component({
selector: 'app-form',
templateUrl: './form.component.html',
styleUrls: ['./form.component.css'],
})
export class FormComponent implements OnInit {
fields!: object;
constructor() { }
ngOnInit(): void {
this.newForm();
}
newForm() {
this.fields = [{ value: "Name", type: "text" },
{ value: "Surname", type: "text" },
{ value: "Email", type: "email" }];
}
tbc = new TableComponent;
submitForm(event: any) {
let newUser = new User();
newUser.name = event.target.Name.value;
newUser.surname = event.target.Surname.value;
newUser.email = event.target.Email.value;
this.tbc.addValue(newUser);
event.preventDefault();
}
}
export class User {
name!: string;
surname!: string;
email!: string;
}
TABLE HTML
<table *ngIf="show">
<tr>
<th *ngFor="let column of headers">
{{column}}
</th>
<th>Commands</th>
</tr>
<tr *ngFor="let row of dataSource | keyobject; let i = index">
<td *ngFor="let col of headers">
{{row.value[col]}}
</td>
<td>
<button class="btn btn-default" type="button" (click)="deleteValue(i)">Delete</button>
</tr>
</table>
TABLE TS
export class TableComponent implements OnInit {
headers = ['name', 'surname', 'email'];
dataSource: any = [
{ id: 1, name: "test", surname: 'test', email: "test#gmail.com"},
];
ngOnInit(): void {
}
addValue(user: User) {
let id = this.dataSource.length + 1;
this.dataSource = [...this.dataSource, { id: id, name: user.name, surname: user.surname, email: user.email, save: false }];
this.reload();
}
deleteValue(id: any) {
this.dataSource.splice(id, 1);
this.reload();
}
public show = true;
reload() {
this.show = false;
setTimeout(() => this.show = true);
}
}
When I call the addValue function in the Form.ts it works but the dataSource doesn't get updated.
Debugging the code everything works and it looks like the record is being added to the dataSource but the table dataSource doesn't actually have the new record so it doesn't get displayed.
Notice that my deleteValue is working fine and is deleting the row from the dable and from the dataSource
I'm new to angular so any help is appreciated
I think the problem is that the changes on dataSource array from your child component are not automatically detected on push. You can force the change detection using detectChanges from ChangeDetectorRef :
#Component({
...
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TableComponent implements OnInit {
contructor(
private cdr: ChangeDetectorRef
) {}
dataSource: any = [
{ id: 1, name: "test", surname: 'test', email: "test#gmail.com"},
];
addValue(user: User) {
let id = this.dataSource.length + 1;
this.dataSource.push({ id: id, name: user.name, surname: user.surname, email: user.email});
this.reload();
}
public show = true;
reload() {
// here you can force the change detection
this.cdr.detectChanges();
...
}
}
Even though, the other solution of the changeDetector might work, it's not the best approach to tell angular to refresh. It's better to instead, just put your code in a way that angular will notice that needs to change.
I believe that in angular, a push into the array, it's not detected as a new change.
I think instead of doing the push, you could do the following:
this.dataSource = [...this.dataSource, { id: id, name: user.name, surname: user.surname, email: user.email}]
Basically, you would create a new array that contains the old array + the new data.
Anyways, to be sure this is a correct answer, could you provide the actual code you have, not a small cut of it, with both TS and HTML Templates ?
I have a table whose data is coming from loop.Here when you press add button new similar row will be added at just bottom.Again when you press edit button all textbox will be enable(initially disable).Till now working fine.But when I check single checkbox or multiple checkbox and press delete button all the row based on checked checkbox will be delete/remove.Again when I click delete button without selecting any checkbox alert message should display and also when user selected all check boxes and tried to delete all the row an alert message should be there that 'at least one row should be there' and he cannot delete all rows unless any one row will be unchecked.I am new to angular can anyone please help me.Here is the code below https://stackblitz.com/edit/angular-wscsmy
app.component.html
<div class="container">
<h2>Basic Table</h2>
<p>The .table class adds basic styling (light padding and only horizontal dividers) to a table:</p>
<div><button (click)="enable()">Edit</button>
<button (click)="delete()">Delete</button> </div>
<table class="table border">
<tbody>
<tr *ngFor="let row of groups;let i = index" (click)="setClickedRow(i)" [class.active]="i == selectedRow">
<td> <input type="checkbox"></td>
<td> <input #focus [disabled]='toggleButton' type="text" value="{{row.name}}"> </td>
<td> <input [disabled]='toggleButton' type="text" value="{{row.items}}"> </td>
<td> <button (click)="addRow(i)">Add</button></td>
</tr>
</tbody>
</table>
</div>
app.component.ts
import { Component, ViewChild, ElementRef } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
selectedRow: Number;
#ViewChild('focus', { static: false }) input: ElementRef;
public toggleButton: boolean = true;
ngOnInit() {
}
groups = [
{
"name": "pencils",
"items": "red pencil"
},
{
"name": "rubbers",
"items": "big rubber"
},
{
"name": "rubbers1",
"items": "big rubber1"
},
];
addRow(index): void {
var currentElement = this.groups[index];
this.groups.splice(index, 0, currentElement);
}
enable() {
this.toggleButton = false
setTimeout(() => { // this will make the execution after the above boolean has changed
this.input.nativeElement.focus();
this.selectedRow = 0;
}, 0);
}
delete(){
alert('hello');
}
setClickedRow(index) {
this.selectedRow = index;
}
}
You have to create an array to keep track of the state of each checkbox. And update it every time a checkbox is checked or unchecked.
Template:
<td>
<input type="checkbox" (click)="toggleSelection($event, i)" [checked]="checkboxes[i]">
</td>
Component:
checkboxes: boolean[];
ngOnInit() {
this.checkboxes = new Array(this.groups.length);
this.checkboxes.fill(false);
}
toggleSelection(event, i) {
this.checkboxes[i] = event.target.checked;
}
Also, add another checkbox entry to the array whenever a new row is added.
addRow(index): void {
// Other code.
this.checkboxes.splice(index, 0, false);
}
You can use Array.splice() to delete elements from an array.
Array.some() can be used to check if at least one checkbox is selected, and Array.every() can be used to check if all the checkboxes are selected.
delete() {
var atleastOneSelected = this.checkboxes.some(checkbox => checkbox === true);
var allSelected = this.checkboxes.every(checkbox => checkbox === true);
if (!atleastOneSelected) {
alert("No rows selected.");
return;
}
if (allSelected) {
alert("At least one row should be present.");
return;
}
// Iterating in reverse to avoid index conflicts by in-place deletion.
for (let i = this.checkboxes.length-1; i >= 0; i--) {
// If selected, then delete that row.
if (this.checkboxes[i]) {
this.groups.splice(i, 1);
}
}
// Remove entries from checkboxes array.
this.checkboxes = this.checkboxes.filter(checkbox => checkbox === false);
}
Live demo on StackBlitz: https://stackblitz.com/edit/angular-abhkyk
Use a helper array, where you store all the checked checkboxes. Before deletion, check that at least one value is present.
I choose to store the indexes of the items to the helper array, and based on that, delete from the original array. So perhaps something like this:
toBeDeleted = [];
// called when button is clicked
delete() {
if (!this.toBeDeleted.length) {
alert('Choose at least one!');
} else if (this.toBeDeleted.length === this.groups.length) {
alert('You cannot delete all rows')
}
else {
this.groups = this.groups.filter((currentValue, index, arr) => !this.toBeDeleted.includes(index));
}
// reset the array
this.toBeDeleted = [];
}
remove(event, index) {
// check if checkbox is checked, if so, push to array, else delete from array
if (event.target.checked) {
this.toBeDeleted.push(index)
} else {
const idx = this.toBeDeleted.indexOf(index);
this.toBeDeleted.splice(idx, 1)
}
}
Then in your template, when user clicks on checkbox, call remove() and pass the $event and index of item:
<td> <input type="checkbox" (click)="remove($event, i)"></td>
STACKBLITZ
I'm using Spring Boot, Angular CLI and mySQL.
I have an Employee than can have one Marital Status, and one M Status can be in N Employees.
In localHost:8080 I get the right array json:
[{"id":1,"firstName":"Name","lastName":"surname1","emailAddress":"test#test1.com","status":{"statusId":1,"nameStatus":"Single"}
In my angular table(localHost:4200), instead I get every data but in Status column I get "[object Object]".
In have a service for each one.
When I do a registration I have a dropDown w/ all status so I get them.
This is my HTML table:
<table class="table table-bordered">
<thead>
<tr>
<th *ngFor="let col of columns">{{col}}
</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let employee of employees | paginate: {itemsPerPage: pageSize,
currentPage: page,
totalItems: employees.length} | filterAll: searchString : field">
<td *ngFor="let col of columns">{{employee[col]}}</td>
<td>
<button [ngClass]="getClassCondition(act.actionType)" *ngFor="let act of actions"
(click)="actionFunc(act, employee)">{{act.label}}</button>
</td>
</tr>
</tbody>
</table>
Here I have an ngFor that gets All employees.
Now I share also my services and my componets.ts:
status.service.ts:
#Injectable({
providedIn: 'root'
})
export class StatusService {
private baseUrl = 'http://localhost:8080/api';
constructor(
private http: HttpClient) { }
getStatus(): Observable<Status[]> {
return this.http.get<Status[]>(`${this.baseUrl}` + '/status');
}
}
employee.service.ts
const httpOptions = {
headers: new HttpHeaders({'Content-Type': 'application/json'})
};
#Injectable({
providedIn: 'root'
})
export class EmployeeService {
columns = COLUMNS;
actions = ACTIONS;
private baseUrl = 'http://localhost:8080/api/employees';
constructor(private http: HttpClient) {
}
getColumns() {
return this.columns;
}
getActions() {
return this.actions;
}
getMetadata() {
return this.metadata;
}
/** GET Employees from the server */
getEmployees(): Observable<Employee[]> {
return this.http.get<Employee[]>(this.baseUrl);
}
getEmployee(id: number): Observable<Employee> {
const url = this.baseUrl + '/' + id;
return this.http.get<Employee>(url);
}
/** PUT: update the employee on the server */
updateEmployee(employee: Employee): Observable<any> {
return this.http.put(`${this.baseUrl}/${employee.id}`, employee, httpOptions);
}
deleteEmployee(id: number): Observable<any> {
return this.http.delete(`${this.baseUrl}/${id}`, {responseType: 'text'});
}
}
Here I have also a const w/ COLUMNS name.
employee.ts
export const COLUMNS = ['id', 'firstName', 'lastName', 'emailAddress', 'status'];
export class Employee {
id: number;
firstName: string;
lastName: string;
emailAddress: string;
status: string;
}
status.ts
export class Status {
statusId: number;
nameStatus: string;
}
What do I have to do to get my status.Name?
Is there something specific?
If you need more documentation ask me.
I suspect that col return status and employee[col] return {"statusId":1,"nameStatus":"Single"}.
So the error seems correct.
You can do a workaround here if you just want to display the nameStatus :
<td *ngFor="let col of columns">{{employee[col]?.nameStatus ? employee[col]?.nameStatus : employee[col]}}</td>
You have to be more specific, how you display the data or map the data to the structure you want
1) instead of <td *ngFor="let col of columns">{{employee[col]}}</td>
you can do
<td>{{employee.firstName}}</td>
<td>{{employee.lastName}}</td>
...
<td>{{employee.status.nameStatus}}</td>
2) before binding the data, map it to the structure you want (in your controller/*.ts file).
Take a look at Array map( for that.
Your code doesn't seem to work because the controller never assigns the employee method
I have to modify the following code with an implementation of an Array of actions (bottom page).
I saw lots of websites by I wasn't able to find something than can be used for my code.
I will have to change my html , my tableService, my component.ts and oviously my actionConfiguration.
At the moment this is my HTML:
<div class="container">
<table class="table">
<tr>
<th *ngFor="let col of columns" (click)="sortTable(col)">{{col}}</th>
<th>Actions</th>
</tr>
<tr *ngFor="let user of users | paginate: {itemsPerPage: 5,
currentPage: page,
totalItems: users.length } ; let i = index">
<td *ngFor="let col of columns">{{user[col]}}</td>
<td>
<button [ngClass]="getClassCondition(act)" *ngFor="let act of actions" (click)="actionFunc(act,i)">{{act}}</button>
</td>
</tr>
</table>
</div>
<div>
<pagination-controls (pageChange)="page = $event"></pagination-controls>
</div>
This is my component.ts:
#Component({
selector: 'app-dynamic-table',
templateUrl: './dynamic-table.component.html',
styleUrls: ['./dynamic-table.component.css']
})
export class DynamicTableComponent implements OnInit {
#Input()
users = [];
#Input()
columns: string[];
#Input()
actions: string[];
#Input()
class;
direction = false;
page: any;
constructor() {
}
sortTable(param) {
/*done*/
}
actionFunc(i, index) {
if (i === 'deleteUser') {
if (confirm('Are you sure you want to delete this item?') === true) {
this.users.splice(index, 1);
}
}
if (i === 'editUser') {
/*...*/
}
}
getClassCondition(act) {
return act === 'deleteUser' ? this.class = 'btn btn-danger' : 'btn btn-primary' ;
}
ngOnInit(): void {
}
}
This is my tableService.ts
import { USERS } from './mock-data';
#Injectable()
export class TableService {
constructor() { }
static getUsers(): Observable<any[]> {
return Observable.of(USERS).delay(100);
}
static getColumns(): string[] {
return ['id', 'firstName', 'lastName', 'age'];
}
static getActions(): string[] {
return ['deleteUser', 'editUser'];
}
}
Here's the new Task, I have to create an Array of Actions so I will be able to use it in different components but I have no idea how to do it.
I have to start from something like this, it's just an example (not complete because I don't know what to insert exactly):
actionConfig.ts
export const ACTIONS = [
{
label: 'Remove',
actionType: 'deleteUser',
},
{
label: 'Edit',
actionType: 'editUser',
},
];
A sample of Enum and a table to show data on iterating on them:
StackBlitz
You also might want to read typescript-enums-explained
Basically, the TypeScript enums are compiled to something as shown below for reverse lookup. Thats why I have added the foreach loop in constructor and created another list.
export enum Fruits {
APPLE = 'Apple',
MANGO = 'Mango',
BANANA = 'Banana',
}
is compiled to
var Fruit;
(function (Fruit) {
Fruit[Fruit["APPLE"] = 'Apple'] = "APPLE";
Fruit[Fruit["MANGO"] = 'Mango'] = "MANGO";
Fruit[Fruit["BANANA"] = 'Banana'] = "BANANA";
})(Fruit || (Fruit = {}));
UPDATE
HTML
<button [ngClass]="getClassCondition(act.actionType)" *ngFor="let act of actions"
(click)="actionFunc(act, user)">{{act.label}}</button>
COMPONENTS.TS
actionFunc(action, element: any) {
if (action.actionType === 'DELETE') {
if (confirm('Are you sure you want to delete this item?') === true) {
/*...*/
}
}
if (action.actionType === 'GO_TO') {
/*...*/
}
}
actionsConfig.ts
export const ACTIONS = [
{
label: 'Delete',
actionType: 'DELETE',
deleteApi: 'api/USERS'
},
{
label: 'Edit',
actionType: 'GO_TO',
getUrl: row => '/detail/' + row.id,
},
];
i'm trying to render the rows in the table after request.
i can see the the response in the browser and i am pushing the new data to the
ROWS: object,
but the table is not refreshing the rows in table.
sample code:
import {Component, OnDestroy, OnInit} from '#angular/core';
import { Subject } from 'rxjs';
import { XXXXXXXService } from './NAME.service';
#Component({
selector: 'app-NAME',
templateUrl: './NAME.component.html',
styleUrls: ['./NAME.component.scss']
})
export class XXXXXXXComponent implements OnDestroy, OnInit {
dtOptions: DataTables.Settings = {};
rows = [];
dtTrigger: Subject<any> = new Subject();
constructor(private XXXXXXXService: XXXXXXXService) { }
ngOnInit(): void {
this.rows.length = 0;
this.dtOptions = {
pagingType: 'full_numbers',
pageLength: 25
};
this.class.getRows()
.subscribe(rows => {
console.log(rows);
this.rows = rows;
// Calling the DT trigger to manually render the table -- not working!!!
this.dtTrigger.next();
});
}
render_rows_filters(filter) {
this.class.getRowsFiltered(filter).subscribe(
rows => {
this.rows = rows;
this.dtTrigger.next();
}
);
}
ngOnDestroy(): void {
this.dtTrigger.unsubscribe();
}
}
html
<table datatable [dtOptions]="dtOptions" [dtTrigger]="dtTrigger" class="table-bordered">
<!--class="row-border table-bordered hover">-->
<thead>
<tr>
<th> NAME</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of rows">
<td>{{ row.Name }}</td>
</tr>
</tbody>
</table>
Ok,
the thing is that when you use angular with components and services, one component can't declare the DataTable Element to another component running in the same page.
the solution was to create a outside (Global) service and pass all the component variables.
then running all the functions in the Service with the component variables and child's.
Thank you all... =)
This is best way to refresh data on search .. or dynamic loading
angular-datatables/#/advanced/rerender
datatable refresh
Click on button press table grid refresh
$('#Clienttbl').dataTable().fnClearTable();