[英]How can I make batchEdit available for json nested nodes as well?
嗨 Stackoverflow 成員
我也想為子節點提供批量編輯,但我無法實現。
任何人都可以查看代碼並建議我進行更改,以便批量編輯可用於父節點和嵌套記錄節點。
app.component.html
<div class="container-fluid">
<!-- Add Record -->
<div *ngIf="isAdd">
<form #myForm="ngForm">
<div class="form-group">
<label>First Name</label>
<input type="text" name="first_name" class="form-control" ngModel>
</div>
<div class="form-group">
<label>Last Name</label>
<input type="text" name="last_name" class="form-control" ngModel>
</div>
<div class="form-group">
<label>Email</label>
<input type="email" name="email" class="form-control" ngModel>
</div>
<div class="form-group">
<label>Gender</label>
<select name="gender" id="" ngModel class="form-control">
<option>Male</option>
<option>Female</option>
</select>
</div>
<div class="form-group">
<label>Date of Birth</label>
<input type="date" name="dob" class="form-control" ngModel>
</div>
<div class="form-group">
<label>Impact</label>
<div class="form-check">
<input class="form-check-input" type="radio" name="impact" ngModel id="impactOption1" value="Applicable" checked>
<label class="form-check-label" for="impactOption1">
Applicable
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="impact" ngModel id="impactOption2" value="Not Applicable">
<label class="form-check-label" for="impactOption2">
Not Applicable
</label>
</div>
</div>
<div class="form-group">
<label>Score</label>
<input type="number" name="score" class="form-control" ngModel>
</div>
<div class="form-group">
<button type="button" class="btn btn-primary btn-sm" (click)="addUser(myForm.value)">Submit</button>
<button type="button" class="btn btn-secondary btn-sm ml-2" (click)="cancelAddUser()">Cancel</button>
</div>
</form>
</div>
<!-- Add Record -->
<!-- Parent Batch Edit -->
<div>
<form #myForm="ngForm">
<div class="form-group">
<select name="impact" [disabled]="!isBatchEdit" class="form-control form-control-sm" [(ngModel)]="currentImpact">
<option value="" disabled selected>Change Impact</option>
<option>Applicable</option>
<option>Not Applicable</option>
<option>FYI</option>
</select>
</div>
<button type="button" [disabled]="!isBatchEdit" (click)="batchUpdateUser(); myForm.reset()" class="btn btn-success btn-sm btn-update mr-2">
Update
</button>
<button type="button" [disabled]="!isBatchEdit" (click)="cancelBatchEdit(); myForm.reset()" class="btn btn-secondary btn-sm">Cancel</button>
</form>
</div>
<!-- Parent Batch Edit -->
<!-- Single Record Edit -->
<div *ngIf="isEdit">
<form #myForm="ngForm">
<div class="form-group">
<select name="impact" id="" class="form-control form-control-sm" [(ngModel)]="currentImpact">
<option>Applicable</option>
<option>Not Applicable</option>
<option>FYI</option>
</select>
</div>
<button type="button" (click)="updateUser()" class="btn btn-success btn-sm btn-update mr-2" *ngIf="isEdit">Update</button>
<button type="button" (click)="cancelEdit()" class="btn btn-secondary btn-sm">Cancel</button>
</form>
</div>
<!-- Single Record Edit -->
<!-- Filter -->
<div class="filter-data mt-3">
<form #form="ngForm">
<div class="form-group float-left mr-4">
<strong>Gender</strong>
<br>
<select class="form-control form-control-sm" name="gender" ngModel [ngModelOptions]="{updateOn: 'submit'}">
<option></option>
<option value="Male">Male</option>
<option value="Female">Female</option>
</select>
</div>
<div class="form-group float-left">
<strong>Impact</strong>
<br>
<select class="form-control form-control-sm" name="impact" ngModel [ngModelOptions]="{updateOn: 'submit'}">
<option></option>
<option value="Applicable">Applicable</option>
<option value="Not Applicable">Not Applicable</option>
</select>
</div>
<div class="form-group float-left mt-3 pt-1 ml-2">
<button type="submit" class="btn btn-primary btn-sm mr-2">Apply</button>
<button type="button" (click)="form.reset();" class="btn btn-secondary btn-sm">Reset</button>
</div>
</form>
</div>
<!-- Filter -->
<div class="clearfix"></div>
<!-- Parent View Table -->
<div class="viewData">
<div class="float-left">
<button class="btn btn-primary btn-sm mb-2 mt-2" (click)="showAddUser()">Add New Record</button>
</div>
<div class="float-right">
<div class="text-right total-records float-right">Total: {{totalRecords}}</div>
<button type="button" class="btn btn-sm btn-secondary float-right mr-2 mt-2 mb-2" (click)="reload()">Refresh</button>
</div>
<div class="clearfix"></div>
<table class="table table-sm table-responsive">
<thead>
<tr>
<th></th>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Gender</th>
<th>DOB</th>
<th>Impact</th>
<th>Score</th>
<th></th>
</tr>
</thead>
<tbody>
<tr class="record-row" (click)="viewUser(user)" *ngFor="let user of allUser | tableFilter: form.value | paginate: { id: 'listing_pagination', itemsPerPage: 10, currentPage: page, totalItems: totalRecords }">
<td><input *ngIf="!isEdit" [(ngModel)]="user.checked" type="checkbox" (change)="checkboxClicked()"></td>
<td>{{user.first_name}}</td>
<td>{{user.last_name}}</td>
<td>{{user.email}}</td>
<td>{{user.gender}}</td>
<td>{{user.dob}}</td>
<td>{{user.impact}}</td>
<td>
<div [ngClass]="getClass(user)">{{user.score}}</div>
</td>
<td>
<button *ngIf="!isEdit" class="btn btn-primary btn-sm" (click)="editUser(user)">Edit</button>
<button class="btn btn-primary btn-sm btn-sm ml-2" (click)="deleteUser(user)">Delete</button>
</td>
</tr>
</tbody>
</table>
<pagination-controls id="listing_pagination" directionLinks="true" (pageChange)="page = $event"></pagination-controls>
</div>
<!-- Parent View Table -->
<div class="clearfix"></div>
<!-- Record Detail View -->
<div *ngIf="isView" class="view-details">
<ul class="card p-2">
<li><strong>First Name</strong> <br />{{userObj.first_name}}</li>
<li><strong>Last Name</strong> <br />{{userObj.last_name}}</li>
<li><strong>Email</strong> <br />{{userObj.email}}</li>
<li><strong>Gender</strong> <br />{{userObj.gender}}</li>
<li><strong>IP Address</strong> <br />{{userObj.dob}}</li>
<li><strong>Impact</strong> <br />{{userObj.impact}}</li>
<li><strong>Score</strong> <br /><span [ngClass]="getClass(userObj)">{{userObj.score}}</span></li>
</ul>
<div class="clearfix"></div>
<div class="mb-3">
<form #myForm="ngForm">
<div class="form-group">
<select name="impact" [disabled]="!isSubBatchEdit" class="form-control form-control-sm" [(ngModel)]="currentImpact">
<option value="" disabled selected>Change Impact</option>
<option>Applicable</option>
<option>Not Applicable</option>
<option>FYI</option>
</select>
</div>
<button type="button" [disabled]="!isSubBatchEdit" (click)="subBatchUpdateUser(); myForm.reset()" class="btn btn-success btn-sm btn-update mr-2">
Update
</button>
<button type="button" [disabled]="!isSubBatchEdit" (click)="subCancelBatchEdit(); myForm.reset()" class="btn btn-secondary btn-sm">Cancel</button>
</form>
</div>
<div class="clearfix"></div>
<table class="table table-responsive table-sm">
<thead>
<tr>
<th></th>
<th>CO Score</th>
<th>Distribution List</th>
<th>Impact</th>
<th>Comments</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let assignee of userObj.assigned_to">
<td><input *ngIf="!isEdit" [(ngModel)]="assignee.checked" type="checkbox" (change)="subCheckboxClicked()"></td>
<td><div [ngClass]="getClass(assignee)">{{assignee.co_score}}</div></td>
<td>{{assignee.dl}}</td>
<td>{{assignee.sub_impact}}</td>
<td>{{assignee.comments}}</td>
</tr>
</tbody>
</table>
<div class="clearfix"></div>
<div class="viewChart">
<div class="skills">
<ul class="labels">
<li>Applicable</li>
<li>Not Applicable</li>
<li>FYI</li>
</ul>
<ul class="lines">
<li class="line l--0"><span class="line__label">0</span></li>
<li class="line l--1"><span class="line__label">1</span></li>
<li class="line l--2"><span class="line__label">2</span></li>
<li class="line l--3"><span class="line__label">3</span></li>
<li class="line l--4"><span class="line__label">4</span></li>
<li class="line l--5"><span class="line__label">5</span></li>
<li class="line l--6"><span class="line__label">6</span></li>
<li class="line l--7"><span class="line__label">7</span></li>
<li class="line l--8"><span class="line__label">8</span></li>
<li class="line l--9"><span class="line__label">9</span></li>
</ul>
<div class="charts">
<div class="chart chart--dev">
<ul class="charts--horiz">
<li class="chart__bar" [style.width]="impactCount.applicable * 10 + '%'">{{impactCount.applicable}}</li>
<li class="chart__bar" [style.width]="impactCount.notapplicable * 10 + '%'">{{impactCount.notapplicable}}</li>
<li class="chart__bar" [style.width]="impactCount.fyi * 10 + '%'">{{impactCount.fyi}}</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<!-- Record Detail View -->
</div>
app.component.ts
import { Component } from '@angular/core';
import { CommonService } from './common.service';
import { NgForm } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'db-poc1';
allUser: any;
isEdit = false;
isView = false;
isBatchEdit = false;
isSubBatchEdit = false;
isAdd = false;
totalRecords: any;
page: Number = 1;
currentImpact: string = '';
batchUpdateUsers = [];
subBatchUpdateUsers = [];
userObj = {
id: '', first_name: '', last_name: '', email: '', gender: '', dob: '', impact: '', score: ''
}
impactCount = {
applicable: 0, notapplicable: 0, fyi: 0
}
constructor(private commonService: CommonService) {}
ngOnInit() {
this.getLatestUser();
}
reload() {
window.location.reload();
}
checkboxClicked() {
this.batchUpdateUsers = this.allUser.filter((row: any) => row.checked);
this.isView = true;
this.isBatchEdit = this.batchUpdateUsers.length > 0;
this.currentImpact = this.userObj.impact;
}
subCheckboxClicked() {
this.subBatchUpdateUsers = this.allUser.filter((row: any) => row.checked);
this.isView = true;
this.isSubBatchEdit = this.subBatchUpdateUsers.length > 0;
this.currentImpact = this.userObj.impact;
}
addUser(formObj: any) {
this.commonService.createUser(formObj).subscribe((response) => {
this.getLatestUser();
});
this.isAdd = false;
}
showAddUser() {
this.isAdd = true;
}
cancelAddUser() {
this.isAdd = false;
}
getLatestUser() {
this.commonService.getAllUser().subscribe((response) => {
this.allUser = response;
this.totalRecords = this.allUser.length;
this.getApplicableCounts();
this.allUser.forEach((row: any) => row.checked = false);
});
}
getApplicableCounts() {
this.impactCount = {applicable:0, notapplicable:0, fyi: 0}
this.allUser.forEach((row: any) => {
// this.allUser.forEach(row => {
// if (row.impact === 'Applicable') {
// this.impactCount.applicable++;
// } else if (row.impact === 'Not Applicable') {
// this.impactCount.notapplicable++;
// } else if (row.impact === 'FYI') {
// this.impactCount.fyi++;
// }
// });
row.assigned_to.forEach((sub: any) => {
if (sub.sub_impact === 'Applicable') {
this.impactCount.applicable++;
} else if (sub.sub_impact === 'Not Applicable') {
this.impactCount.notapplicable++;
} else if (sub.sub_impact === 'FYI') {
this.impactCount.fyi++;
}
});
});
}
editUser(user: any) {
this.isEdit = true;
this.userObj = user;
this.allUser.forEach(user => user.checked = false);
this.currentImpact = user.impact;
}
deleteUser(user: any) {
this.commonService.deleteUser(user).subscribe(() => {
this.getLatestUser();
});
}
updateUser() {
this.isEdit = !this.isEdit;
this.userObj.impact = this.currentImpact;
this.commonService.updateUser(this.userObj).subscribe(() => {
this.getLatestUser();
});
this.getApplicableCounts();
}
cancelEdit() {
this.isEdit = false;
this.isView = false;
}
viewUser(user: any) {
this.isView = true;
this.userObj = user;
}
cancelBatchEdit() {
this.isBatchEdit = false;
this.allUser.forEach((user: any) => {user.checked = false});
}
getClass(user) {
if(user.score <= 30 || user.co_score <= 30)
return 'beginner';
else if (user.score <= 75 || user.co_score <= 75)
return 'intermediate';
else if (user.score <= 100 || user.co_score <= 100)
return 'expert';
else return 'other';
}
batchUpdateUser() {
this.isBatchEdit = false;
const batchUpdateUserList = [];
this.allUser.forEach((user: any) => {
if (user.checked) {
user.impact = this.currentImpact
batchUpdateUserList.push(user);
user.checked = false;
this.commonService.updateUser(user).subscribe(() => {
this.getLatestUser();
});
user.score = "Updated";
}
});
this.commonService.updateUser(this.userObj).subscribe(() => {
this.getLatestUser();
});
this.getApplicableCounts();
}
subBatchUpdateUser() {
this.isSubBatchEdit = false;
const subBatchUpdateUserList = [];
this.allUser.forEach((user: any) => {
if (user.sub_impact.checked) {
user.sub_impact.impact = this.currentImpact
subBatchUpdateUserList.push(user);
user.sub_impact.checked = false;
this.commonService.updateUser(user).subscribe(() => {
this.getLatestUser();
});
user.score = "Updated";
}
});
this.commonService.updateUser(this.userObj).subscribe(() => {
this.getLatestUser();
});
this.getApplicableCounts();
}
subCancelBatchEdit() {
this.isSubBatchEdit = false;
this.allUser.forEach((user: any) => {user.checked = false});
}
}
db.json
{
"users": [
{
"id": 1,
"first_name": "Male",
"last_name": "Record",
"email": "male.record@gmail.com",
"gender": "Male",
"dob": "01-01-1987",
"impact": "Not Applicable",
"score": "Updated",
"checked": false,
"assigned_to": [
{
"co_score": 54,
"dl": "CAT1",
"sub_impact": "Applicable",
"checked": false,
"comments": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."
},
{
"co_score": 20,
"dl": "CAT2",
"sub_impact": "Not Applicable",
"checked": false,
"comments": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."
},
{
"co_score": 99,
"dl": "CAT1",
"sub_impact": "Applicable",
"checked": false,
"comments": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."
}
]
},
{
"id": 2,
"first_name": "Female",
"last_name": "Record",
"email": "female.record@gmail.com",
"gender": "Female",
"dob": "31-12-1987",
"impact": "Applicable",
"checked": false,
"score": "Updated",
"assigned_to": [
{
"co_score": 54,
"dl": "CAT1",
"sub_impact": "Applicable",
"checked": false,
"comments": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."
},
{
"co_score": 20,
"dl": "CAT2",
"sub_impact": "Not Applicable",
"checked": false,
"comments": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."
}
]
},
{
"id": 3,
"first_name": "Male",
"last_name": "Record Another",
"email": "male.recordanother@gmail.com",
"gender": "Male",
"dob": "31-10-2017",
"impact": "Applicable",
"checked": false,
"score": 25,
"assigned_to": [
{
"co_score": 100,
"dl": "CAT3",
"sub_impact": "Applicable",
"checked": false,
"comments": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."
},
{
"co_score": 2,
"dl": "CAT2",
"sub_impact": "Not Applicable",
"checked": false,
"comments": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."
},
{
"co_score": 48,
"dl": "CAT2",
"sub_impact": "Not Applicable",
"checked": false,
"comments": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."
}
]
},
{
"first_name": "Male",
"last_name": "One More Record",
"email": "male.onemorerecord@gmail.com",
"gender": "Male",
"dob": "08-08-1984",
"impact": "Applicable",
"id": 6,
"checked": false,
"score": "Updated",
"assigned_to": [
{
"co_score": 4,
"dl": "CAT1",
"sub_impact": "Applicable",
"checked": false,
"comments": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."
},
{
"co_score": 85,
"dl": "CAT3",
"sub_impact": "Not Applicable",
"checked": false,
"comments": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."
}
]
},
{
"first_name": "Female",
"last_name": "Another Record",
"email": "female.anotherrecord@gmail.com",
"gender": "Female",
"dob": "2000-07-15",
"impact": "Applicable",
"id": 7,
"checked": false,
"score": 85,
"assigned_to": [
{
"co_score": 34,
"dl": "CAT3",
"sub_impact": "Applicable",
"checked": false,
"comments": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."
},
{
"co_score": 55,
"dl": "CAT2",
"sub_impact": "Not Applicable",
"checked": false,
"comments": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."
}
]
},
{
"id": 8,
"first_name": "New",
"last_name": "Record",
"email": "new.record@gmail.com",
"gender": "Male",
"dob": "2020-12-17",
"impact": "Not Applicable",
"score": 60,
"checked": false,
"assigned_to": [
{
"co_score": 94,
"dl": "CAT1",
"sub_impact": "Not Applicable",
"checked": false,
"comments": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."
},
{
"co_score": 85,
"dl": "CAT3",
"sub_impact": "Applicable",
"checked": false,
"comments": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."
}
]
}
]
}
有很多方法可以實現這一點,一種方法是:
在您的模板中:
<tr *ngFor="let assignee of userObj.assigned_to">
<td><input type="checkbox" [(ngModel)]="assignee.checked"></td>
<td>{{assignee.sub_impact}}</td>
</tr>
並在您的組件中:
updateUser() {
this.isView = !this.isView;
this.isEdit = !this.isEdit;
this.userObj.impact = this.currentImpact;
debugger;
const checkedItems = this.userObj.assigned_to.filter(a => a.checked);
checkedItems.forEach(a => {
a.sub_impact = this.currentImpact;
delete a.checked;
});
console.log("update");
//this.commonService.updateUser().subscribe(response => {
this.getCounts();
//});
}
請注意,如果您希望用戶 obj 和 assigned_to 之間有不同的值,則必須創建一個新的下拉列表
這是一個有效的stackblitz
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.