Home Reference Source

src/components/checkbox/Checkbox.js

import _ from 'lodash';
import { componentValueTypes, getComponentSavedTypes } from '../../utils/utils';
import Field from '../_classes/field/Field';

export default class CheckBoxComponent extends Field {
  static schema(...extend) {
    return Field.schema({
      type: 'checkbox',
      inputType: 'checkbox',
      label: 'Checkbox',
      key: 'checkbox',
      dataGridLabel: true,
      labelPosition: 'right',
      value: '',
      name: ''
    }, ...extend);
  }

  static get builderInfo() {
    return {
      title: 'Checkbox',
      group: 'basic',
      icon: 'check-square',
      documentation: '/userguide/form-building/form-components#check-box',
      weight: 50,
      schema: CheckBoxComponent.schema()
    };
  }

  static get serverConditionSettings() {
    return CheckBoxComponent.conditionOperatorsSettings;
  }

  static get conditionOperatorsSettings() {
    return {
      ...super.conditionOperatorsSettings,
      operators: ['isEqual'],
      valueComponent() {
        return {
          valueType: 'boolean',
          data: {
            values: [
                { label: 'Checked', value: 'true' },
                { label: 'Not Checked', value: 'false' },
              ]
          },
          type: 'select'
        };
      }
    };
  }

  static savedValueTypes(schema) {
    schema = schema || {};
    const types = getComponentSavedTypes(schema);

    if (_.isArray(types)) {
      return types;
    }

    if (schema.inputType === 'radio') {
      return [componentValueTypes.string];
    }

    return [componentValueTypes.boolean];
  }

  get defaultSchema() {
    return CheckBoxComponent.schema();
  }

  get labelClass() {
    let className = '';
    if (this.isInputComponent
      && !this.options.inputsOnly
      && this.component.validate
      && this.component.validate.required) {
      className += ' field-required';
    }
    return `${className}`;
  }

  get hasSetValue() {
    return this.hasValue();
  }

  get inputInfo() {
    const info = super.elementInfo();
    info.type = 'input';
    info.changeEvent = 'click';
    info.attr.type = this.component.inputType || 'checkbox';
    info.attr.class = 'form-check-input';
    if (this.component.name) {
      info.attr.name = `data[${this.component.name}]`;
    }
    info.attr.value = this.component.value ? this.component.value : 0;
    info.label = this.t(this.component.label, { _userInput: true });
    info.labelClass = this.labelClass;
    return info;
  }

  get labelInfo() {
    return {
      hidden: true
    };
  }

  render() {
    return super.render(this.renderTemplate('checkbox', {
      input: this.inputInfo,
      checked: this.checked,
      tooltip: this.interpolate(this.t(this.component.tooltip) || '', { _userInput: true }).replace(/(?:\r\n|\r|\n)/g, '<br />')
    }));
  }

  attach(element) {
    this.loadRefs(element, { input: 'multiple' });
    this.input = this.refs.input[0];
    if (this.refs.input) {
      this.addEventListener(this.input, this.inputInfo.changeEvent, () => this.updateValue(null, {
        modified: true
      }));
      this.addShortcut(this.input);
    }
    return super.attach(element);
  }

  detach(element) {
    if (element && this.input) {
      this.removeShortcut(this.input);
    }
    super.detach();
  }

  get emptyValue() {
    return this.component.inputType === 'radio' ? null : false;
  }

  isEmpty(value = this.dataValue) {
    return super.isEmpty(value) || value === false;
  }

  get key() {
    return this.component.name ? this.component.name : super.key;
  }

  getValueAt(index) {
    if (this.component.name) {
      return this.refs.input[index].checked ? this.component.value : '';
    }
    return !!this.refs.input[index].checked;
  }

  getValue() {
    const value = super.getValue();
    if (this.component.name) {
      return value ? this.setCheckedState(value) : this.setCheckedState(this.dataValue);
    }
    else {
      return (value === '') ? this.dataValue : !!value;
    }
  }

  get checked() {
    if (this.component.name) {
      return (this.dataValue === this.component.value);
    }
    return !!this.dataValue;
  }

  setCheckedState(value) {
    if (!this.input) {
      return;
    }
    if (this.component.name) {
      this.input.value = (value === this.component.value) ? this.component.value : 0;
      this.input.checked = (value === this.component.value) ? 1 : 0;
    }
    else if (value === 'on') {
      this.input.value = 1;
      this.input.checked = 1;
    }
    else if (value === 'off') {
      this.input.value = 0;
      this.input.checked = 0;
    }
    else if (value) {
      this.input.value = 1;
      this.input.checked = 1;
    }
    else {
      this.input.value = 0;
      this.input.checked = 0;
    }
    if (this.input.checked) {
      this.input.setAttribute('checked', true);
    }
    else {
      this.input.removeAttribute('checked');
    }
    return value;
  }

  setValue(value, flags = {}) {
    if (
      this.setCheckedState(value) !== undefined ||
      (!this.input && value !== undefined && (this.visible || this.conditionallyVisible() || !this.component.clearOnHide))
    ) {
      const changed = this.updateValue(value, flags);
      if (this.isHtmlRenderMode() && flags && flags.fromSubmission && changed) {
        this.redraw();
      }
      return changed;
    }
    return false;
  }

  getValueAsString(value) {
    const { name: componentName, value: componentValue } = this.component;
    const hasValue = componentName ? _.isEqual(value, componentValue) : value;
    if (_.isUndefined(value) && this.inDataTable) {
      return '';
    }

    return this.t(hasValue ? 'Yes' : 'No');
  }

  updateValue(value, flags) {
    // If this is a radio and is alredy checked, uncheck it.
    if (this.component.name && flags.modified && (this.dataValue === this.component.value)) {
      this.input.checked = 0;
      this.input.value = 0;
      this.dataValue = '';
      this.updateOnChange(flags, true);
    }

    const changed = super.updateValue(value, flags);

    // Update attributes of the input element
    if (changed && this.input) {
      if (this.input.checked) {
        this.input.setAttribute('checked', 'true');
      }
      else {
        this.input.removeAttribute('checked');
      }
    }

    return changed;
  }
}