Difficulty with the value binding issue on input text produced by *NgFor

When using *ngFor in Angular to loop over an array and generate input text elements bound to the values in the array, I'm encountering some issues. The value is not binding correctly when a user inputs something into the text field.

I attempted to run changeDetection after updating the array but it did not resolve the problem.

In the code example below, I am dynamically generating input elements by clicking on an add button using an array of string values "test". The [ngModel] of the input is supposed to bind to the value inside the array, so all inputs should have the value "test".

However, when entering a value into the input field and then clicking on the add button, the generated input does not bind to the value in the array.

Link to Code Example

import { Component } from '@angular/core';
@Component({
  selector: 'my-app',
  template: `
    <button (click)="onAdd()">Add</button>
    <br/><br/>
    <input
      *ngFor="let d of data;let i = index;trackBy:trackByfn" 
      type="text"
      [ngModel]="data[i]"
    > 
    <br/><br/>
    data: {{data|json}}
  `,
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  data = ['test'];  
  onAdd() {  
    this.data.push('test');
  }
  trackByfn = (index) => index;
}

Answer №1

Take a look at a live example on StackBlitz.

This code demonstrates two-way binding using the syntax ---> [(ngModel)]. This allows you to keep track of variable changes and get new values.

import { Component } from '@angular/core';
@Component({
  selector: 'my-app',
  template: `
    <br/><br/>
    <input *ngFor="let d of data; let i = index; trackBy:trackByfn" 
    type="text" [value]="data[i]" [(ngModel)]="dataarray"> 
    <button (click)="onAdd(data[i])">Add</button>
    <br/><br/>
    data: {{data|json}}
  `,
  styleUrls: [ './app.component.css' ]
})
export class AppComponent {
  data = ["ssdsdsd"];
  datatosave: any;  
  onAdd(data1) {  
    this.data.push(this.datatosave);
  }
  trackByfn = (index) => index;
}

Answer №2

To enable Two-way Data Binding, it's necessary to switch from using [ngModel] to [(ngModel)].

If you want to learn more about angular data binding, check out this informative article:

import { Component } from '@angular/core';
@Component({
  selector: 'my-app',
  template: `
    <button (click)="onAdd()">Add</button>
    <br/><br/>
    <input 
      *ngFor="let d of data; let i = index; trackBy:trackByfn"
      type="text"
      [(ngModel)]="data[i]"
    /> 
    <br/><br/>
    data: {{data|json}}
  `,
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  data = ['test'];  
  onAdd() {  
    this.data.push('test');
  }
  trackByfn = (index) => index;
}

Update: Implementing Form Group

import { Component } from '@angular/core';
import { FormGroup, FormControl, Validators, AbstractControl } from '@angular/forms';

@Component({
  selector: 'my-app',
  template: `
    <button (click)="onAdd()">Add</button>
    <div [formGroup]="form" *ngFor="let f of fields">
      <input type="text" [formControlName]="f" /> 
    </div>
    <div *ngFor="let f of fields">
      {{form.controls[f].value}}
    </div>
  `,
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  form: FormGroup = new FormGroup({
    test: new FormControl('test')
  });
  fields = ['test'];
  onAdd() {
    const length = this.fields.length;
    this.fields.push('test'+length);
    this.form.addControl('test'+length, new FormControl('test'));
  } // length to dynamically name the field
}

Note: Remember to include ReactiveFormsModule in your imports withinapp.module.ts

I have made some modifications to your stackblitz example: https://stackblitz.com/edit/angular-2t157s

Answer №3

Utilize the @ViewChildren directive to dynamically add elements. The onAdd() function pushes the last element of the inputs array to the data[]. Take a look at this example on StackBlitz for reference.

Sample code:

import { Component, ViewChildren, ElementRef, 
         QueryList, AfterViewInit } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
  <button (click)="onAdd()">Add</button>
  <br/><br/>
  <input #inputRef type="text" 
  *ngFor="let d of data; let i = index; trackBy:trackByfn"> 
  <br/><br/>
  data: {{data | json}}
  `,
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  data = ['test'];

  @ViewChildren("inputRef") inputs: QueryList<ElementRef>;

  onAdd() {
    let domElement = this.inputs.last as ElementRef;
    this.data.push(domElement.nativeElement.value);
  }

}

Dive deeper into the capabilities of @ViewChildren in the official Angular documentation.

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

Is there a way to help my KafkaJS consumer stay patient while waiting for a broker to become available?

My KafkaJS consumer setup looks like this: // Create the kafka client const kafka = new Kafka({ clientId, brokers, }); // Create the consumer const consumer = this.kafka.consumer({ groupId, heartbeatInterval: 3000, sessionTimeout: 30000, }); // ...

Absolute imports in create-react-app do not function properly when using yarn v2 workspaces alongside typescript

I am currently utilizing yarn v2 workspaces, and within my workspaces, I have a frontend project built using create-react-app / react-scripts. My goal is to enable absolute imports in the frontend application so that I can simply do things like import Butt ...

Tips for monitoring changes to files while developing a NestJs application within a Docker container

Having an issue with NestJS and Docker here. Trying to run the development script using npm start: dev, but encountering a problem where the app runs fine but doesn't detect any changes in the source files, hindering the development process. Here&apo ...

Is there a way to associate a click event with an angular2 template interpolation?

Can a click event be bound to an interpolation? Whenever I try to run the code below, I encounter the following ERROR Error: Uncaught (in promise): Error: Template parse errors: Parser Error: Got interpolation ({{}}) where expression was expected at col ...

The concept of Nested TypeScript Map Value Type

Similar to Nested Typescript Map Type, this case involves nesting on the "value" side. Typescript Playground const mapObjectObject: Map<string, string | Map<string, string>> = new Map(Object.entries({ "a": "b", &quo ...

Encountering issues with redirecting the URI when using Oidc-client in an Angular2 application with hash

I am currently following a tutorial on Authenticating Angular2 with Oidc-client and attempting to incorporate the authentication aspect into my project. Since Angular2 is using { provide: LocationStrategy, useClass: HashLocationStrategy } my URLs are no ...

Why does Angular keep changing my request method to OPTIONS?

I've been working on setting up a JWT Interceptor in Angular. Following the example provided here, I implemented my JWT interceptor using the code snippet below: import { HttpInterceptor, HttpRequest, HttpEvent, HttpHandler, HttpHeaders } from &apos ...

"Is there a way to extract a value from a JSON object using

I have an object with the following key-value pairs: { 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier': '918312asdasc812', 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name': 'Login1&a ...

The assignment to 'total' is prohibited as it is either a constant or a property that is read-only within the get total() function

After running the command ng build --prod in my project, I encountered the following error message: "Cannot assign to 'total' because it is a constant or read-only property for function get total(){}" The function causing the issue is: get to ...

Tips on converting a date string in the format 'dd/MM/yyyy' to a date type using TypeScript

I have attempted the following code in order to convert the date from 'yyyy-mm-dd' format to 'dd/MM/yyyy'. However, when I check the typeof() of the result, it shows that it is a string. Is there a method to convert it into only a date? ...

What's the most effective method for transferring data to different components?

How can I efficiently pass a user info object to all low-level components, even if they are grandchildren? Would using @input work or is there another method to achieve this? Here is the code for my root component: constructor(private _state: GlobalSta ...

Troubleshooting a dynamically loaded Angular 2 module in Chrome and VS Code

Currently, I am utilizing WebPack in conjunction with Angular 2/4 and incorporating modules that are lazy loaded. Due to this setup, the components and modules are not included in the primary .js file; instead, their code is distributed across files genera ...

The Step-by-Step Guide to Deselecting an Angular Checkbox with a Button

I currently have a situation where I have three checkboxes labeled as parent 1, parent 2, and parent 3. Initially, when the page loads, parent 1 and parent 3 are checked by default, while parent 2 is unchecked. However, when I manually check parent 2 and c ...

Cannot assign Angular 4 RequestOptions object to post method parameter

I'm having trouble with these codes. Initially, I created a header using the code block below: headers.append("Authorization", btoa(username + ":" + password)); var requestOptions = new RequestOptions({ headers: headers }); However, when I tried to ...

The method TranslateModule.forRoot does not require a specific type argument and produces a ModuleWithProviders type

After upgrading my Angular application from version 5 to version 9, I encountered an error during the build process. The error message stated: "TranslateModule.forRoot returns a ModuleWithProviders type without a generic type argument. Please add a ge ...

The various types of Angular 2 FormBuilders

As I delved into learning Angular 2, I initially came across ngModel, and later discovered FormGroup/FormBuilder which seemed more suitable for handling complex forms. However, one downside that caught my attention was that by using FormBuilder, we sacrifi ...

deliver a promise with a function's value

I have created a function to convert a file to base64 for displaying the file. ConvertFileToAddress(event): string { let localAddress: any; const reader = new FileReader(); reader.readAsDataURL(event.target['files'][0]); reader ...

Error: To execute NPX command locally from Google Maps API documentation, make sure to call npm.load(callback) as required

Attempting to execute the Google Maps API example locally using this command: npx @googlemaps/js-samples init directions-waypoints googlemapssample However, every time I try to run the npx command locally, it fails after a short period and I encounter the ...

Can we create an alias for the import path in TypeScript?

import A = require('../../distant/PathToA'); import B = require('./different/path/PathToB'); I am utilizing external modules (commonJS) and browserify, with WebStorm as my editor. If this were just regular javascript, there are severa ...

Customize the style of Angular Material within an Angular component

In my Angular component, I am utilizing Material 2's <md-input-container>. I am looking to customize a specific class, such as .mat-input-wrapper, that is originally defined in Angular Material. However, my intention is for this customization to ...