Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2: Binding to Functions from Component Templates

In Angular 1 we avoided calling functions from within template expressions in excess, e.g. ng-repeat="item in vm.getFilteredItems()" because property changes unrelated to the result of getFilteredItems would cause the function to recompute repeatedly and unnecessarily on digests, which commonly causes performance problems at scale. Instead we bound to objects, and compute based on events (e.g. ng-repeat="item in vm.filteredItems).

In Angular 2, the dirty checking process has been optimized but functions called in component templates will still be called when any properties at the component level change, regardless of whether the function is dependent on those properties. I expect this could lead to the same performance issues if used improperly.

Here is a simplified example of the differing approaches in Angular 2:

// function binding in template
@Component({
  selector: 'func',
  template: `
    <input [(ngModel)]="searchTerm" placeholder="searchTerm" />
    <div *ngFor="let name of filteredNames(searchTerm)">{{name}}</div>
  `
})
export class FuncComponent {
  @Input() names:string[];

  filteredNames(searchTerm) {

    if (!searchTerm) return this.names;

    let filteredNames = [];

    return this.names.filter((name) => {
      return name.toLowerCase().indexOf(searchTerm.toLowerCase()) > -1;
    });
  }
}

-

// no function binding
@Component({
  selector: 'nofunc',
  template: `
    <input [(ngModel)]="searchTerm" (ngModelChange)="search($event)" placeholder="searchTerm" />
    <div *ngFor="let name of filteredNames">{{name}}</div>
  `
})
export class NoFuncComponent implements OnInit {
  @Input() names:string[];

  searchTerm: string;

  ngOnInit() {
    this.search(this.searchTerm);
  }

  search() {
    if (!this.searchTerm) {
      this.filteredNames = this.names;
      return;
    }

    this.filteredNames = this.names.filter((name) => {
      return name.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1;
    });
  }
}

http://plnkr.co/edit/AAFknlJgso3D8F1w3QC1?p=preview

Is this still a concern in Angular 2? Which approach is preferred, and why? Thanks!

like image 422
Skyler Avatar asked Jun 07 '16 19:06

Skyler


People also ask

Which data binding can pass data from a template to a component?

There are two ways to pass data into a component, with 'property binding' and 'event binding'.

Does Angular support 2 way binding?

Two-way data binding in Angular will help users to exchange data from the component to view and from view to the component. It will help users to establish communication bi-directionally. Two-way data binding can be achieved using a ngModel directive in Angular.

Can Angular component have multiple templates?

You can simply extend your base component and overwrite the template. This allows you to have different components with the exact same functionality, but different templates. Save this answer.

Which property is used to bind an external template with the component in Angular?

Property binding is the primary way of binding data in Angular.


1 Answers

You could create a pipe. Pipes (if pure) are only called when depending values change.

@Pipe({
  name: 'search',
//  pure: 'false'
})
class SearchPipe {
  transform(names, searchTerm) {
   if (!this.searchTerm) {
      this.filteredNames = names;
      return;
    }

    return names.filter((name) => {
      return name.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1;
    });
  }
}

@Component({
  selector: 'func',
  pipes: [SearchPipe],
  template: `
    <input [(ngModel)]="searchTerm" placeholder="searchTerm" />
    <div *ngFor="let name of names | search:searchTerm">{{name}}</div>
  `
})
export class FuncComponent {
  @Input() names:string[];
}

If the pipe needs to recognize changes in names then pure needs to be disabled.

If names is replaced by a different instance instead of just members being added or removed, then pure works fine and the pipe is only executed when names or searchTerm changes.

Hint

In devMode (default) change detection runs twice and the pipe will be called twice as much as expected.

like image 79
Günter Zöchbauer Avatar answered Oct 14 '22 04:10

Günter Zöchbauer