4

In php there is possibility to conditionally close html tag. Can we emulate something like that in angular 2?

For example

<p>
    Some lorem
<?php  if(someConditionTrue){ echo "</p>"}; ?>
Cœur
  • 37,241
  • 25
  • 195
  • 267
  • HTML tags are supposed to be closed. Can you please explain why you'd like it not to be closed ? – Ploppy Nov 16 '16 at 15:49
  • I want to close it at some point of the ngFor when some condition is true,something similar to example i provided. Thanks for correcting my post Pierre! – Marko Djordjevic Nov 16 '16 at 15:54
  • Then you should probably put the content of the paragraph in a variable and bind the variable to the 'p' tag. – Ploppy Nov 16 '16 at 15:56
  • So im having simple array with some data and my desired output is
    item1
    item2
    item3
    item4
    item5
    item6
    item7
    item8
    On every four items in array i want to open row display four items and close it. I did it already by transforming array into multidimensional array and than using nested ngFor directive,but i was wondering if something simillar to php is possible .
    – Marko Djordjevic Nov 16 '16 at 16:04
  • 1
    That's not supported in Angular2. – Günter Zöchbauer Nov 16 '16 at 16:22

5 Answers5

3

Even though it works, there is probably a better solution, see the note below.

The script of the component:

private items: string[] = ['test1','test2','test3','test4','test5','test6','test7','test8','test9'];

The HTML:

<div *ngFor="let item of items; let i = index">
    <div class="row" *ngIf="i%4==0">
        <div *ngIf="items[i]">{{items[i]}}</div>
        <div *ngIf="items[i+1]">{{items[i+1]}}</div>
        <div *ngIf="items[i+2]">{{items[i+2]}}</div>
        <div *ngIf="items[i+3]">{{items[i+3]}}</div>
    </div>
</div>

https://plnkr.co/edit/RDZFJFEZtTD0NA5d8YNJ?p=preview

NB: It would probably be better to create an array (rows) of array (items) instead of using the 'template only' solution I posted.

Ploppy
  • 14,810
  • 6
  • 41
  • 58
1

This is a common frustration for developers with PHP experience, not a rejection of Angular or any other framework (such as Ionic). Unfortunately, you CANNOT put *ngIf conditions on closing HTML tags, and when you put the condition on the opening <div>, you will conditionally exclude everything INSIDE of the <div> as well--not just the tag you are targeting.

So, in the end, your code will be fairly redundant but you can solve the problem like this:

<div class="iterable-container">
 <div *ngFor="let item of items; let i = index">
  <div class="iterable-col-1" *ngIf="(i+3) % 3 == 0">
   <p>first column: {{item.name}}</p>
  </div>
  <div class="iterable-col-2" *ngIf="(i+3) % 3 == 1">
   <p>second column: {{item.name}}</p>  
  </div>
  <div class="iterable-col-3" *ngIf="(i+3) % 3 == 2">
   <p>third column: {{item.name}}</p>
  </div>
 </div>
</div>

You'll also need some CSS. Here is some starter:

.iterable-container {
  background-color: #f2f2f2;
}

.iterable-col-1 {
  display: flex;
  height: 175px;
}

.iterable-col-2 {
  display: flex;
  height: 0;
  left: 33%;
  position: relative;
  top: -175px;
}

.iterable-col-3 {
  display: flex;
  height: 0;
  left: 66%;
  position: relative;
  top: -175px;
}

It may also be worthwhile to consider ditching those <div> tags for a good old-fashioned HTML <table>. She may be out-of-vogue but I feel like she was almost built for this.

Ben Hulan
  • 537
  • 2
  • 7
  • My previous example assumes you need _different_ content for each of the columns (represented by "first", "second", "third", but it could be anything). – Ben Hulan Jul 12 '17 at 18:42
1

I had this issue when I tried to display data on 3 columns in a responsive way. The data that I had to display in the 3 columns was boxes with different heights (actually they were mat-expansion-panel). I've tried first to use the flex from Angular, but that was not ok as I had spaces between the boxes (on the bottom and top). I finally discovered a layout that was working fine by using bootstrap from Angular. I had a dynamic number of boxes that had to be displayed in 3 columns. In the end it should looked more or less like this (example for 9 boxes).

<div class="container-fluid">
    <div class="row justify-content-start">
        <div class="col-12 col-lg-4">
            <box1></box1>
            <box1></box1>
            <box1></box1>
        </div>
        <div class="col-12 col-lg-4">
            <box1></box1>
            <box1></box1>
            <box1></box1>
        </div>
        <div class="col-12 col-lg-4">
            <box1></box1>
            <box1></box1>
            <box1></box1>
        </div>
    </div>
</div>

My first idea was to put a ngFor on the <div class="row in order to loop through all the boxes but the issue was ... how do I make the <div class="col-12 col-lg-4 to appear every 3 boxes? I used some help from this post, looking for a solution for an entire day on google and I did not found any solution. Finally I come with the following solution and works fine for any number of boxes.

<div class="container-fluid">
    <div class="row justify-content-start">
        <div class="col-12 col-lg-4">
            <ng-container *ngFor="let cat of categoryProducts; let i = index">
                <box1 *ngIf="i%4 == 0">{{cat.name}}</box1>
            <ng-container
        </div>
        <div class="col-12 col-lg-4">
            <ng-container *ngFor="let cat of categoryProducts; let i = index">
                <box1 *ngIf="i%4 == 1">{{cat.name}}</box1>
            <ng-container
        </div>
        <div class="col-12 col-lg-4">
            <ng-container *ngFor="let cat of categoryProducts; let i = index">
                <box1 *ngIf="i%4 == 2">{{cat.name}}</box1>
            <ng-container
        </div>
    </div>
</div>

The explanation is this. Example: Suppose we have an array of categoryProducts. These will have the following indexes [0, 1, 2, 3, 4, 5, 6, 7, 8]. As you see, the solution will cycle 3 times on the same array (is a little redundant but it's ok). At first loop we will take in consideration only the elements with these indexes: 0, 3, 6. The others will be ignored but will be taken in consideration on the next 2 loops. At second loop we will take in consideration only the elements with these indexes: 1, 4, 7. The others will be ignored. At third loop we will take in consideration only the elements with these indexes: 2, 5, 8. The others will be ignored but already displayed in the other loops. box1 can be every element you need: a div, a mat-expansion-panel, a component, etc. The example had 3 columns but you can use it for any number of columns. In my case I needed 4. This works fine for any number of boxes. All of them will be splitted into 3 columns.

0

Why would you need this? It seems like you're working against the framework instead of embracing it.

There are several ways to do similar things, like ng-if, ng-repeat and ng-show.

A way would be:

<p>
   <span ng-show='condition' ng-repeat='item in collection'>
       {{item.Text}}
   </span>
</p>
simme
  • 1,514
  • 12
  • 23
0

My previous answer assumes you need different content for each of the columns (represented by the text, "first", "second", "third").

Simon Aronsson is correct that this is working against the framework. If you just need rows and columns of consistently-styled content you can simplify as follows:

<div class="iterable-container">
   <div *ngFor="let item of items">
     <div class="iterable-col of-3">
       <p>{{item.name}}</p>
     </div>
  </div>
</div>

I use .of-2 and .of-3 classes to apply similar architecture to 2-col and 3-col views. Some starter Sass:

// assumes you have a color map:
.iterable-container { 
  background-color: color($colors, light); 
}
.iterable-col {
  display: flex;
  position: relative;
  float: left;
  clear: right;
}
// first column
.iterable-col {
  &.of-2:nth-of-type(2n+1){
    width: 50%;
    max-height: 300px; // depending on size of your card
  }
  &.of-3:nth-of-type(3n+1){
    width: 33.33%;
  }
}
// 2nd of 3 columns
.iterable-col.of-3:nth-of-type(3n+2){
  width: 33.33%;
}
// last column
.iterable-col{
  &.of-2:nth-of-type(2n){
    width: 50%;
    max-height: 300px;
  }
  &.of-3:nth-of-type(3n){
    width: 33.33%;
  }
}
Ben Hulan
  • 537
  • 2
  • 7