Creating Dynamic Radio Lists with Angular Forms
Tags: angular, forms
Published: 2019-09-04 15:21:00

---
title: Creating Dynamic Radio Lists with Angular Forms
description: Learn how to dynamically create a radio list using Angular Reactive Forms and asynchronous data.
keywords: Angular, Angular Forms, Radio List, Cory Rylan
tags: angular, forms
canonical_url: https://coryrylan.com/blog/creating-dynamic-radio-lists-with-angular-forms
published: true
---

When building real-world applications with complex forms, often we need to create the forms dynamically. Commonly, we need to load in data and
construct the form based on that data. In this tutorial, we will see how to create a radio list from an asynchronous data source.

Our example we will create a simple radio list that iterates over a list
of orders for a user to choose like the radio list below.

```html
<label><input type="radio" name="orders" value="1" checked />order 1</label>
<label><input type="radio" name="orders" value="2" />order 2</label>
<label><input type="radio" name="orders" value="3" />order 3</label>
<label><input type="radio" name="orders" value="4" />order 4</label>
```

First, we need to create our form in Angular. The first step is to import
the `ReactiveFormsModule` into our application module. By importing the
Reactive Forms Module into our application module we enable the Reactive
Forms API for our entire application.

```typescript
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

@NgModule({
  imports:      [ BrowserModule, ReactiveFormsModule ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }
```

Next, we need to create the form using the `FormBuilder` service. This service makes it easy to create complex Angular forms and manage validation. To use the `FormBuilder` service we use Angular's dependency injection system by listing the dependency in the constructor of our component. Angular instantiates and passes in an instance of the `FormBuilder` service for the component to use.

```typescript
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, FormArray, FormControl, ValidatorFn } from '@angular/forms';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  form: FormGroup;

  constructor(private formBuilder: FormBuilder) {
    this.form = this.formBuilder.group({
      orders: ['']
    });
  }

  submit() {
    console.log(this.form.value);
  }
}
```

The form builder creates a `FormGroup` instance. The form group contains one to many `FormControl`s. Our single input in this form is our `orders`
radio list input. Each control takes a default initial value and a list
of one to many optional validation rules.

For now, we are going to hard code our data into our component we will use to create our radio list input.

```typescript
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, FormArray, FormControl, ValidatorFn } from '@angular/forms';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  form: FormGroup;
  orders = [];

  constructor(private formBuilder: FormBuilder) {
    this.form = this.formBuilder.group({
      orders: ['']
    });

    this.orders = this.getOrders();
  }

  getOrders() {
    return [
      { id: '1', name: 'order 1' },
      { id: '2', name: 'order 2' },
      { id: '3', name: 'order 3' },
      { id: '4', name: 'order 4' }
    ];
  }

  submit() { ... }
}
```

We loop over our orders data using ngFor to build the radio list items in
the HTML template.

```html
<form [formGroup]="form" (ngSubmit)="submit()">

  <label *ngFor="let order of orders;">
    <input formControlName="orders" type="radio" name="orders" [value]="order.id" />
    {{order.name}}
  </label>

  <button>submit</button>
</form>
```

For each order in our data, we create a single radio input and bind the order id as the value for the individual radio input. One thing to note when you bind data to a value attribute in HTML the value is always treated as a string.

Now that we have our dynamic radio list created, let's make it get the data asynchronously. We usually get data from an API request. In this example, we simulate an API request using an Observable to emit our data.

```typescript
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, FormArray, FormControl, ValidatorFn } from '@angular/forms';
import { of } from 'rxjs';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  form: FormGroup;
  orders = [];

  constructor(private formBuilder: FormBuilder) {
    this.form = this.formBuilder.group({
      orders: ['']
    });

    // mimic async orders
    of(this.getOrders()).subscribe(orders => {
      this.orders = orders;
      this.form.controls.orders.patchValue(this.orders[0].id);
    });
  }

  getOrders() {
    return [
      { id: 100, name: 'order 1' },
      { id: 200, name: 'order 2' },
      { id: 300, name: 'order 3' },
      { id: 400, name: 'order 4' }
    ];
  }

  submit() { console.log(this.form.value) }
}
```

Using the RxJS `of()` operator, we can convert our data to by async similar to if we requested the data via Angular's HTTP Client Service. We subscribe to the async data and assign it to our orders property. We need to update the radio list to have an initial default value once our async data has loaded. We can do this by using the `patchValue` method on our form control.

```typescript
of(this.getOrders()).subscribe(orders => {
  this.orders = orders;
  this.form.controls.orders.patchValue(this.orders[0].id);
});
```

If we log out the value of our form, we should see the `id` of the selected order
from the radio list.

```bash
{ orders: 100 }
```

You can find the full working [demo here](https://stackblitz.com/edit/angular-hfzywh)!