Shan-Desai
Shan-Desai

Reputation: 3349

use single ngFor loop to display two distinct optgroup in select tag for angular 4

I have a dummy Array of Objects as follows:

this.historyOfWords = [
      {
        'property': 'property1',
        'type': 'dataprop',
        'value': 'value1'

      },
      {
        'property': 'Ref1',
        'type': 'objprop',
        'value': 'Prop of Ref1'
      }
    ];

I am looking to sort the above mentioned information into <optgroup> for the <select> tag

My current implementation is as follows:

<select size="10">
      <optgroup label="Properties"> <!-- all type of data that is not `objprop`-->
        <option *ngFor="let eachVal of historyOfWords">
          <div *ngIf="eachVal.type!='objprop'"> <!-- test type here -->
          {{eachVal.property}}</div>
        </option>
      </optgroup>
      <optgroup label="References to Properties">
        <option *ngFor="let eachVal of historyOfWords"> <!-- need to run the  loop again-->
          <div *ngIf="eachVal.type==='objprop'">{{eachVal.property}}</div>
        </option>
      </optgroup>
    </select>

I tried the logic if else logic in angular similarly

<select size="10">
      <optgroup label="Properties"> <!-- all type of data that is not `objprop`-->
        <option *ngFor="let eachVal of historyOfWords">
          <div *ngIf="eachVal.type=='dataprop'; else ref;"> <!-- test type here -->
          {{eachVal.property}}</div>
        </option>
      </optgroup>
      <optgroup label="References to Properties">
        <ng-template #ref> <-- ELSE show this -->
        <option *ngFor="let eachVal of historyOfWords"> <!-- need to run the  loop again-->
          <div>{{eachVal.property}}</div> <!-- need to put some logic here again -->
        </option>
      </optgroup>
    </select>

The problem is eachVal is outside the scope of the first optgroup and hence not available so I need to loop over again.

What is an optimal way to display two distinct values under optgroup without looping more times.

Upvotes: 3

Views: 2074

Answers (2)

Royer Adames
Royer Adames

Reputation: 1076

interface optgroup {
  label: string,
  options: {value: string, name:string}[]
}

      <optgroup
        *ngFor="let group of optgroup"
        [label]="group.label"
      >
        {{ group.label }}
        <option
          *ngFor="let option of group.options; index as i"
          class="title"
[value]="option.value"
        >
          {{ i + 1 }}. {{ option.name }}
        </option>
      </optgroup>

Upvotes: 0

Tomasz Kula
Tomasz Kula

Reputation: 16837

Filter the data ahead of time. It's always a good idea to keep as much of the logic as possible in the component class, and not in the template.

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
  <select>
      <optgroup label="Properties"> 
        <option *ngFor="let eachVal of notObjProp">
          <div> {{eachVal.property}}</div>
        </option>
      </optgroup>
      <optgroup label="References to Properties">
        <option *ngFor="let eachVal of objProp"> 
          <div>{{eachVal.property}}</div>
        </option>
      </optgroup>
    </select>
  `,
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  data = [
    {
      'property': 'property1',
      'type': 'dataprop',
      'value': 'value1'

    },
    {
      'property': 'Ref1',
      'type': 'objprop',
      'value': 'Prop of Ref1'
    }
  ];

  objProp = this.data.filter(({ type }) => type === 'objprop');
  notObjProp = this.data.filter(({ type }) => type !== 'objprop');
}

Live demo

Upvotes: 2

Related Questions