Guide on how to update an array within typed angular reactive forms

I'm currently working on finding a solution for patching a form array in a strongly-typed reactive Angular form. I've noticed that patchValue and setValue don't consistently work as expected with FormControl. Here's an example of the form:

 this.form = fb.group<IPersonForm>({
      name: new FormControl<string | null>('bob'),
      phones: new FormArray<FormGroup<IPhoneForm>>([]),
    });

Patching the name control is straightforward:

this.form.controls.name.patchValue('Jim', { onlySelf: true, emitEvent: false });

However, dealing with the form array poses a challenge. Let's say I create a replacement array:

const myPhone = this.fb.group<IPhoneForm>({
      phone: new FormControl<string | null | undefined>('bob')
    });
const array = new FormArray<FormGroup<IPhoneForm>>([myPhone]);

Now, attempting to patch (or set) the array results in compilation errors:

    //this.form.controls.phones.setValue(array);
    //this.form.controls.phones.setValue(array.controls);
    //this.form.controls.phones.patchValue(array);
    //this.form.controls.phones.patchValue(array.controls);

Although I can use setControl, this method lacks the option for onlySelf:

this.form.setControl('phones', array, { emitEvent: false });

I believe that onlySelf is essential in this scenario because when replacing the data and dealing with complex validations, I prefer to defer running them on any control until the entire form has been patched. Thank you!

For a demonstration, here's a stackblitz link: https://stackblitz.com/edit/angular-path-typed-array?file=src%2Fmain.ts

Answer №1

When you update a formArray, if the array does not have enough elements, those elements are not added. Only the first elements will be updated if there are fewer elements.

For example:

formArray=new FormArray<FormGroup<IPhoneForm>>([this.newPhoneGroup()])
ngOnInit(){
  const dataArray=[{phone:'222222'},{phone:'33333'}]
  this.formArray.patchValue(dataArray)
}
newPhoneGroup()
{
  return new FormGroup({
    phone:new FormControl()
  })
}

Your formArrayElement only has one element!

You can do the following:

dataArray=[{phone:'222222'},{phone:'33333'}]

this.formArray.clear();
while (this.formArray.controls.length<dataArray.length)
  this.formArray.push(this.newPhoneGroup());

this.formArray.patchValue(dataArray)

Alternatively, you can modify the newPhoneGroup function like this:

newPhoneGroup(data:any=null)
{
  data=data || {phone:''}
  return new FormGroup({
    phone:new FormControl(data.phone)
  })
}

Then write:

this.formArray=dataArray.map(x=>this.newFormGroup(x))

Answer №2

It's important to pass the logical value, rather than another form, when using patch method

this.form.controls.phones.patchValue([{phone: '123'}]);

Alternatively,

this.form.patchValue({phones: [{phone: '123'}]})

You can also combine both actions into one call by specifying the name as well:

this.form.patchValue({name: 'Jim', phones: [{phone: '123'}]})

If needed, you have the option to include onlySelf or emitEvent parameters, which are not directly related to the main question.

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

Angular - A Guide to Managing User Roles by Toggling Checkbox Values

In my current project, I am developing a web portal using Angular-7 for the frontend and Laravel-5.8 for the backend. Additionally, I am utilizing Laravel Spatie for User Role Management. Within the user.component.ts file: export class UsersComponent imp ...

Is it possible to display the combined string when concatenating two strings?

Consider the following code snippet: const a = "url"; const b = "/route"; const c = a + b; Even though TypeScript knows the exact values of a and b, resulting in immutable constants, when concatenating both strings, the type of c is di ...

Issue with Angular4 ngFor - Unable to locate a distinguishable entity supporting the object '[object Object]' categorized as 'object'

Currently, I'm diving into Angular 4 and actively working on displaying the results of a backend API call. Thankfully, I have successfully retrieved the data but am facing issues with how to showcase it. Below is the component code snippet: import { ...

Secure your TypeScript code by encapsulating it with protection mechanisms and distribute

Currently in the process of constructing an internal TypeScript "library" using webpack 1.14. I've set up an npm package and have it published on a private feed, which is working smoothly (able to utilize classes and interfaces from the library in o ...

Material-UI: Error thrown when attempting to pass props to makeStyles in React due to missing property 'X' on type '{}'

Currently experimenting with Adapting based on props, you can find more information here import React from 'react'; import { makeStyles } from '@material-ui/core'; const useStyles = makeStyles({ // style rule foo: props => ( ...

Struggling with breaking a string into an array in C

Need help with splitting a character string into an array called temp_dow. // Here is the code to parse the incoming string char input[] = {"1111111,0000000,1010101"}; char temp_dow[3][7]; char *tok1; int i = 0; tok1 = strtok(input, ","); while (tok1 != N ...

Subscribing to an RxJs Subject and receiving multiple values

In my Angular Service, there is a Subject defined like this: private sub = new Subject(); sendSub(page: page) { this.sub.next(page); } getSub(): Observable<any> { return this.sub.asObservable(); } In the parent component, I have subscribe ...

Passing the value of the attribute from event.target as a parameter in a knockout click event

I have been exploring knockout events and am currently working on a functionality involving three buttons ("Packers", "Trail Blazers", and "Dodgers") within a div. Each button is associated with a data-league attribute of "NFL", "NBA", and "MLB," respectiv ...

Arrangement of items in Angular 2 array

Received a JSON response structured like this JSON response "Terms": [ { "Help": "Terms", "EventType": "Success", "Srno": 1, "Heading": "Discount Condition", "T ...

Retrieve parent route parameters from a dynamically loaded route component

Struggling to access the parent route params in a lazy loaded route component using activatedRoute.parent.params. Despite this not working, I have managed to find a solution that involves fetching the value using an array index number which feels like a &a ...

Encounter an error while attempting to store and retrieve an array of JavaScript objects in localStorage and parsing the data

I'm dealing with an array of JavaScript objects, like this: var objectList = [{phone: true},{name: 'room'}]. My goal is to store this array in localStorage, retrieve it later, and continue working with the objects it contains. Here is what ...

ngx-upload-core and media files

Recently, I started working with the newest release of ngx-resource-core in Angular 7. I'm wondering if there is a method to submit a multipart form when considering that a model could include files or byte arrays? ...

Why is my Angular promise unexpectedly landing in the error callback?

I am facing an issue with my Angular + Typescript client. I have developed a PHP API and need to send a post request to it. Upon receiving the request, the server fills the response body with the correct data (verified through server debugging). However, w ...

Tips for retrieving a JSON object value using a key in Angular 6 View

As a beginner in Angular 6, I am struggling to figure out how to access values from a JSON object in the view using keys. In my service, I am making an http.get(url) call and then invoking that method in my component. export class CustomersComponent impl ...

What is the best way to change a timestamp into a date format using Angular?

I am struggling to convert a timestamp to the date format 'dd/MM/YYYY' but keep getting a different date format in the output. I am using syncfusion spreadsheet for this task. https://i.sstatic.net/BoRaa.png export-electronic.component.ts updat ...

The Content Security Policy directive has blocked the font from loading

After successfully creating an Angular project using angular-cli, I attempted to start the project with npm start. However, I encountered an error message indicating that a font was refused to load. Refused to load the font 'data:font/woff;base64,d0 ...

What is the best way to extract multiple records from an Array?

Below is a simple filter function that filters Rec_pagedItems in an array called allItems. someval(value){ if(value.length>=5){ this._pagedItems= this.allItems.find(e=>e.uniqueid == value || e.name == value ); if(this._pagedItem ...

Instructions on transferring JSON data to clipboard using a button

How can I copy JSON data to clipboard using a button click? { "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": [ ... ], "Resource": "*" } ] } I attempted to ...

How can I use Typescript to define a function that accepts a particular string as an argument and returns another specific string?

I've been working on this code snippet: const Locales = { en_gb: 'en-gb', en_us: 'en-us', } as const type ApiLocales = typeof Locales[keyof typeof Locales] type DatabaseLocales = keyof typeof Locales function databaseLanguage ...

Styling a <slot> within a child component in Vue.js 3.x: Tips and tricks

I'm currently working on customizing the appearance of a p tag that is placed inside a child component using the slot. Parent Component Code: <template> <BasicButton content="Test 1234" @click="SendMessage('test') ...