2016-02-04 49 views
4

我试图在Angular2中实现(带有TS在Plunker中的测试版0)带有2个嵌套窗体的场景,每个窗体都由组件表示。Angular2测试版:嵌套基于窗体的父/子组件,并从父项验证

父组件是Word,它表示假字典中的单词。孩子们的组成部分是WordSense's,每个都代表父母的意思。

这两个组件都使用模型驱动的表单,并且子表单绑定其模型的值以使用ngModel形成控件。通过这种方式,父组件可以很容易地将其单词的感觉传递给子组件,而双向绑定完成剩下的工作。

简单的自定义验证器附加到这两个表单。除此之外,我希望不仅在单词形式无效时禁用“提交”按钮,而且在任何感官无效时也禁用提交按钮。为此,我在正在编辑的模型中添加了一个isValid属性,并在代码中观察感官形式的变化:每当发生变化时,我检查表单的valid属性并相应地设置模型的属性。然后,我可以在视图和代码中的父级组件级别轻松添加检查,以便只有在两个表单均可用时才能发布检查。

为了支持自定义验证和其他逻辑,我将我的初始代码从基于模板的模型切换到基于模型的模板;但是,只要我启动重构代码,我会得到几个没有指令注释发现错误,我不确定它们的含义。

也许我错过了一些明显的东西,但我是一个新手。任何人都可以提出建议吗?你可以在这个plunker找到一个repro:http://plnkr.co/edit/v9Dj5j5opJmonxEeotcR。下面是它的一些基本代码:

一)父组件:

@Component({ 
    selector: "word", 
    directives: [FORM_DIRECTIVES, FORM_PROVIDERS, WordSense], 
    templateUrl: ` 
<div> 
    <form [ngFormModel]="wordForm" 
      (ngSubmit)="onSubmit(wordForm.value)" 
      role="form"> 

      <div class="form-group" 
       [class.has-error]="!lemma.valid && lemma.touched"> 
      <label for="lemma">lemma</label> 
      <input type="text" id="lemma" 
        maxlength="100" required spellcheck="false" 
        class="form-control" 
        placeholder="lemma" 
        [ngFormControl]="wordForm.controls['lemma']"> 
      <div *ngIf="lemma.hasError('required') && lemma.touched" 
        class="text-danger small">lemma required</div> 
      <div *ngIf="lemma.hasError('lemmaValidator') && lemma.touched" 
        class="text-danger small">invalid lemma</div> 
      </div> 
      ... 
      <div class="form-group"> 
      <table class="table table-bordered"> 
       <tbody> 
       <tr *ngFor="#s of senses"> 
       <td> 
        <word-sense [sense]="s" [ranks]="ranks" [fields]="fields"></word-sense> 
       </td> 
       </tr> 
       </tbody> 
      </table> 
      </div> 
      ...    
      <button type="submit" 
        [ngClass]="{disabled: !wordForm.valid}" 
        class="btn btn-primary btn-sm">save</button> 
    </form> 
</div> 
    `, 
    inputs: [ 
     "word" 
    ] 
}) 
export class Word { 
    private _word: IWordModel; 

    public set word(value: IWordModel) { 
     this._word = value; 
     this.setFormValues(); 
    } 
    public get word() { 
     return this._word; 
    } 
    // ... 

    // form 
    public wordForm: ControlGroup; 
    public lemma: Control; 
    public language: Control; 
    public class: Control; 
    public ranks: IPair<number>[]; 
    public senses: ISenseViewModel[]; 
    public fields: IFieldModel[]; 

    constructor(private formBuilder:FormBuilder) { 
     // ... 
     this.senses = [ 
      this.createSense() 
     ]; 
     // ...    
     // build the form 
     this.wordForm = this.formBuilder.group({ 
      "lemma": ["", Validators.compose([Validators.required, LemmaValidator.isValidLemma])], 
      "language": ["eng", Validators.required], 
      "class": ["s.", Validators.required], 
     }); 
     this.lemma = <Control> this.wordForm.controls["lemma"]; 
     this.language = <Control> this.wordForm.controls["language"]; 
     this.class = <Control> this.wordForm.controls["class"]; 
     // ... 
    } 
} 

B)的子组件:

@Component({ 
    selector: "word-sense", 
    directives: [FORM_DIRECTIVES], 
    template: ` 
    <form class="form-inline" role="form" [ngFormModel]="senseForm"> 

    <div class="form-group" 
     [class.has-error]="!definitionCtl.valid"> 
     <input type="text" 
       class="form-control" 
       placeholder="definition" 
       [ngFormControl]="definitionCtl" 
       [(ngModel)]="sense.definition"> 
    </div> 

    <div class="form-group" 
     [class.has-error]="!yearCtl.valid"> 
     <input type="number" 
       class="form-control" 
       placeholder="date" 
       [ngFormControl]="yearCtl" 
       [(ngModel)]="sense.year"> 
    </div> 
    ...   
</form> 
    `, 
    inputs: [ 
     "sense", 
     "ranks", 
     "fields" 
    ] 
}) 
export class WordSense { 
    // model being edited 
    public sense: ISenseViewModel; 
    // lookup data 
    public ranks: IPair<number>[]; 
    public fields: IFieldModel[]; 
    public field: IFieldModel; 
    // form 
    public senseForm: ControlGroup; 
    public definitionCtl: Control; 
    public yearCtl: Control; 
    public rankCtl: Control; 
    public fieldsCtl: Control; 

    constructor(private formBuilder: FormBuilder) { 
     this.senseForm = this.formBuilder.group({ 
      "definition": ["", Validators.required], 
      "year": [0, Validators.compose([Validators.required, YearValidator.isValidYear])], 
      "rank": [{value: 2, label: "media"}, Validators.required], 
      "fields": [""] 
     }); 
     this.definitionCtl = <Control> this.senseForm.controls["definition"]; 
     this.yearCtl = <Control> this.senseForm.controls["year"]; 
     this.rankCtl = <Control> this.senseForm.controls["rank"]; 
     this.fieldsCtl = <Control> this.senseForm.controls["fields"]; 
    } 
    // ... 
} 
+0

[使用组件的角2形式级别的验证](的可能的复制http://stackoverflow.com/questions/34980344/angular-2-form-level-validation-using -components) –

回答

0

要有更具可读性的错误,你可以改变Angular2 .min.js文件到.dev.js的。

这样做,你现在有以下错误:

No Directive annotation found on FormBuilder

事实上,问题是你设置的FORM_PROVIDERS到组件的directives属性。因此,尝试使用提供商的指令,但他们都没有......

@Component({ 
    selector: "word", 
    directives: [FORM_DIRECTIVES, FORM_PROVIDERS, WordSense], <----- 
    templateUrl: ` 
    <div> 
    (...) 
    ` 
}) 
export class ... 

删除它应该解决您的问题:

@Component({ 
    selector: "word", 
    directives: [FORM_DIRECTIVES, WordSense], <----- 
    templateUrl: ` 
    <div> 
    (...) 
    ` 
}) 
export class ... 

另一个问题是,你使用templateUrl而不是templateWord成分:

@Component({ 
    selector: "word", 
    directives: [FORM_DIRECTIVES,WordSense], 
    templateUrl: ` <---------- 
    ` 
    (...) 

你应该使用这样的:

@Component({ 
    selector: "word", 
    directives: [FORM_DIRECTIVES,WordSense], 
    template: ` <---------- 
    ` 
    (...) 

这里是重构的plunkr:http://plnkr.co/edit/x0d5oiW1J9C2JrJG8NdT?p=preview

希望它能帮助你, 亨利

+0

谢谢!可悲的是,另一个问题是:在我的应用程序中,单词组件将其单词模型绑定到另一个父级,可以将其设置为:只是一个普通的[单词] =“单词”。当word属性发生变化时,我会收到异常,例如“表达式在检查后发生了变化”(指的是有效属性)。比赛状况?我发现只有这个:http://stackoverflow.com/questions/35019829/formbuilder-control-causing-expression-has-changed-after-it-was-checked-except。你能想象任何解决方案吗? – Naftis

+0

鉴于评论似乎不适合这个,这似乎是一种不同的错误,我在这里提出了一个关于这个问题的新帖子:http://stackoverflow.com/questions/35219844/angular2-beta3-expression-has-changed之后被检入更新的形式。 – Naftis

+0

@thierry您没有更改最后一个示例中的代码 – select