マテリアル デザイン コンポーネントを使用して暫定的なドロップダウン メニューを作成しようとしていますが、機能しない理由がわかりControlValueAccessor
ません。コードの関連部分は次のとおりです。
import {
AfterViewInit,
Component,
ElementRef,
forwardRef,
Input,
OnInit,
Provider,
ViewChild
} from '@angular/core';
import {
NG_VALUE_ACCESSOR,
ControlValueAccessor,
CORE_DIRECTIVES
} from '@angular/common';
import { MdCard } from '@angular2-material/card';
import {
MdInput,
MD_INPUT_DIRECTIVES
} from '@angular2-material/input';
import { MD_LIST_DIRECTIVES } from '@angular2-material/list';
declare var module: {
id: string;
};
export const MD_SELECT_VALUE_ACCESSOR = new Provider(
NG_VALUE_ACCESSOR, { useExisting: forwardRef(() => MdSelect), multi: true });
const noop = () => {};
@Component({
selector: 'md-select',
moduleId: module.id,
template: `
<div>
<md-input readOnly type="text" [placeholder]="placeholder" (click)="selectClick()">
<i md-suffix class="fa fa-sort-desc"></i>
</md-input>
<md-card [ngClass]="{ visible: menuVisible }" (blur)="menuBlur()">
<md-list>
<md-list-item class="md-option" *ngFor="let option of options" (click)="optionClick(option)" [ngClass]="{ 'selected': option.selected }">
{{option.name}}
</md-list-item>
</md-list>
</md-card>
</div>
`,
styleUrls: [
'md-select.component.css'
],
directives: [
CORE_DIRECTIVES,
MdCard,
MdInput,
MD_INPUT_DIRECTIVES,
MD_LIST_DIRECTIVES
],
providers: [MD_SELECT_VALUE_ACCESSOR]
})
export class MdSelect implements ControlValueAccessor {
@Input() multiple: boolean;
@Input() placeholder: string;
private _value: string;
onChanged: (_: any) => void = noop;
onTouched: () => void = noop;
options: MdOption[] = [];
menuVisible: boolean = false;
selectedOption: MdOption;
private _selectedOptions: MdOption[] = [];
addOption(option: MdOption) {
this.options.push(option);
if (option.selected && (!this.selectedOption || this.multiple)) {
this.selectedOption = option;
this.value = this.selectedOption.name;
}
}
selectClick() {
if (!this.menuVisible) {
this.menuVisible = true;
}
}
optionClick(option: MdOption) {
if (option) {
if (this.multiple) {
option.selected = !option.selected;
} else {
this.options.filter(option => option.selected).forEach(option => option.selected = false);
option.selected = true;
}
this.onChanged('value');
}
this.menuBlur();
}
menuBlur() {
this.menuVisible = false;
}
get value(): string {
return this.options.filter(option => option.selected).map(option => option.name).join(', ')
}
set value(value: string) {
if (value !== this._value) {
this._value = value; // TODO
this.onChanged('value');
}
}
writeValue(value: any): void {
console.log('writeValue("' + value + '")')
this.value = value;
}
registerOnChange(fn: (_: any) => void): void {
this.onChanged = (_: any) => { console.log('onChange("' + _ + '")'); fn(_); };
}
registerOnTouched(fn: () => void): void {
this.onTouched = () => { console.log('onTouched()'); fn(); }
}
}
@Component({
selector: 'md-option',
template: `
<div #wrapper>
<ng-content></ng-content>
</div>
`
})
export class MdOption implements AfterViewInit {
@ViewChild('wrapper') wrapper: ElementRef;
@Input() disabled: boolean;
name: string;
@Input() selected: boolean;
@Input() value: string;
constructor(private select: MdSelect) { }
ngAfterViewInit() {
if (this.wrapper) {
let name = this.wrapper.nativeElement.innerHTML;
this.name = name ? name.trim() : 'EMPTY';
}
this.select.addOption(this);
}
}
これは、それが使用されるテンプレートの一部です
<div class="md-form-control">
<md-select placeholder="Shift" class="shift" formControlName="shift">
<md-option *ngFor="let s of shifts" [value]="s.id" [ngValue]="s.id"
[selected]="s.id === shift.id">
{{s.name}}
</md-option>
</md-select>
</div>
これがフォームのセットアップです
private initForm() {
...
this.form = this.formBuilder.group({
shift: [this.shift.name],
...
})
}
このコードを実行しようとすると、
platform-browser.umd.js:1900 元の例外: 'shift' の値アクセサーがありません
私は何を取りこぼしたか?