1

Error:

Error: Template parse errors: Parser Error: Bindings cannot contain assignments at....

line: <div>Closed: {{blah}}.find()...

HTML:

<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="4px">
  <div>Total: {{(issuesData$ | async)?.length}}</div>
  <div>Closed: {{(issuesData$ | async)?.filter(data => {data.closedOn}).length}}</div>
</div>

I'm curious if it is possible to use find/filter without running into the template parse error when find/filter are called on a collection in the interpolation statement.

EDIT: Angular 2 - Bindings cannot contain assignments - This does not work for me because I'm passing in an Observable to the component. OnInit I assign the @Input data variable to the issuesData$ observable. Using something like {{getCount()}} in the interpolation results in no data. I tried implementing that like this:

ANGULAR:

@Input()
data;

ngOnInit() {
  this.issuesData$ = this.data;
  
}

getCount(){
  this.issuesData$.subscribe(data => {
    return data.length;
  })
}

HTML:

 <div>Total: {{getCount()}}</div>

But there is nothing to subscribe to when the getCount() is called in the interpolation and this doesn't work either {{(getCount() | async}}

Community
  • 1
  • 1
Jacob Barnes
  • 1,480
  • 1
  • 12
  • 29

3 Answers3

1

You should subscribe to your Observable and manually assign the variables you want in there instead, purely to reduce the complexity of your template code.

@Input()
data;

total: number;
closed: number;

ngOnInit() {
  this.issuesData$ = this.data;
  this.issuesData$.subscribe(next => {
    this.total = next.length;
    this.closed = next.filter(x => x.closedOn).length;
  }
}

Then just use the total and closed variables in your template.

Matt
  • 2,063
  • 1
  • 14
  • 35
1

To call find or filter from the async array in the template, define the callback in the component class. For example, you can set the method isClosedOn as the filter callback:

<div>Closed: {{ (issuesData$ | async)?.filter(isClosedOn).length }}</div>

and define it as follows in the component class:

public isClosedOn = data => data.closedOn;

See this stackblitz for a demo.

ConnorsFan
  • 70,558
  • 13
  • 122
  • 146
1
  • In this scenario you should use map and format the response in a way that makes the data easily consumable by the component/template.
  • Also you can't return a value from subscribe, you can assign a value though.
  • find returns one match, filter returns an array. You meant to use filter if you are wanting to see the total number of matches using length
  • If you use shareReplay the observable will be resolved once so it can be called multiple times using either async pipes or subscribe without incurring additional costs if it does something with external resources like making an http request.
  • Finally you should define types / definitions, typescript is (can be) strongly typed and this is a big advantage over javascript (what it supersedes).

Template.html

<div>Total: {{(issuesData$ | async)?.length}}</div>
<div>Closed: {{(issuesData$ | async)?.closedOnLength}}</div>

YourComponent.ts

import { Observable } from 'rxjs';
import { map, shareReplay } from 'rxjs/operators';


@Input()
data: Observable<{closedOn:any}[]>;
issuesData$: Observable<{length: number, closedOnLength: number}>;

ngOnInit() {
  this.issuesData$ = this.data.pipe(map((_) => {
    return {
      length: _.length,
      closedOnLength: _.filter(d => d.closedOn).length
    };
  }), shareReplay());
}

count: number;
readCount() {
  // you can't return data in a subscribe callback, it is asynchronous
  // you can assign a value though
  this.issuesData$.subscribe(_ => this.count = _.length);
}
Igor
  • 60,821
  • 10
  • 100
  • 175
  • I like your and ConnorsFan's answers. I realized my mistake with the subscribe/return pretty quickly and ended up doing the assignment which ultimately turned into a verbose version of Nothematic's answer. – Jacob Barnes Apr 10 '19 at 16:12