Angular binding object with array from component to view with ngModels

为君一笑 提交于 2019-12-10 12:58:46

问题


I tried to bind my model on my view, but I have a problem when I submit my form : I don't have an array, but many property.

component :

export class QuizFormAddQuestionComponent implements OnInit {
    public question: Question;

    constructor() {
        this.question = new Question();
    }

    ngOnInit() {
        this.question.setModel({ question: 'test' });
        this.question.setAnswers(3);
    }

    createQuestion(form) {
        console.log(form.value);
    }

}

my template :

<hello name="{{ name }}"></hello>

<div class="row">
    <div class="col-sm-1"></div>
    <div class="col-sm-10">

        <form #form="ngForm" (ngSubmit)="createQuestion(form)" class="mt-4">
            <div class="form-row">
                <div class="form-group col-md-12">
                    <label for="question" class="col-form-label">Question</label>
                    <input type="text"
                           class="form-control"
                           id="question"
                           placeholder="Enter your question..."
                           name="question"
                           [ngModel]="question.question"
                           required>
                </div>
            </div>
            <div class="form-group row" *ngFor="let answer of question.answers; let i = index;">
                <div class="col-sm-12">
                    <div class="form-check">
                        <label class="form-check-label">
                            <input class="form-check-input"
                                   type="checkbox"
                                   id="answer-value-{{i}}"
                                   [ngModel]="question.answers[i].value"
                                   name="answers[{{i}}].value">
                            Answer {{ i }}
                        </label>
                    </div>
                    <input type="text"
                           class="form-control"
                           id="answer-text-{{i}}"
                           [ngModel]=question.answers[i].text
                           name="answers[{{i}}].text">
                           {{ answer.getManipulateObjet() }}
                </div>
            </div>
            <div class="form-row">
                <div class="form-froup col-md-12 text-right">
                    <button type="submit" class="btn btn-primary">Add question</button>
                </div>
            </div>
        </form>
    </div>
</div>

question.ts (model)

import { Answer } from "./answer";

export class Question {

    constructor(private question: string          = '',
                private answers: any[]            = [],
                private more_informations: string = '',
                private difficulty: number        = 0,) {
    }

    setModel(obj) {
        Object.assign(this, obj);
    }

    addAnswer() {
        let new_answer = new Answer();

        new_answer.setModel({ text: 'test', value: false });

        this.answers.push(new_answer);
    }

    setAnswers(number_answers) {
        for (let i = 0; i < number_answers; i++) {
            this.addAnswer();
        }

        console.log(this);
    }

}

answer.ts (model)

export class Answer {

    constructor(private text: string  = '',
                private value: boolean = false,) {
    }

    setModel(obj) {
        Object.assign(this, obj);
    }

    getManipulateObjet() {
      return '=== call getManipulateObjet() for example : return more information after manipulating object, count value properties, concat, etc... ===';
    }

    getCount() {
      // ....
    }

    getInspectMyObject() {
      // ...
    }
}

initial object :

console after submit :

After the submit I would like the same things as the initial object (same structure with the data updated), the same data structure before and after submit

I tried this on in my view, but it doesn't work :

<div class="form-group row" *ngFor="let answer of question.answers; let i = index;">
    <div class="col-sm-12">
        <div class="form-check">
            <label class="form-check-label">
                <input class="form-check-input"
                       type="checkbox"
                       id="answer-value-{{i}}"
                       [ngModel]="answer.value"
                       name="answer[{{i}}].value">
                Answer {{ i }}
            </label>
        </div>
        <input type="text"
               class="form-control"
               id="answer-text-{{i}}"
               [ngModel]=answer.text
               name="answer[{{i}}].text">
               {{ answer.getManipulateObjet() }}
    </div>
</div>

I transform in the *ngFor [ngModel]=question.answers[i].text by [ngModel]="answer.text", but I have the same problem...

I tried many things from differents posts : Angular 2 form with array of object inputs, Angular 2 - 2 Way Binding with NgModel in NgFor

But always many properties and no array

I would like to do this without reactive form, only template driven

Demo:

https://angular-by7uv1.stackblitz.io/

I would like to use different function from my object 'answer', for example : answer.getInformation(), getCount(), getInspectMyObject() etc.. to iterate on my object only, in my view. This function is provided by my model 'Answer' to have a clean code in my view. I would like use many functions from my model in the *ngFor. If I use the reactive form, I can't use different function from my model because the "link" between my parent object and my childs is broken.

SOLVED

https://fom-by-template-driven.stackblitz.io


回答1:


The problem is, whatever the input name specified, it will be considered as just text. Should not reference any Object or Array.But with slight modifications, there is a chance to obtain the same data structure with updated data.

All elements are binded in one way, so make it two way binding. So whenever input value changes, The binded element value updates.

 [(ngModel)]="question.question"

Use template driven form for validation

<form #form="ngForm" (ngSubmit)="createQuestion()" class="mt-4">
...
<button [disabled]="!form.valid"  

Now the values are validated & updated in the variable question.There is no need to get the value from form, use the updated object question to create question.

createQuestion() {
        console.log(this.question);
    }

View the results in worked out App




回答2:


You can do something like this:-

import {Component, OnInit} from '@angular/core';

import {FormGroup, FormArray, FormControl} from '@angular/forms';

@Component({

  selector: 'form-component',

  template: `

    <form [formGroup]="formGroup">
      <div formArrayName="inputs" *ngFor="let control of formArray;     let i = index;">
        <input placheholder="Name please" formControlName="{{i}}"/>
      </div>
    </form>

    <button (click)="addInput()">Add input</button>

  `
})

export class FormComponent implements OnInit{

  formGroup: FormGroup;


  contructor() {
  }


  ngOnInit(){

    this.formGroup = new FormGroup({
      inputs: new FormArray([
        new FormControl("Hello"),
        new FormControl("World"),
      ]);
    });
  }

  get formArray() {

    return this.formGroup.get('inputs').controls
  }


  addInput(){

    this.formArray.push(new FormControl("New Input"));
  }

}



回答3:


i see that you are using [ngModel] in you html template. this will only bind the input to bind the output as well you need to use [(ngModel)]. this is the regular way of using ngModel. i find one more wrong in your code that name="answer[{{i}}].value"here name is value should be constant, you are giving it as variable the correct way of writing it is name="{{answer[i].value}}"




回答4:


The following scenario is not possible using the current Angular Template driven form. There is a issue raised to the Angular Team LINK.

Its requires a lot of rework as the template driven forms uses ngModel . Angular Forms are moving towards reactive approach and in the near feature i dont see this feature being added to it.

Please use Reactive forms for this formArrayName will be sufficient to help get the desired result.



来源:https://stackoverflow.com/questions/45969004/angular-binding-object-with-array-from-component-to-view-with-ngmodels

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!