Search code examples
angularangular2-formsangular2-servicesangular-reactive-forms

Angular 2 Reactive Forms, select control filled from service


I'm trying to use Angular's reactive forms and I have trouble figuring out how to delay default value binding for drop down lists filled by a service. Here's fragments of my component's code:

export class TransferComponent {
id: number;
accounts: Account[] = [];
myForm: FormGroup;
transfer: Transfer;

constructor(
    private http: Http,
    private fb: FormBuilder,
    private route: ActivatedRoute,
    private transferService: TransferService,
    private accountService: AccountService,
    private router: Router) {
    this.transfer = new Transfer();
    this.myForm = fb.group({
        'id': [null],
        'accountFromId': [this.transfer.accountFromId, Validators.required],
        'accountToId': [this.transfer.accountToId, Validators.required],
        'title': [this.transfer.title, Validators.required],
        'amount': [this.transfer.amount, Validators.required],
        'transferDate': [this.transfer.transferDate, Validators.required]
    });
}

ngOnInit(): void {
    this.accountService.getAccountList()
        .then(accounts => this.accounts = accounts);
    this.route.queryParams.subscribe(params => {
        this.id = params['id'];
        if (this.id) {
            this.transferService.getTransfer(this.id)
                .then(transfer => {
                    this.transfer = transfer;
                    this.myForm.setValue(transfer);
                });
        }
    });
}

The idea here is to try and get 'id' parameter, call service for a transfer entity and bind it to form with prefilled drop downs with account entries. Part of my view looks like this:

<select class="form-control"
                id="accountFromInput"
                [formControl]="myForm.controls['accountFromId']">
            <option *ngFor="let acc of this.accounts" value="{{acc.id}}">{{acc.name}}</option>
        </select>

Transfer entity binds correctly for most fields, but 'accountFromId' select element is left with empty value selected (options are there, but not selected properly). How should I rewire my component to ensure accountFromId is being bound after getting account values from service and adding them to select?


Solution

  • It turns out I was looking for Promise.all(). I had to wait for both transfer and account[] entities from services and then bind to form. Updated and working code below:

    export class TransferComponent {
    id: number;
    accounts: Account[] = [];
    myForm: FormGroup;
    submitted: boolean = false;
    saved: boolean = false;
    
    constructor(
        private http: Http,
        private fb: FormBuilder,
        private route: ActivatedRoute,
        private transferService: TransferService,
        private accountService: AccountService,
        private router: Router) {
        this.myForm = fb.group({
            'id': [null],
            'accountFromId': [null, Validators.required],
            'accountToId': [null, Validators.required],
            'title': [null, Validators.required],
            'amount': [null, Validators.required],
            'transferDate': [null, Validators.required]
        });
    }
    
    ngOnInit(): void {
        var accountPromise:Promise<Account[]> = this.accountService.getAccountList()
            .then(accounts => this.accounts = accounts);
        this.route.queryParams.subscribe(params => {
            this.id = params['id'];
            if (this.id) {
                var transferPromise: Promise<Transfer> = this.transferService.getTransfer(this.id);
                Promise.all([
                    accountPromise,
                    transferPromise
                ]).then(value => {
                    this.myForm.setValue(value[1]);
                })
            }
        })
    }