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);
}
}

*** edited

I think you're missing the use of the ngValue directive here to have the object
reflected in the value bound to ngModel.
<label>Target Account</label>
<select [(ngModel)]="transaction.targetAccount" >
<option *ngFor="let a of accounts" [ngValue]="a">{{a.name}}</option>
</select>
From the documentation .. If your option values happen to be objects (and you'd like to save the selection in your form as an object), use ngValue instead.
See here for the full docs for the select element.
Note I'm not sure why it seems to be working on the sourceAccount property.
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;
}
);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With