Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 - ngModel with dynamic object/properties

In my TS file I am dynamically creating the properties on my selectedValsObj object like this:

private selectValsObj: any = {};

setSelectedValsObj(sectionsArr) {
  sectionsArr.forEach(section => {
    section.questions.forEach(questionObj => {
      if (questionObj.type === 'drop-down') {
        this.selectValsObj[questionObj.questionId] = { selected: questionObj.answerDetails[0] };
      }
    })
  });
}

In my HTML I want to bind the [ngModel] on my inputs to the properties on the selectValsObj object. I have tried this but have had no luck:

<div *ngFor="let question of section.questions">
    <div class="drop-down-question" *ngIf="question?.type === 'drop-down'">
        <select class="q-select"
                [(ngModel)]="selectValsObj[questionId].selected" // <== doesnt work either**
                // [(ngModel)]="selectValsObj[{{ questionId }}].selected" // <== doesnt work**
                name="answerForQuestion{{ question?.questionId }}">
            <option *ngFor="let answer of question?.answerDetails"
                [ngValue]="answer">
                    {{ answer?.value }}
            </option>
        </select>
    </div>
</div>

How can I set the ngModel in my HTML to a dynamically created property in my TS file?

like image 915
georgej Avatar asked Nov 22 '16 03:11

georgej


1 Answers

I tried to replicate the situation but in the code, you have posted seem to be multiple problems.

  1. property selectValsObj is declared as private but you are trying to use it in the template
  2. in the template you are trying to iterate over section.questions but I don't see it defined anywhere else but in the setSelectedValsObj method forEach local scope
  3. You might be using your data wrong because of lacking type definitions

This is your code as I understood it and added typedefs

interface QuestionModel {
  type: string;
  questionId: string;
  answerDetails: string[];
}

const MOCK_DATA = [
  {
    questions: [{
      type: 'drop-down',
      questionId: '42',
      answerDetails: ['wololo'],
    }],
  },
];


@Component(...)
export class ProductsComponent {
  selectValsObj: { [key: string]: { selected: string } } = {};

  constructor() {
    this.setSelectedValsObj(MOCK_DATA);
  }

  setSelectedValsObj(sectionsArr: { questions: QuestionModel[] }[]) {
    sectionsArr.forEach(section => {
      section.questions.forEach(questionObj => {
        if (questionObj.type === 'drop-down') {
          this.selectValsObj[questionObj.questionId] = {selected: questionObj.answerDetails[0]};
        }
      });
    });
  }
}

After you check if the type definitions are as you originally intended (and use it properly) you will prevent a lot of bugs.

Also, consider using more declarative approach, map and filter your data instead of using forEach in a method.

like image 169
Vojtech Avatar answered Sep 18 '22 10:09

Vojtech