简体   繁体   English

如何使 batchEdit 也可用于 json 嵌套节点?

[英]How can I make batchEdit available for json nested nodes as well?

Hi Stackoverflow Members嗨 Stackoverflow 成员

I wanted to make batch edit available for sub-nodes as well but I am not able to achieve it.我也想为子节点提供批量编辑,但我无法实现。

Can anyone please look into the code and suggest me the changes so, that batch edit is available for both parent node and nested node of record.任何人都可以查看代码并建议我进行更改,以便批量编辑可用于父节点和嵌套记录节点。

app.component.html 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 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 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."
        }
      ]
    }
  ]
}

There are a lot of ways to implement this, one way is something like:有很多方法可以实现这一点,一种方法是:

in your template:在您的模板中:

<tr *ngFor="let assignee of userObj.assigned_to">
    <td><input type="checkbox" [(ngModel)]="assignee.checked"></td>
    <td>{{assignee.sub_impact}}</td>
</tr>

and in your component:并在您的组件中:

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();
    //});
  }

notice that if you want different values between the user obj and the assigned_to you will have to create a new dropdown请注意,如果您希望用户 obj 和 assigned_to 之间有不同的值,则必须创建一个新的下拉列表

here is a working stackblitz这是一个有效的stackblitz

在此处输入图像描述

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM