2016-11-11 100 views
0

我试图首次使用name[(ngModel)]模板驱动的窗体语法,在使用我第一次使用的controlValueAccessor的自定义控件上。Angular 2 form.value属性未定义

当我输入一些词语在我的<input>然后登录我form.value到控制台,我看到我添加表单域的名称,但它仍然是不确定的:

Object {keywords: undefined} 

如果我以编程方式设置的值对于result.keywords,然后当我将form.value记录到控制台时,关键字属性被填充。从模型到form.value的绑定正在工作。从视图(html输入控件)到模型的绑定不起作用。

ngOnInit() { 
    this.result = new Result(); 
    this.result.keywords = ["aaa"]; <----works 
} 

以上将在控制台中显示[“aaa”],但它不会在视图中显示任何内容。 如何正确获取表单的关键字属性以填充?

我的代码:

我的形式:

<form class="text-uppercase" (ngSubmit)="onSubmit(findForm.value, findForm.valid)" #findForm="ngForm"> 
     <vepo-input 
      [placeholder]='"keywords (optional)"' 
      [id]='"keywordsInput"' 
      name="keywords" 
      [(ngModel)]="result.keywords"> 
     </vepo-input> 
    </form> 

输入component.ts:

import { Component, ViewChild, ElementRef, Input, forwardRef } from '@angular/core'; 
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms'; 

const noop =() => { 
}; 

export const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = { 
    provide: NG_VALUE_ACCESSOR, 
    useExisting: forwardRef(() => InputComponent), 
    multi: true 
}; 


@Component({ 
    selector: 'vepo-input', 
    templateUrl: 'app/shared/subcomponents/input.component.html', 
    styleUrls: ['app/shared/subcomponents/input.component.css'], 
    providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR] 
}) 

export class InputComponent implements ControlValueAccessor { 
    @Input() private placeholder: string; 
    @Input() private id: string; 

    //The internal data model 
    private innerValue: any = ''; 

    //Placeholders for the callbacks which are later providesd 
    //by the Control Value Accessor 
    private onTouchedCallback:() => void = noop; 
    private onChangeCallback: (_: any) => void = noop; 

    //get accessor 
    get value(): any { 
     return this.innerValue; 
    }; 

    //set accessor including call the onchange callback 
    set value(v: any) { 
     if (v !== this.innerValue) { 
      this.innerValue = v; 
      this.onChangeCallback(v); 
     } 
    } 

    //Set touched on blur 
    onBlur() { 
     this.onTouchedCallback(); 
    } 

    //From ControlValueAccessor interface 
    writeValue(value: any) { 
     if (value !== this.innerValue) { 
      this.innerValue = value; 
     } 
    } 

    //From ControlValueAccessor interface 
    registerOnChange(fn: any) { 
     this.onChangeCallback = fn; 
    } 

    //From ControlValueAccessor interface 
    registerOnTouched(fn: any) { 
     this.onTouchedCallback = fn; 
    } 

} 

input.component.html:

<input class="form-item-input" 
      placeholder={{placeholder}} 
      id={{id}} /> 
<label attr.for="{{id}}" 
     class="form-item-right-icon input-icon"> 
</label> 

我的表单实际上比我发布的表单大很多,但我不想用无关代码重载所有人。为了完整起见,这里是全form.ts文件:

import { 
    Component, 
    ViewChild, 
    ElementRef, 
    EventEmitter, 
    Output, 
    OnInit 
} from '@angular/core'; 
import { 
    FormGroup, 
    FormBuilder, 
    Validators, 
    ControlValueAccessor 
} from '@angular/forms'; 
import { ResultService } from '../../../services/result.service'; 
import { Result } from '../../../models/all-models'; 
import { HighlightDirective } from '../../../directives/highlight.directive'; 
import { DistanceUnitsComponent } from './distance-units.component'; 
import { MultiselectComponent } from './multiselect-find-category.component'; 
import { MultiselectFindMealTypeComponent } from 
    './multiselect-find-meal-type.component'; 
import { AreaComponent } from './area-picker.component'; 
import { NumberPickerComponent } from './number-picker.component'; 
import { InputComponent } from '../../../shared/subcomponents/input.component'; 

@Component({ 
    selector: 'find-form', 
    templateUrl: 'app/find-page/subcomponents/find-page/find-form.component.html', 
    styleUrls: ['app/find-page/subcomponents/find-page/find-form.component.css'], 
    providers: [ResultService] 
}) 
export class FindFormComponent implements OnInit { 

    @ViewChild('multiselectFindCategory') 
    private multiselectFindCategory: MultiselectComponent; 
    @ViewChild('multiselectFindMealType') 
    private multiselectFindMealType: MultiselectFindMealTypeComponent; 
    @ViewChild('distanceUnits') private distanceUnits: DistanceUnitsComponent; 
    @ViewChild('numberPicker') private numberPicker: NumberPickerComponent; 
    @ViewChild('areaInput') private areaInput: AreaComponent; 
    @ViewChild('keywordsInput') private keywordsInput: InputComponent; 

    @Output() private onResultsRecieved: 
    EventEmitter<Object> = new EventEmitter<Object>(); 
    @Output() private onSubmitted: EventEmitter<boolean> = 
    new EventEmitter<boolean>(); 

    private categoryError: string = 'hidden'; 
    private mealTypeError: string = 'hidden'; 
    private areaError: string = 'hidden'; 

    private findForm: FormGroup; 
    private submitted: boolean = false; 
    private result: Result; 

    private displayMealCategories: boolean = false; 
    private mealSelected: boolean = false; 
    private place: google.maps.Place; 

    constructor(private resultService: ResultService, 
     private formBuilder: FormBuilder, 
     el: ElementRef) { } 

    ngOnInit() { 
     this.result = new Result(); 
    } 

    private setCategoryErrorVisibility(
     multiselectFindCategory: MultiselectComponent 
    ): void { 
     if (multiselectFindCategory.selectedCategories.length < 1 && 
      !multiselectFindCategory.allSelected && 
      this.submitted) { 
      this.categoryError = 'visible'; 
     } else { 
      this.categoryError = 'hidden'; 
     } 
    } 

    private setMealTypeErrorVisibility(
     multiselectFindMealType: MultiselectFindMealTypeComponent 
    ): void { 
     if (multiselectFindMealType) { 
      if (multiselectFindMealType.selectedCategories.length < 1 && 
       !multiselectFindMealType.allSelected && 
       this.submitted) { 
       this.mealTypeError = 'visible'; 
      } else { 
       this.mealTypeError = 'hidden'; 
      } 
     } 
    } 

    private setAreaErrorVisibility(): void { 
     if (this.areaInput.areaInput.nativeElement.value) { 
      if (!this.areaInput.address) { 
       this.areaError = 'visible'; 
       this.areaInput.areaInput.nativeElement.setCustomValidity("Please select from dropdown or leave blank."); 
      } else { 
       this.areaError = 'hidden'; 
       this.areaInput.areaInput.nativeElement.setCustomValidity(""); 
      } 
     } else { 
      this.areaError = 'hidden'; 
      this.areaInput.areaInput.nativeElement.setCustomValidity(""); 
     } 
    } 

    private onCategoriesChanged(): void { 
     this.setCategoryErrorVisibility(this.multiselectFindCategory); 
     this.mealSelected = this.multiselectFindCategory.mealSelected; 
     if (!this.mealSelected) { 
      this.mealTypeError = 'hidden'; 
     } 
    } 

    private onMealTypesChanged(): void { 
     this.setMealTypeErrorVisibility(this.multiselectFindMealType); 
    } 

    private onAreaChanged(areaEntered: any): void { 
     this.setStateOfDistanceControls(areaEntered.areaEntered); 
     this.areaError = "hidden"; 
     this.areaInput.areaInput.nativeElement.setCustomValidity(""); 
     if (areaEntered.place) { 
      this.place = areaEntered.place; 
     } 
    } 

    private setStateOfDistanceControls(areaEntered: any): void { 
     if (areaEntered.areaEntered) { 
      this.distanceUnits.isEnabled = true; 
      this.numberPicker.isEnabled = true; 
     } else { 
      this.distanceUnits.isEnabled = false; 
      this.numberPicker.isEnabled = false; 
     } 
     this.distanceUnits.setImage(); 
    } 

    private getResults(): void { 
     var results: Result[] = []; 
     results = this.resultService.getResults(); 
     if (results) { 
      this.onResultsRecieved.emit({ 
       recieved: true, 
       results: results, 
       place: this.place 
      }); 
     } 
    } 

    private onSubmit(model: any, isValid: boolean): void { 

     console.log(model, isValid); 


     // this.submitted = true; 
     // this.setCategoryErrorVisibility(this.multiselectFindCategory); 
     // this.setMealTypeErrorVisibility(this.multiselectFindMealType); 
     // this.setAreaErrorVisibility(); 
     // if (this.areaError === "hidden" && 
     // this.categoryError === "hidden" && 
     // this.mealTypeError === "hidden") { 
     // this.onSubmitted.emit(true); 
     // this.getResults(); 
     // } 
    } 
} 

回答

1

好吧,这是我在与工作plunker备份工作,你的意图刺:

在你input.component。 HTML你需要确保你已经设置了绑定到ngModel

<input class="form-item-input" [(ngModel)]="value" [placeholder]="placeholder" id="{{id}}" /> 

之外,还有真的没有别的事情可做。

这里是蹲点:http://plnkr.co/edit/HleTVBnvd8ePgMClAZS2?p=preview

相关问题