Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

angular - Custom checkbox input component styled with Switchery

I'm trying to create a custom checkbox component styled with Switchery that can be used in a form like any other <input type="checkbox" ... /> component.

The code I have now takes care of the styling:

import {Component,ViewChild,AfterViewInit,Input} from 'angular2/core';
import switchery from 'switchery';

@Component({
  selector: 'switchery-checkbox',
  template: `<input #checkbox type="checkbox" class="js-switch"/>`,
})
export class SwitcheryComponent implements AfterViewInit {
  @Input() options: Switchery.Options = {};
  @ViewChild('checkbox') checkbox: any;
  ngAfterViewInit() {
    new switchery(this.checkbox.nativeElement,
                  this.options);
  }
}

What do I have to add to be able to use it in a template like in the following code? It should ideally implement all the functionality of <input type="checkbox" />.

<switchery-checkbox
     [(ngModel)]="model.onOrOff"
     ngControl="onOrOff"
     [disabled]="disabledCondition"
     ... >
</switchery-checkbox>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

In fact you need to make your component "ngModel-compliant" but implementing a custom value accessor.

Here is the way to do:

@Component({
  selector: 'switchery-checkbox',
  template: `
    <input #checkbox type="checkbox" (change)="onChange($event.target.checked)" class="js-switch"/>
  `,
  (...)
})
export class SwitcheryComponent implements AfterViewInit, ControlValueAccessor {
  @Input() options: Switchery.Options = {};
  @Input() disabled:boolean = false;
  @ViewChild('checkbox') checkbox: any;

  value: boolean = false;

  onChange = (_) => {};
  onTouched = () => {};

  writeValue(value: any): void {
    this.value = value;
    this.setValue(this.value);
  }

  registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }
  registerOnTouched(fn: () => void): void { this.onTouched = fn; }

  ngAfterViewInit() {
    this.switcher = new switchery(this.checkbox.nativeElement,
              this.options);
    this.setValue(this.value);
    this.setDisabled(this.disabled);
  }

  ngOnChanges(changes: {[propName: string]: SimpleChange}) {
    if (changes && changes.disabled) {
      this.setDisabled(changes.disabled.currentValue);
    }
  }

  setValue(value) {
    if (this.switcher) {
      var element = this.switcher.element;
      element.checked = value
    }
  }

  setDisabled(value) {
    if (this.switcher) {
      if (value) {
        this.switcher.disable();
      } else {
        this.switcher.enable();
      }
    }
  }
}

Finally you need to register the value accessor into the providers of the component:

const CUSTOM_VALUE_ACCESSOR = new Provider(
  NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => SwitcheryComponent), multi: true});

@Component({
  selector: 'switchery-checkbox',
  template: `
    <input #checkbox type="checkbox" (change)="onChange($event.target.checked)" class="js-switch"/>
  `,
  providers: [ CUSTOM_VALUE_ACCESSOR ]
})
export class SwitcheryComponent implements AfterViewInit, ControlValueAccessor {
  (...)
}

This way you can use your directive this way:

<switchery-checkbox [disabled]="disabled"
       [(ngModel)]="value" ngControl="cb"
       #cb="ngForm"></switchery-checkbox>

See this plunkr: https://plnkr.co/edit/z1gAC5U0pgMSq0wicGHC?p=preview.

See this article for more details (section "NgModel-compatible component"):


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...