简体   繁体   中英

Angular indeterminate checkbox

I have an AngularJS (1.5) setup for making a parent checkbox indeterminate if one of its children is selected as well as selecting all the children if the parent is selected.

I'm having trouble converting the old ES5 JS to typescript.

Here's the old controller:

  var _this = this;

_this.hierarchicalData = [
  {
    id: 0,
    label: 'Parent item',
    checked: false,
    children: [
      { id: 0, label: 'Child one', value: 'child_one', checked: false },
      { id: 1, label: 'Child two', value: 'child_two', checked: false },
      { id: 2, label: 'Child three', value: 'child_three', checked: false }
    ]
  }
];

_this.selectedChildren = [];
_this.isIndeterminate = false;
_this.allRowsSelected = false;

_this.selectChildren = function (data, $event) {
  var parentChecked = data.checked;
  angular.forEach(_this.hierarchicalData, function (value, key) {
    angular.forEach(value.children, function (value, key) {
      value.checked = parentChecked;
    });
  });
};

_this.selectChild = function (data, $event) {
  if (_this.selectedChildren.indexOf(data.id) === -1) {
    _this.selectedChildren.push(data.id);
    data.selected = true;
  } else {
    _this.selectedChildren.splice(_this.selectedChildren.indexOf(data.id), 1);
    _this.allRowsSelected = false;
    data.selected = false;
  }
};

// for the purposes of this demo, check the second child checkbox
_this.selectedChildren.push(1);
_this.hierarchicalData[0].children[1].checked = true;

and the old template:

 <ul class="list-nomarkers">
  <li ng-repeat="parent in check.hierarchicalData">
    <div class="checkbox">
      <label>
        <input type="checkbox" ng-model="parent.checked" ng-click="check.selectChildren(parent, $event)" ui-indeterminate="check.selectedChildren.length">{{parent.label}}
      </label>
    </div>
    <ul class="list-nomarkers">
      <li ng-repeat="child in parent.children">
        <div class="checkbox">
          <label>
            <input type="checkbox" ng-model="child.checked" ng-click="check.selectChild(child, $event)"> {{child.label}}
          </label>
        </div>

      </li>
    </ul>
  </li>
</ul>

I updated the template for Angular 5 (and Bootstrap 4):

   <ul class="list-unstyled">
     <li *ngFor="let parent of hierarchicalData">
      <div class="form-check">
        <input class="form-check-input" type="checkbox" [(ngModel)]="parent.checked" (click)="selectChildren(parent, $event)">
        <label class="form-check-label">
         {{parent.label}}
        </label>
      </div>
      <ul class="list-unstyled">
        <li *ngFor="let child of parent.children">
          <div class="form-check">
            <input class="form-check-input" type="checkbox" [(ngModel)]="child.checked" (click)="selectChild(parent, $event)">
            <label class="form-check-label">
              {{child.label}}
            </label>
          </div>
        </li>
      </ul>
     </li>
   </ul>

And added the 2 main functions to the component:

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'pb-ds-checkboxes',
  templateUrl: './checkboxes.component.html'
})
export class CheckboxesComponent implements OnInit {
  hierarchicalData = [
    {
      id: 0,
      label: 'Parent item',
      checked: false,
      children: [
        { id: 0, label: 'Child one', value: 'child_one', checked: false },
        { id: 1, label: 'Child two', value: 'child_two', checked: false },
        { id: 2, label: 'Child three', value: 'child_three', checked: false }
      ]
    }
  ];
  selectedChildren = [];
  isIndeterminate = false;
  allRowsSelected = false;
  constructor() {}

  ngOnInit() {}

  selectChildren = function(data, $event) {
    const parentChecked = data.checked;
    angular.forEach(this.hierarchicalData, function (value, key) {
      angular.forEach(value.children, function (value, key) {
        value.checked = parentChecked;
      });
    });
  };

  selectChild = function(data, $event) {
    if (this.selectedChildren.indexOf(data.id) === -1) {
      this.selectedChildren.push(data.id);
      data.selected = true;
    } else {
      this.selectedChildren.splice(this.selectedChildren.indexOf(data.id), 1);
      this.allRowsSelected = false;
      data.selected = false;
    }
  };
}

Obviously, I need to convert the old angular.forEach into ES6, but I'm still a little weak on arrow functions. Can someone please give me a nudge in the right direction?

Make sure you are casting the types for each declared value by replacing all the values with the proper type. The arrow functions can replace your ES5 functions.

selectChildren: <TYPE> = (data:<TYPE>, event:<TYPE>) => {
        const parentChecked <TYPE> = data.checked;
        this.hierarchicalData.forEach((value, key) => {
          value.children.forEach((value2, key2) => {
            value2.checked = parentChecked;
          });
        });
      };

      selectChild:<TYPE> = (data:<TYPE>, event:<TYPE>) {
        if (this.selectedChildren.indexOf(data.id) === -1) {
          this.selectedChildren.push(data.id);
          data.selected = true;
        } else {
          this.selectedChildren.splice(this.selectedChildren.indexOf(data.id), 1);
          this.allRowsSelected = false;
          data.selected = false;
        }
      };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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