119

I'm using template like following:

<ul [ngClass]="{dispN: !shwFilter,'list-group':true,'autoS':true,'dispB':shwFilter,'myshddw':true}" style=";display: none">
  <li *ngIf="itsNotF && itsNotF.length" [ngClass]="{bgDFF: !colps[j],'list-group-item':true}" *ngFor="let valm1 of itsNotF;let j=index;" (click)="togFltr(j)" style="padding: 0;background: #fff">
    <div *ngIf="valm1 && valm1.type=='1'">
      <h5 style="padding:8px;margin: 0;">{{valm1['header']}}</h5>
      <p style="margin: 8px;">{{valm1['body']}}</p>
      <h6 style="padding:8px;margin: 0;">{{valm1['note']}}</h6>
    </div>
    <div *ngIf="valm1 && valm1.type=='2'" (click)="modlTxt=valm1;notREadVu(j)" data-toggle="modal" data-target="#myModal">
      <h5 style="padding:8px;margin: 0;">{{valm1['header']}}</h5>
      <h6 style="padding:8px;margin: 0;">{{valm1['note']}}</h6>
    </div>
    <div *ngIf="valm1 && valm1.type=='3'">
      <h5 style="padding:8px;margin: 0;">{{valm1['header']}}</h5>
      <p style="margin: 8px;">{{valm1['body']}}</p>
      <h6 style="padding:8px;margin: 0;">{{valm1['note']}}</h6>
    </div>
  </li>
  <li [ngClass]="{bgDFF: !colps[j],'list-group-item':true,'lgOt':true}" (click)="logout()">
    <span class="title">Log Out <i class="fa fa-sign-out"></i></span>
  </li>
</ul>

So it gives following error:

EXCEPTION: Template parse errors:
Can't have multiple template bindings on one element. Use only one attribute named 'template' or prefixed with * ("one">
  <li *ngIf="itsNotF && itsNotF.length" [ngClass]="{bgDFF: !colps[j],'list-group-item':true}" [ERROR ->]*ngFor="let valm1 of itsNotF;let j=index;" (click)="togFltr(j)" style="padding: 0;background: #fff">
"): App@78:94

Previously it was not giving error I faced this issue after upgrading to RC4.

So what's workaround, so I can apply multiple template binding on single element without altering Template structure.

Mohammed Safeer
  • 20,751
  • 8
  • 75
  • 78
Akhilesh Kumar
  • 9,085
  • 13
  • 57
  • 95
  • 1
    `ngIf` & `ngFor` both are structural directives, they can't be there on same element.. For workaroud you could check this [github issue coment](https://github.com/angular/angular/issues/7315#issuecomment-232083676) – Pankaj Parkar Jul 26 '16 at 09:16
  • But previously(RC1) it was working. – Akhilesh Kumar Jul 26 '16 at 09:17

4 Answers4

230

Can't use two template binding on one element in Angular 2 (like *ngIf and *ngFor). But you can achieve the same by wrapping the element with a span or any other element. It is good to append with an <ng-container> as it is a logical container and it will not get append to the DOM. For example,

<ng-container *ngIf="condition">
    <li *ngFor="let item of items">
        {{item}}
    </li>
</ng-container>
Mohammed Safeer
  • 20,751
  • 8
  • 75
  • 78
15

You can use the following (expanded version) to preserve the document structure (e.g. for your css selectors):

<template [ngIf]="itsNotF && itsNotF.length">
    <div [ngClass]="{bgDFF: !colps[j],'list-group-item':true}" *ngFor="let valm1 of itsNotF;let j=index;" (click)="togFltr(j)" style="padding: 0;background: #fff">
    </div>
</template>
typesafe
  • 176
  • 3
4

Put your *ngIf in a parent div, and the *ngFor can stay where it is.

For example:

<div *ngIf="itsNotF && itsNotF.length">
    <div [ngClass]="{bgDFF: !colps[j],'list-group-item':true}" *ngFor="let valm1 of itsNotF;let j=index;" (click)="togFltr(j)" style="padding: 0;background: #fff">
    </div>
</div>
Andy-Delosdos
  • 3,560
  • 1
  • 12
  • 25
  • But for this I have to alter the template structure and CSS (Corresponding selector). Isn't there any Other workaround without altering Template structure. – Akhilesh Kumar Jul 26 '16 at 09:20
  • Isn't there any solution similar to http://stackoverflow.com/questions/10700020/how-to-have-multiple-data-bind-attributes-on-one-element – Akhilesh Kumar Jul 26 '16 at 09:26
  • 1
    That is true. You could define the parent as a span if it helps your CSS. Or even make a custom element: `
    ` for example
    – Andy-Delosdos Jul 26 '16 at 09:27
  • Although it's a bit rubbish, one option would be to make the div element invisible using `display:none` and then use `*ngFor`. However, that wouldn't remove the element from the DOM like `*ngIf` does, so it's not very nice – Andy-Delosdos Jul 26 '16 at 09:30
  • Now I updated My scenario Now you can understand why I cant use your solution Because line logout will always be visible and altering ul>li selector is not possible(Lots of changes requires in css). – Akhilesh Kumar Jul 26 '16 at 09:48
  • So only solution I'm getting is I have to replicate ul with *ngIf condition – Akhilesh Kumar Jul 26 '16 at 09:48
  • Nah... But thx anyway ;) – Cody Feb 01 '17 at 20:33
2

If you are using *ngFor and want to add *ngIf to check some field, if conditional is not too complicated, I use filter for that, where I run my conditional and return only items that enter in my condition inside that loop.. Hope it helps

something like that where I want to show only items with description:

<div class="delivery-disclaimer" *ngFor="let payment of cart.restaurant.payment_method | filter:[{short_name: cart.payment_method}] | onlyDescription" text-wrap>
        <ion-icon item-left name="information-circle"></ion-icon> {{payment.pivot.description}}
    </div>

davor

Davor
  • 400
  • 5
  • 12