select ngmodel not binding the variable

Issue

I have a very simple page with two selects filled in with same data (bank accounts). One is aimed to be source and another target in order to create a transaction. In this simple scenario a transaction is just an amount transfered from one account to another.

I am facing a problem while sending the transaction to my rest service. From the image bellow is easy to see that the transaction variable isn’t properly filled but I don’t know what is going wrong.

I see the first account (source) from transaction partially filled and the second (target) with [object Object]. Why wasn’t filled the same since they are exactly same type of object and why in the first one name wasn’t filled?

new-transaction.html:

<div>
  <div>
  <label>Source Account</label>
  <select [(ngModel)]="transaction.sourceAccount"> 

      <option *ngFor="let a of accounts" [value]="a" >{{a.name}}</option>
  </select>
</div>
<div>
  <label>Target Account</label>
  <select  [(ngModel)]="transaction.targetAccount" > 
      <option *ngFor="let a of accounts" [value]="a">{{a.name}}</option>
  </select>
</div>
<div>
  <input type="text" [(ngModel)]="transaction.amount">
</div>
<div>
    <button (click)="addTransaction()">Add</button>
 </div>
</div>

new-transaction.component.ts

...
export class NewTransactionComponent implements OnInit {

  accounts: Account[];
  transaction: Transaction = new Transaction();

  constructor(private accountService: AccountService, private transactionService: TransactionService) { }

  ngOnInit(): void {
    this.transaction.targetAccount = new Account();
    this.transaction.sourceAccount = new Account();

    this.accountService
    .getAllAccounts()
    .subscribe(
      (accounts) => {
        this.accounts = accounts;
      }
    );
  }

  addTransaction(): void {
    this.transactionService.addTransaction(this.transaction)    
    .subscribe(
      (transaction) => {
        this.transaction = transaction;
      }
    );
    //this.router.navigate(['/home']);
  } 
}

transaction.service.ts

  public addTransaction(transaction: Transaction): Observable<Transaction> {
    return this.http
      .post(API_URL + '/transaction', transaction)
      .map(response => {
        return new Transaction(response.json());
      })
      .catch(this.handleError);
  }

transaction.ts

import { Account } from "./account";

export class Transaction {
    idtransaction: number;
    amount: number;
    sourceAccount: Account;
    targetAccount: Account;

    constructor(values: Object = {}) {
      Object.assign(this, values);
    }
}

account.ts

import { User } from "./user";

export class Account {
    id: number;
    name: string = '';
    user: User[] = [];

    constructor(values: Object = {}) {
      Object.assign(this, values);
    }
}

enter image description here

*** edited

enter image description here

Solution

I got this working with the following code. I like what Garth posted, and it would be less code, too. I had this ready just minutes after seeing his answer, so I am going to post it since I spent some time on it.

new-transaction.component.html

<div>
  <div>
  <label>Source Account</label>
  <select [(ngModel)]="sourceBankAccount" name="sourceBankAccount" (change)="sourceAccountChanged($event.target.value)" >

      <option *ngFor="let a of accounts" [value]="a.id" >{{a.name}}</option>
  </select>
</div>
<div>
  <label>Target Account</label>
  <select  [(ngModel)]="targetBankAccount"  name="targetBankAccount" (change)="targetAccountChanged($event.target.value)" >
      <option *ngFor="let a of accounts" [value]="a.id">{{a.name}}</option>
  </select>
</div>
<div>
  <input type="text" [(ngModel)]="transaction.amount">
</div>
<div>
    <button (click)="addTransaction()">Add</button>
 </div>
</div>

Notice that this uses the account id for the value in the drop down. There are change event calls here, too.

new-transaction.component.ts

export class NewTransactionComponent implements OnInit {

  accounts: BankAccount[];
  transaction: Transaction = new Transaction();
  sourceBankAccount: number;
  targetBankAccount: number;

  constructor(private accountService: BankAccountService, private transactionService: TransactionService) { }

  ngOnInit(): void {
    this.accountService
    .getAllAccounts()
    .subscribe(
      (accounts) => {
        this.accounts = accounts;
      }
    );
  }

  sourceAccountChanged(account: number) {
    const newAccount: BankAccount = this.accounts.find(acct => acct.id === +account);
    if (newAccount) {
      this.transaction.sourceAccount = new BankAccount(newAccount);
    }
  }

  targetAccountChanged(account: number) {
    const newAccount: BankAccount = this.accounts.find(acct => acct.id === +account);
    if (newAccount) {
      this.transaction.targetAccount = new BankAccount(newAccount);
    }
  }

  addTransaction(): void {
    console.log(this.transaction);
    this.transactionService.addTransaction(this.transaction)
    .subscribe(
      (transaction) => {
        this.transaction = transaction;
      }
    );
  }
}

Answered By – R. Richards

Answer Checked By – Dawn Plyler (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.