Utilizing Angular 2's ngModel feature for dynamic objects and properties

Within my TypeScript file, I am dynamically generating properties on the object named selectedValsObj in the following manner:

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] };
      }
    })
  });
}

When it comes to the HTML part, I desire to bind the [ngModel] attribute of my inputs to the properties existing within the selectValsObj object. Despite attempting various approaches, I have not been able to achieve the desired outcome:

<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" // <== doesn't work either**
                // [(ngModel)]="selectValsObj[{{ questionId }}].selected" // <== also doesn't work**
                name="answerForQuestion{{ question?.questionId }}">
            <option *ngFor="let answer of question?.answerDetails"
                [ngValue]="answer">
                    {{ answer?.value }}
            </option>
        </select>
    </div>
</div>

Is there a way for me to properly assign the ngModel within my HTML to a property that is created dynamically within my TypeScript file?

Answer №1

Upon attempting to replicate the scenario, I noticed multiple issues within the code snippet you provided.

  1. The property selectValsObj is declared as private, yet it is being utilized in the template.
  2. In the template, there is an attempt to iterate over section.questions, but this array is not defined elsewhere apart from the setSelectedValsObj method's local scope.
  3. You may be misusing your data due to a lack of type definitions.

This revised version includes inferred type definitions:

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]};
        }
      });
    });
  }
}

Prior to implementation, ensure the type definitions align with your intentions to reduce potential errors.

Additionally, consider adopting a more declarative approach by utilizing map and filter for data manipulation instead of relying solely on forEach.

Answer №2

Review the HTML code snippet below:

[(ngModel)]="selectValsObj[questionId].selected"

If you have not defined a variable named questionId with a value in your TypeScript file, this could be causing an issue.

To obtain the questionId for each question within your section.questions loop, consider using the following modification:

[(ngModel)]="selectValsObj[question.questionId].selected"

I've included a simple example demonstrating various scenarios in this link (located in the src/app.ts). Hopefully, it provides some assistance.

Answer №3

(click)="toggle(personnel.id)"
  *ngIf="isToggled[personnel.id]"

in typescript file:

isToggled: any = {};

inside toggle method,

this.isToggled[personnelId] = !this.isToggled[personnelId];

Answer №4

  • Your intentions seem a bit unclear at the moment.
  • It appears that you are aiming to dynamically construct a page featuring questions and answers in a drop-down format, along with capturing the selected answer.
  • If this is the case, the code snippet below may be of assistance.

If so, the following Angular code can guide you:

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

interface Question {
  questionStr: string;
  questionId: string;
  type: string;
  answers: Array<string>;
  selectedAnswer: string;
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  title = 'app';

  selectValsArr: Array<Question> = [];

  ngOnInit() {
    this.setSelectedValsObj([
      {
         questionStr : 'Question1',
         questionId: 'Q01',
         type: 'drop-down',
         answers: ['Q1Ans1', 'Q1Ans2', 'Q1Ans3'],
         selectedAnswer: null
      },
      {
        questionStr: 'Question2',
        questionId: 'Q02',
        type: 'drop-down',
        answers: ['Q2Ans1', 'Q2Ans2', 'Q2Ans3'],
        selectedAnswer: null
      },
    ]);
  }


  setSelectedValsObj(sectionsArr: Array<Question>) {
    sectionsArr.forEach(section => {
      if (section.type === 'drop-down') {
        this.selectValsArr.push(section);
        }
    });
  }
}

and HTML

<div *ngFor="let question of selectValsArr">
  <h3>{{question.questionStr}}</h3>
  <div class="drop-down-question">
    <select [(ngModel)]="question.selectedAnswer">
      <option value="">Select an Answer</option>
      <option *ngFor="let ans of question.answers" [ngValue]="ans"> {{ans}}</option>
    </select>
  </div>
</div>

<br>
<h2>Selected Answer</h2>

<div *ngFor="let question of selectValsArr">
    <span>{{question.questionStr}}</span>
    <span>&nbsp; &nbsp; - &nbsp; {{question.selectedAnswer}}</span>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

"Utilizing Typescript's keyof operator on its own

I'm grappling with the challenge of creating a type that can utilize the typeof its own keys, but I'm hitting a roadblock. Below is a simplified version of what I'm attempting to achieve: type SpecialType = Record<string, (getter: <K e ...

Remember to always call "done()" in Typescript + Mocha/Chai when dealing with async tests and hooks. Additionally, when returning a Promise, make sure it resolves correctly

It seems like I'm facing an old issue that I just can't seem to resolve, despite trying everything in my power. The error message reads: Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Pro ...

Issue with Angular2 Property Change Notification

I have a directive called app.service.ts that holds the state data of the app. I'm using this directive in other components to access and modify the app state, which is functioning correctly. However, I encounter an error when I attempt to bind a pro ...

What methods are available to enhance the appearance of a string with TypeScript Angular in Python?

Looking to enhance the appearance of a Python string for display on an HTML page. The string is pulled from a database and lacks formatting, appearing as a single line like so: for count in range(2): global expression; expression = 'happy'; sto ...

Angula 5 presents a glitch in its functionality where the on click events fail

I have successfully replicated a screenshot in HTML/CSS. You can view the screenshot here: https://i.stack.imgur.com/9ay9W.jpg To demonstrate the functionality of the screenshot, I created a fiddle. In this fiddle, clicking on the "items waiting" text wil ...

Concealing the TinyMce Toolbar upon initialization

After setting my content with tinymce, I want to make the toolbar readonly. To achieve this, I subscribed to the editor's init function like so: editor.on('init', () => { editor.setContent(this.value); if (this.disab ...

Is there a way to identify the specific button that was clicked within an Angular Material dialog?

import {Component, Inject} from '@angular/core'; import {MdDialog, MdDialogRef, MD_DIALOG_DATA} from '@angular/material'; /** * @title Dialog Overview Example with Angular Material */ @Component({ selector: 'dialog-overview-ex ...

Remove all input fields within an HTML file using a TypeScript method implemented in an Angular 2 component

Within my Angular project, there are several input elements in the HTML file that are not enclosed within a form tag. I am looking to create a function in the TypeScript file that will clear all of these inputs. I attempted to utilize ViewChild, but it a ...

How can you ensure that an inline <span> automatically moves to the next line if it is too wide?

Struggling with bootstrap badges and trying to arrange <span> elements to appear on the next line when they are too large. On mobile, my page looks like this: Joe Bloggs (Bigger Badge) Joe Bloggs Brother (SMALL BADGE) How can I configure it so t ...

What could be causing this discriminated union to act differently than anticipated?

Desired Outcome When the href prop is present, TypeScript should recognize that the remaining props are suitable for either a Link or Button element. However, I am encountering an error indicating type conflicts with the button element. Type '{ chil ...

The component fails to load on the designated router outlet

I have updated my question to provide more clarity. I am working with 2 routing files, admin-layout.routing.ts and parameter.routing.ts. In admin-layout.routing.ts, there is a path for property.component.ts with a child called parameter.component.ts. Insid ...

Utilizing React-hook-Form to transfer data between two SelectBoxes

This simple logic is causing me some trouble. Despite using react-hook-form, I thought this would be easy. However, after struggling with it for over a week, I'm still facing challenges. I'm incorporating nextUI components into my project. < ...

Having trouble getting your .NET Core web application to run properly with Angular

https://i.sstatic.net/N5krh.png I am having trouble launching a sample application and encountering several errors in the process. For instance, when I run npm install -g @angular/cli, I receive an error message stating that ng is not recognized as an int ...

What is the best method for connecting an Angular 2 application with an existing Angular JS app?

I recently created an application using Angular 2 and now I am looking to combine it with an Angular JS app. ...

What is the process for importing libraries from a different local directory?

What I mean by that title is: I have some code that was generated and now I am incorporating it into my Angular application. Currently, I am installing this code as a package using npm, but it is causing issues with my deployment setup. So, I would like ...

Array updating using the foreach method in Angular

Hey everyone, I've encountered an error that seems to be related to scope and I could use some advice. I'm currently looping through an array and trying to push the results to another array. However, when I attempt to push the results to public m ...

The color syntax in the text editor of Visual Studio 2022 is being lost when casting an interface

After attempting to cast an interface, the entire code turns white. let object : someInterface = <someInterface> someUnknownHapiRequestPayload View a screenshot of the text editor here I have already tried common troubleshooting steps such as updat ...

What steps are involved in implementing ts-transformer-keys in a Next.js project?

I am trying to extract keys from an interface as a string array so that I can iterate over them. After doing some research on stackoverflow, I found out that I need to use a library called 'ts-transformer-keys'. In my Next.js project, which invol ...

Discovering the world of Promises in TypeScript and understanding how to return specific types

Transitioning from coding in Clojure for the past two years to TypeScript has been an interesting journey. However, I've hit a bit of a roadblock today. The issue lies with my interface: interface ICustomer { id: number, first_name: string } I ...

Having difficulty connecting web API service data to ng2-smart-table in Angular 2

Although I can fetch the data from my service, I am struggling to bind it to an ng2-smart-table for display in a grid view format. Table Component Code: table.component.ts @Component({ selector: 'ngx-table', templateUrl: './table.compo ...