Alternative to functions inside Angular Template

angular 6 call function from html
angular 8 call function from html
angular call function from template
angular pipe
ng-template pass function
angular template bind to function
call function in interpolation angular 6
angular call function from html

I have a very common instance of an issue all over my app. I'll give a simple example.

component code:

const items = [1, 2, 3, 4, 5];
let selectedItems = [2, 4];

public isSelected(item: number): boolean {
    return this.items.find(x => x === item) != null;
}

template:

<div *ngFor="let item of items">
    <span class="check-mark" *ngIf="isSelected(item)"></span>
    {{ item }}
</div>

I'm well aware that this is bad practice:

*ngIf="isSelected(item)"

I am also aware that two solutions to this issue is 1. Use pipes 2. Store values in local variables

I do not have the option of doing either because my "items" and "selectedItems" are populated via data calls and I have varying object types as well. They are not static arrays.

It would be nice if Angular had an "ngIfChange" directive that only executed if a specified object changes. Something along the lines of this:

*ngIf="isSelected(item); change selectedItems"

Does anyone know of a clean, simple way of handling arrays/lists/objects like this without the "functions in templates" issue?

Thanks

To eliminate calling a function in your template, I would recommend creating a structure as follows:

items = [
  { value: 1, selected: false },
  { value: 2, selected: false },
  { value: 3, selected: false }, 
  // ...
];
<div *ngFor="let item of items">
    <span class="check-mark" *ngIf="item.selected"></span>
    {{ item.value }}
</div>

Don't Use Functions Inside Angular Templates and What to Use , Use a pure pipe instead of a function in Angular templates. This only works with primitive input types. If the input is an object, make sure you are providing a new object reference. This template was built using Angular and includes examples of many of the features the Angular framework provides. Angular CLI The Angular Command Line Interface (CLI) is a powerful tool to initialize, develop, scaffold and maintain Angular applications.

Having selectedItems as Dictionary solves the problem

public items = [1, 2, 3, 4, 5];
public selectedItems = {
  2: true,
  3: true,
};

// example toggle selection function
toggleSelection(item) {
  this.selectedItems[item] = !this.selectedItems[item];
}

// example on submit logic
onSubmit() {
  const selectedItemsToSend = Object.entries(selectedItems)
                                    .filter(([item, selected]) => selected)
                                    .map(([item, selected]) => item);
  // rest of ur logic
}

template:

<div *ngFor="let item of items"> <span class="check-mark" *ngIf="selectedItems[item]"></span> {{ item }} </div>

When not to use methods in templates, What is the big deal if functions are called constantly? I know there are some libraries for internationalization in Angular 2 but my friend https://angular.io/ docs/ts/latest/guide/template-syntax.html Let's check another time the official documentation; where can we find a similar behaviour in Angular 2? Angular Site Template has many features and functionalities that you will love. Explore them one by one to see the beautifully designed and responsive components. Re use them inside your Angular application and take your website to the next level.

I don't think this is a great idea, and you can't do it exactly like you're imagining due to how template expressions are evaluated, but nothing is stopping you from writing a structural directive like:

@Directive({
  selector: '[myIf]'
})
export class MyIfChanged {
  @Input('myIf') conditional

  @Input('myIfParams') params = []

  @Input() set myIfChanged(value) {
    this.viewContainer.clear()
    if (this.conditional && this.conditional(...this.params)) {
      this.viewContainer.createEmbeddedView(this.templateRef)
    }
  }

  constructor(private viewContainer: ViewContainerRef, private templateRef: TemplateRef<any>) {}
}

which could be used like:

@Component({
  selector: 'my-component',
  template: `
    <button (click)="change()">change</button>
    <div *myIf="isSelected; params [1]; changed selected">SHOW</div>
  `
})
export class MyComponent {
  selected = []
  isSelected = (value) => this.selected.indexOf(value) > -1
  change() {
    this.selected = [1]
  }
}

it's weird, but it works. structured the params as an array to allow multiple parameters. you need to define the function passed in as an arrow function and you need to never mutate the variable to be watching. but this would work fine under those hidden dependencies.

sample blitz: https://stackblitz.com/edit/angular-ktq4re?file=src/app/app.component.html

Function calls in Angular expressions are killing your apps , Both Angular and AngularJS allow the use of function calls in template expressions. This seems like a reasonable approach to supply data to� Angular 7 uses the <ng-template> as the tag instead of <template>which is used in Angular2. <ng-template> has been in use since the release of Angular 4 , and the earlier version i.e Angular 2 uses <template> for the same purpose.

I could suggest a better solution if I understand the problem better.

But from what I can see in your current description, a nice and simple way to avoid unnecessary computation is to just memorize it.

There are a lot of similar libraries help you do that, such as memoizee

And your code becomes

public isSelected = memoizee(oldIsSelected);

Another way that probably makes more sense, but needs a better context, is to manually control when to compute this "selected items" list. Have event triggers and listeners (perhaps just rxjs observables), and have your Angular template simply subscribe to this observable using async pipe.

The benefits of using pure pipes in Angular templates, Because of this, it is considered better to substitute function call in the expression with a pure pipe that encapsulates logic. A pure pipe is a� The let attribute is constructed like this: let-templatevar="inputvar" where templatevar is the name that is used to reference the value inside the <ng-template> and inputvar is the name of the

Why you should never use function calls in Angular template , Before we know it, we end up with function calls in our Angular templates: <ng- container *ngIf="isLoggedIn"> <h1>Welcome {{ fullName }}!</h1> This page will walk through Angular 4 <ng-template> example.<ng-template> is an angular element for rendering HTML. It is never displayed directly. It can be displayed using structural directive, ViewContainerRef etc. Suppose we have following code in our HTML template.

Template syntax, For example, Angular helps you get and set DOM (Document Object Model) values dynamically with features such as built-in template functions, variables, event� Learning Angular: What is Angular? Let me introduce you to Angular. Angular is a JavaScript open-source front-end web application framework. It is primarily sustained by Google together with an extended community of people and companies, to approach many of the challenges faced when developing single page, cross platform, performant applications.

AngularJS to Angular concepts: Quick reference, In Angular, a template expression in curly braces still denotes one-way In Angular you use similar syntax with the pipe (|) character to filter output, but now In AngularJS, you write the code for the model and methods in a controller function. Showing an alternative template using elselink. To display a template when expression evaluates to false, use an else template binding as shown in the following example. The else binding points to an <ng-template> element labeled #elseBlock. The template can be defined anywhere in the component view, but is typically placed right after ngIf for

Comments
  • I would recommend: return this.items.indexOf(item) >= 0;. A better alternative, if possible, is to turn each item into an object: items = [{ value: 1, selected: false }, { value: 2, selected: true }, ...] instead of having the selected items in a separate array.
  • My example is just that - an example. Your suggestion has nothing to do with my question.
  • His given alternative IS the way to solve this though..
  • the correct way to handle this is the way others have shown. even if your data is coming from an api, you don't need to stick with just that data structure. you map it into a more friendly view model to work with.
  • Before he edited, he only posted this: I would recommend: return this.items.indexOf(item) >= 0;
  • I have used this method, however, it is slightly inconvenient because and not as passive. For example, in your solution, "items" is the object I would be working on, but "selectedItems" is the object I need to save to the database. So either I have to keep both objects updated at all times OR prepare selectedItems when the user clicks save.
  • Also, I don't delete data from my database, I just set an IsDeleted flag on all of my tables. So the logic behind keeping track of these changes gets to be kind of hairy. But I do understand that this is a "best" solution that I've ever come across. I was just curious if there were any other ways.
  • Definitely do not keep two objects updated, IMO that is just asking for trouble. Keep a single point of truth. It's very simple to only get the selected values on save: const selectedItems = this.items.filter(item => item.selected).map(item => item.value);
  • @SamHerrmann - In your example, make sure to use items = ... instead of items: ..., so that nobody gets bitten by this mistake which is not always easy to detect.
  • Good catch @ConnorsFan! I fixed my answer. Thanks!