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;
}
2
  • Why the dollar sign in your variable names? Typically, that is used to indicate it is an observable? Also, you'll get much better help if you include an minimal reproducible example. 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. Commented Nov 29, 2018 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. Commented Nov 29, 2018 at 18:26

1 Answer 1

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)

Sign up to request clarification or add additional context in comments.

2 Comments

Sorry, the error is on line <th>{{getAccountById(item.AccoundId).name}}</th> 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
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.