Angular 角度2 form.value属性未定义

Angular 角度2 form.value属性未定义,angular,angular2-forms,Angular,Angular2 Forms,我第一次尝试在一个自定义控件上使用name和[(ngModel)]模板驱动的表单语法,该控件使用了controlValueAccessor,我也是第一次使用它 当我在我的中输入一些单词,然后将我的表单.value记录到控制台时,我看到了我添加的表单字段的名称,但它仍然没有定义: Object {keywords: undefined} 如果以编程方式设置result.keywords的值,那么当我将form.value记录到控制台时,将填充keywords属性。从模型到form.value的绑

我第一次尝试在一个自定义控件上使用
name
[(ngModel)]
模板驱动的表单语法,该控件使用了
controlValueAccessor
,我也是第一次使用它

当我在我的
中输入一些单词,然后将我的
表单.value
记录到控制台时,我看到了我添加的表单字段的名称,但它仍然没有定义:

Object {keywords: undefined}
如果以编程方式设置result.keywords的值,那么当我将form.value记录到控制台时,将填充keywords属性。从模型到form.value的绑定正在工作。从视图(html输入控件)到模型的绑定不起作用

ngOnInit() {
    this.result = new Result();
    this.result.keywords = ["aaa"]; <----works
}
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();
        // }
    }
}
导入{
组成部分,
ViewChild,
ElementRef,
事件发射器,
产出,
奥尼特
}从“@angular/core”开始;
进口{
FormGroup,
造模工,
验证器,
控制值存取器
}从“@angular/forms”开始;
从“../../../services/result.service”导入{ResultService};
从“../../../models/all models”导入{Result};
从“../../../directions/highlight.directive”导入{HighlightDirective};
从“./distance units.component”导入{distance units组件};
从“./multiselect find category.component”导入{MultiselectComponent};
从导入{MultiselectFindMealTypeComponent}
'./多选查找膳食类型.组件';
从“./area picker.component”导入{AreaComponent};
从“./number picker.component”导入{NumberPickerComponent};
从“../../../shared/subcomponents/input.component”导入{InputComponent};
@组成部分({
选择器:“查找表单”,
templateUrl:'app/find page/subcomponents/find page/find form.component.html',
样式URL:['app/find page/subcomponents/find page/find form.component.css'],
提供者:[结果服务]
})
导出类FindFormComponent实现OnInit{
@ViewChild('multiselectFindCategory')
私有multiselectFindCategory:MultiselectComponent;
@ViewChild('multiselectFindMealType')
私有multiselectFindMealType:MultiselectFindMealTypeComponent;
@ViewChild(“距离单位”)专用距离单位:距离单位组件;
@ViewChild('numberPicker')私有numberPicker:NumberPickerComponent;
@ViewChild('areaInput')私有areaInput:AreaComponent;
@ViewChild('keywordsInput')私有关键字输入:InputComponent;
@Output()私有OnResultsReceived:
EventEmitter=新的EventEmitter();
@提交时输出()私有:EventEmitter=
新事件发射器();
私有categoryError:string='hidden';
private mealTypeError:string='hidden';
私有区域错误:字符串='隐藏';
私人金融机构:FormGroup;
私有提交:布尔值=false;
私人结果:结果;
私有displayMealCategories:boolean=false;
private mealSelected:布尔值=false;
私人场所:google.maps.place;
构造函数(私有resultService:resultService,
私有formBuilder:formBuilder,
el:ElementRef){}
恩戈尼尼特(){
this.result=新结果();
}
私有setCategoryErrorVisibility(
multiselectFindCategory:MultiselectComponent
):无效{
如果(multiselectFindCategory.selectedCategories.length<1&&
!multiselectFindCategory.allSelected&&
本文件(已提交){
this.categoryError='visible';
}否则{
this.categoryError='hidden';
}
}
私有setMealTypeErrorVisibility(
multiselectFindMealType:MultiselectFindMealTypeComponent
):无效{
if(多选FindMealType){
如果(multiselectFindMealType.selectedCategories.length<1&&
!multiselectFindMealType.allSelected&&
本文件(已提交){
this.mealTypeError='visible';
}否则{
this.mealTypeError='hidden';
}
}
}
私有setAreaErrorVisibility():void{
if(this.areaInput.areaInput.nativeElement.value){
如果(!this.areaInput.address){
this.areaError='可见';
this.areaInput.areaInput.nativeElement.setCustomValidity(“请从下拉列表中选择或留空”);
}否则{
this.areaError='hidden';
this.areaInput.areaInput.nativeElement.setCustomValidity(“”);
}
}否则{
this.areaError='hidden';
this.areaInput.areaInput.nativeElement.setCustomValidity(“”);
}
}
private onCategoriesChanged():void{
this.setCategoryErrorVisibility(this.multiselectFindCategory);
this.mealSelected=this.multiselectFindCategory.mealSelected;
如果(!this.mealSelected){
this.mealTypeError='hidden';
}
}
私有onMealTypesChanged():void{
this.setMealTypeErrorVisibility(this.multiselectFindMealType);
}
已重新更改的专用区域(输入的区域:任意):无效{
此.setStateOfDistanceControls(areaEntered.areaEntered);
this.areaError=“hidden”;
this.areaInput.areaInput.nativeElement.setCustomValidity(“”);
如果(区域输入。位置){
this.place=areaEntered.place;
}
}
private setStateOfDistanceControls(区域输入:任意):无效{
如果(区域输入。区域输入){
this.distanceUnits.isEnabled=true;
this.numberPicker.isEnabled=true;
}否则{
this.distanceUnits.isEnabled=false;
this.numberPicker.isEnabled=false;
}
这是.distanceUnits.setImage();
}
私有getResults():void{
var结果:结果[]=[];
结果=this.resultService.getResults();
<input  class="form-item-input"
            placeholder={{placeholder}} 
            id={{id}} />
<label   attr.for="{{id}}"
         class="form-item-right-icon input-icon">
</label>
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();
        // }
    }
}
<input class="form-item-input" [(ngModel)]="value" [placeholder]="placeholder" id="{{id}}" />