2

I am trying to display a single object from an array based on a property value.

My list of transactionitems has an accountId property, but I would like to display the account name instead. All accounts are loaded in the accounts$ array. I just can't figure out how to properly use my getAccountById function

Here is the component class

export class NewtransactionComponent implements OnInit {
  transaction$: Transaction;
  tempItem$: TransactionItem;
  accounts$: Array<Account>;

  constructor(private data: DataService) { }

  ngOnInit() {
    this.transaction$ = new Transaction();
    this.data.getAccounts().subscribe(data => this.accounts$ = Object.assign(new Array<Account>(), data));
    this.tempItem$ = new TransactionItem();
    this.transaction$.TransactionDate = new Date();
  }

  addItem(){
    this.transaction$.TransactionItems.push(this.tempItem$);
    this.tempItem$ = new TransactionItem();
  }

  getAccountById(id):Account{
    return this.accounts$.find(x => x.id === id);
  };

and here is the html view that gives the error "Cannot read property 'name' of undefined"

     <div class="items-container">
        <mat-form-field>
          <input matInput placeholder="Amount" [(ngModel)]="tempItem$.Amount">
        </mat-form-field>
        <mat-form-field *ngIf="accounts$">
          <mat-select placeholder="Account" [(ngModel)]="tempItem$.AccountId">
            <mat-option *ngFor="let account of accounts$" [value]="account.id">{{account.name}}</mat-option>
          </mat-select>
        </mat-form-field>
        <mat-form-field>
          <mat-select placeholder="Credit/Debit" [(ngModel)]="tempItem$.CreditDebit">
            <mat-option value="Credit">Credit</mat-option>
            <mat-option value="Debit">Debit</mat-option>
          </mat-select>
        </mat-form-field>
        <button mat-mini-fab color="primary" (click)="addItem()">Add</button>
      </div>
      <table *ngIf="transaction$.TransactionItems.length">
        <tr>
          <th>Amount</th>
          <th>Account</th>
          <th>Credit/Debit</th>
        </tr>
        <tr *ngFor="let item of transaction$.TransactionItems">
          <th>{{item.Amount | currency}}</th>
          <th>{{getAccountById(item.AccoundId).name}}</th>
          <th>{{item.CreditDebit}}</th>
        </tr>
      </table>

these are the account and transactionitem data models for reference

export class Account {
    Id: string;
    Name: string;
    Category: string;
    SubCategory: string;
}

export class TransactionItem{
    Id: number;
    TransactionId:number;
    Accountid: string;
    Amount: number;
    CreditDebit: string;
}
Dhana
  • 1,618
  • 4
  • 23
  • 39
Villhellm
  • 69
  • 3
  • 12
  • Why the dollar sign in your variable names? Typically, that is used to [indicate it is an observable](https://stackoverflow.com/questions/37671700/angular2-style-guide-property-with-dollar-sign)? Also, you'll get much better help if you include an [mcve]. Lastly, very difficult to answer without some sample data. We will only be guessing, on the assumption that your types properly match your data structure. – random_user_name Nov 29 '18 at 17:34
  • I'm new to angular, I thought the $ was for global variables or something. Thank you for letting me know, I fixed my variable names now. And I will work on making a better example next time. I just thought I was missing something basic in syntax. – Villhellm Nov 29 '18 at 18:26

1 Answers1

5

I assume that the error is here: {{account.name}}?

This is most likely a timing issue. The page will attempt to display before the data is retrieved from the subscription.

One way to resolve the issue is to use an *ngIf

 <div class="items-container" *ngIf="account">

That way the page won't try to display until the data is retrieved.

Another option is to use the safe navigation operator:

{{account?.name}}

The question mark tells Angular not to attempt to read the name property if the account is null or undefined.

EDIT:

If there error is here: {{getAccountById(item.AccountId).name}}, then it is telling you that getAccountById(item.AccountId) is undefined or null. Is it possible that one of your transactions has no account?

And looking at your code more closely, JavaScript/TypeScript is case sensitive. So if you declare the id using:

Id: string;

(Upper case I)

You can't then access it using:

return this.accounts$.find(x => x.id === id);

(Lower case)

DeborahK
  • 57,520
  • 12
  • 104
  • 129
  • Sorry, the error is on line {{getAccountById(item.AccoundId).name}} the first loop through the accounts array works fine. And that was a typo, it is supposed to say "AccountId", but even without the typo I get the same error – Villhellm Nov 29 '18 at 17:44
  • And that was it. Thank you so much! Apparently my rest service changes the first letter of all fields to lower case. Until I started learning angular I was using a deserializer so I never saw the raw json that was returned. – Villhellm Nov 29 '18 at 18:23