3

My app UI is based on PrimeNG and i am working on dynamic forms and also getting form fields configuration through API. My PrimeNG dropdown is showing empty options. Here is the image for the reference: Behaviour of PrimeNG dropdown

Here is the code for PrimeNG dropdown:

 <p-dropdown *ngIf="field.IsLookup == 'Y'" [options]="field.LookupVal.split('|')" 
        [id]="field?.ColumnName"
        [formControlName]="field?.ColumnName"
      [showClear]="true">
</p-dropdown>

With Bootstrap select it is working fine but i want to achieve this through PrimeNG, here is the code for Bootstrap select:

 <select
      *ngIf="field.IsLookup == 'Y'"
        class="form-control"
        [id]="field?.ColumnName"
        [formControlName]="field?.ColumnName"
      >
        <option *ngFor="let opt of field.LookupVal.split('|')" [value]="opt">{{
          opt
        }}</option>
 </select>

Here is the data for dropdown i am getting from API: LookupVal: "KK-ID-IDEAS - KARACHI|00001-Karachi|KHI-KARACHI NEW |14121-BDJJSJBSJ"

Kindly help me find a way out?

  • Try adding your dropdown values in label and values. visit this [link](https://stackoverflow.com/a/49378464/7541317). – Farhat Zaman Jul 15 '20 at 14:18

2 Answers2

2

The reason these dropdowns are blank is because PrimeNg required a model for all dropdowns. In your component, the model looks like this, for example:

this.dropdownContent = [
  { label: 'label1', value: 'content1' },
  { label: 'label2', value: 'content2' },
  ...
];

Because this is the case, more than likely your [options]="field.LookupVal.split('|')" does not satisfy the model requirements for the dropdown component.

First, I would check inside your component if you can manually use the data and put it inside the model so that every value has a label and value. If this doesn't work, then there are 2 other ways I would recommend solving this.

1 Map (easiest way)

By mapping the model inside your component.

When the data comes in from the api, you should map it to make the dropdown. Something like this, based on the data from the dropdown sample you gave. Note, this would be either in your subscription, observable, ngOnInit, or somewhere else. just wherever you are getting and working with the data...:

this.options = this.apiData.LookupVal.split('|')".map((o) => ({
  label: o,
  value: o,
}));

Now, in your html, change your options to [options]="options", or whatever you named this inside your component. What is going on here, is you are mapping, or changing the data to fit the model requirements. So if the field.LookupVal.split('|') or whatever your component's data is had a value of foo, it would now have a value of { label: 'foo', value: 'foo' }.

2 Pipe (more complex, only if necessary or you're doing this a lot of times)

If this does not work, or you can't get it to, the next option would be to create a pipe. You would want the pipe to convert each item inside the array to have a label and value, just like you did with the map. Something like this (it may need to be changed to your specific case):

import { Pipe, PipeTransform } from '@angular/core';
import { SelectItem } from 'primeng/api';

@Pipe({ name: 'dropdownPipe' })
export class DropdownPipe implements PipeTransform {
  @param array
  @param labelKey

transform(array: any[], labelKey: string | string[]): SelectItem[] {
  if(!labelKey || !array) {
    return undefined;
  }
  
  let pipeArray;
  
  if (labelKey instanceof Array) {
    for (let o = 2; o < labelKey.length; o++) {
      pipeArray = array.map((val, i) => ({
        label: pipeArray[i].label + val[labelKey[o]],
        value: val
     }));
  }
  return pipeArray;
}      

Then, in your html, you can add the following (make sure the pipe is in your app or component module)

<p-dropdown 
  *ngIf="field.IsLookup == 'Y'" 
  [options]="field.LookupVal.split('|') | dropdownPipe" 
  [id]="field?.ColumnName"
  [formControlName]="field?.ColumnName"
  [showClear]="true">
</p-dropdown>
Jeremy
  • 598
  • 4
  • 17
  • Thanks for your answer actually where i am consuming the api is my parent component and in which i am using dropdown is my great grand child component. As i have told i am working on dynamic field builder. To get better understanding of hierarchy of components refer this link: https://stackblitz.com/edit/angular-dynamic-form-builder?file=app%2Fdynamic-form-builder%2Fdynamic-form-builder.component.ts – Usama Tariq Jul 16 '20 at 09:18
  • I am getting field from it's parent component using @Input decorator. But it showing as empty i.e {} when i am logging it on console in ngOnInit() lifecycle hook. So, that is why i am directly using splitter in my template as i can't work out things in typescript. – Usama Tariq Jul 16 '20 at 09:20
  • Thanks @JeremyLucas for the map function :) it was brilliant! – Usama Tariq Jul 16 '20 at 11:52
  • Apologies for not seeing the rest of the questions. I'm glad you got it worked out! Best of luck ongoing for your projects :) – Jeremy Jul 17 '20 at 03:57
  • So kind of you :) – Usama Tariq Jul 17 '20 at 06:10
2

you can just use it in the constructor like this, as stated by @JeremyLucas. Just use settimeout and if condition for it

 setTimeout(() => {
                 if(this.field.IsLookup == 'Y'){

        this.array = this.field.LookupVal.split('|').map((o) => ({
          label: o,
          value: o,
        }))
        console.log(this.array, "array");
        
        }
      
    
    }, 1000);