簡體   English   中英

如何使 batchEdit 也可用於 json 嵌套節點?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM