ค้นหาเว็บไซต์

typescript - Angular2 เบต้า: การซ้อนคอมโพเนนต์แบบฟอร์มพาเรนต์/ไชลด์และการตรวจสอบจากพาเรนต์


ฉันกำลังพยายามนำไปใช้งานใน Angular2 (เบต้า 0 กับ TS ใน Plunker) สำหรับสถานการณ์ที่มีฟอร์มซ้อนกัน 2 ฟอร์ม แต่ละฟอร์มถูกแทนด้วยคอมโพเนนต์

คอมโพเนนต์ผู้ปกครองคือ Word ซึ่งแทนคำในพจนานุกรมปลอม คอมโพเนนต์ลูกคือ WordSense แต่ละตัวแทนความหมายของคำผู้ปกครอง

ทั้งสองคอมโพเนนต์ใช้ฟอร์มที่ขับเคลื่อนด้วยโมเดล และฟอร์มลูกผูกค่าของโมเดลกับคอนโทรลของฟอร์มโดยใช้ ngModel ด้วยวิธีนี้ คอมโพเนนต์แม่สามารถส่งความหมายของคำลงไปยังคอมโพเนนต์ลูกได้อย่างง่ายดาย และการผูกแบบสองทิศทางจะจัดการส่วนที่เหลือ

ตัวตรวจสอบแบบกำหนดเองง่าย ๆ ถูกแนบไปกับทั้งสองฟอร์ม นอกจากสิ่งอื่น ๆ ฉันต้องการปิดการใช้งานปุ่มส่งไม่เพียงแต่เมื่อฟอร์มคำไม่ถูกต้อง แต่ยังเมื่อความหมายใด ๆ ของมันไม่ถูกต้องด้วย เพื่อวัตถุประสงค์นี้ ฉันได้เพิ่มคุณสมบัติ isValid ให้กับโมเดลที่กำลังแก้ไข และโค้ดเพื่อติดตามการเปลี่ยนแปลงในฟอร์มความหมาย: ทุกครั้งที่เกิดการเปลี่ยนแปลง ฉันจะตรวจสอบคุณสมบัติ valid ของฟอร์มและตั้งค่าคุณสมบัติของโมเดลตามนั้น จากนั้นฉันสามารถเพิ่มการตรวจสอบได้ง่าย ๆ ที่ระดับของคอมโพเนนต์หลักในมุมมองและในโค้ดเพื่อให้ฉันสามารถโพสต์ได้ก็ต่อเมื่อทั้งสองฟอร์มถูกต้อง

เพื่อสนับสนุนการตรวจสอบแบบกำหนดเองและตรรกะเพิ่มเติม ฉันได้เปลี่ยนโค้ดเริ่มต้นจากฟอร์มแบบใช้เทมเพลตไปเป็นฟอร์มแบบใช้โมเดล; แต่ทันทีที่ฉันเปิดใช้งานโค้ดที่ปรับปรุงแล้ว ฉันได้รับข้อผิดพลาดหลายรายการ No Directive annotation found และฉันไม่แน่ใจว่าหมายความว่าอย่างไร

ผมอาจจะพลาดบางสิ่งที่ชัดเจนไป แต่ผมเป็นมือใหม่ที่นี่ มีใครพอจะแนะนำได้ไหม? คุณสามารถหาตัวอย่างซ้ำได้ที่ plunker นี้: 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"];
    }
    // ...
}

คำตอบ #1

เพื่อให้ข้อผิดพลาดอ่านได้ง่ายขึ้น คุณสามารถเปลี่ยนไฟล์ Angular2 .min.js เป็นไฟล์ .dev.js ได้

การทำเช่นนี้ ตอนนี้คุณจะพบข้อผิดพลาดดังต่อไปนี้:

ไม่พบคำอธิบายประกาศ Directive บน FormBuilder

ในความเป็นจริง ปัญหาคือคุณกำหนด FORM_PROVIDERS เข้าไปในแอตทริบิวต์ directives ของคอมโพเนนต์ของคุณ ดังนั้นมันจึงพยายามใช้ 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 แทน template สำหรับคอมโพเนนต์ Word ของคุณ:

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

คุณควรใช้สิ่งนี้แทน:

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

นี่คือ plunkr ที่ได้รับการปรับโครงสร้างใหม่: http://plnkr.co/edit/x0d5oiW1J9C2JrJG8NdT?p=preview.

หวังว่านี่จะช่วยคุณได้ Thierry

บทความที่เกี่ยวข้อง