0

I need to create grouped dropdown select using Angular. In my case group is make.

const cars = [{
        make: "audi",
        model: "r8",
        year: "2012"
    },
    {
        make: "audi",
        model: "rs5",
        year: "2013"
    },
    {
        make: "ford",
        model: "mustang",
        year: "2012"
    },
    {
        make: "ford",
        model: "fusion",
        year: "2015"
    },
    {
        make: "kia",
        model: "optima",
        year: "2012"
    }
];

So the output would be dropdown select with options:

audi
- r8
- rs5
ford
- mustang
- fusion
kia
- optima

And I wondering whether should I transform this object before? For example similar to this solution: https://medium.com/@edisondevadoss/javascript-group-an-array-of-objects-by-key-afc85c35d07e

Or maybe there is another better way. I found this https://stackblitz.com/edit/angular-optgroup. But the structure of object is kinda different.

DiPix
  • 4,140
  • 9
  • 47
  • 83

1 Answers1

0

Yeah so you should transform the object before, similar to the medium article's answer (on make's basis).

Even in the stackblitz example you can see the main name is something on which it has to be grouped.

So your ngFor will show a group1 and then its opt-groups and then group2 and its children so on. So transforming is the way in my opinion as well.

UPDATED

So from your stackblitz example(the one you shared above) it will go something like this

enter image description here

  <select name="cars" id="cars">
    <optgroup *ngFor="let item of optGroups" label="{{item.name}}" >
       <option *ngFor="let sub of item.data" value="{{sub.value}}"> 
         {{sub.text}} 
       </option>
    </optgroup>
  </select>

one ngFor on optgroup and another on option

And you can get the transformed response from this snippet

 let group = this.cars.reduce((r, a) => {
  console.log("a", a);
  console.log('r', r);
  r[a.make] = [...r[a.make] || [], a];
  return r;
 }, []);

You will get the desired transformed response, which will be Array of makes and each make will have number of items inside

Look at this image below, I have already tried it. Then you can use ngFor the way I have mentioned above

enter image description here

Wahab Shah
  • 1,315
  • 1
  • 9
  • 12
  • Can you give some example how you see this? – DiPix Jun 24 '20 at 07:10
  • you mean the ngFor example or what? – Wahab Shah Jun 24 '20 at 07:13
  • How it can be transformed to be working with grouped ngFor. – DiPix Jun 24 '20 at 07:19
  • Okay let me see. Do you have some stackblitz setup or something already which I can see? – Wahab Shah Jun 24 '20 at 08:01
  • Maybe you can modify that stackblitz that I sent in main post? – DiPix Jun 24 '20 at 08:29
  • That HTML code won't work, since you iterate over the object's array. So you shouldn't call `item.name` i'll try to improve that code. – DiPix Jun 24 '20 at 09:23
  • It is already working!. The first screenshot that I have sent I did it on stackblitz already. The example there with animals names and types on stackblitz its from that. 'name' is the category like 4-legged, flying-pets.Obviously you will do it according to your requirements in cars example. I already have given you the transformed part. You will do it like in initial ngFor "item of group" and then for nested loop item.model, item.year etc. – Wahab Shah Jun 24 '20 at 09:34
  • To make it work I had to use keyvalue pipe. `` – DiPix Jun 24 '20 at 09:41
  • One more question, can you tell me how can I change sorting to desc? So it would be `[kia, ford, audi]` – DiPix Jun 24 '20 at 09:43
  • yeah that works too, but it worked even without that. Anyways as long as your problem is resolved that matters :) – Wahab Shah Jun 24 '20 at 09:44
  • So there is a sort() method which sorts an array in ascending then you can call reverse() on that sorted array you will get descending order so `arr.sort().reverse`. Though the simplest way is in your ngFor on optGroup array call .slice().reverse() `optGroup.slice().reverse()` – Wahab Shah Jun 24 '20 at 10:18
  • Hm `.reverse()` not working and `.slice().reverse()` cleaning up the array – DiPix Jun 24 '20 at 10:34
  • worked for me both of them. So then on your main array chain the methods `.sort().reverse()`. If you have updated stackblitz, share it I will check. – Wahab Shah Jun 24 '20 at 13:33
  • Check this. https://www.w3schools.com/code/tryit.asp?filename=GG4PXCHZ4VUD It's because my key is name. That's why reverse doesn't work. Dunno how to fix it. – DiPix Jun 24 '20 at 13:52
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/216565/discussion-between-wahab-shah-and-dipix). – Wahab Shah Jun 24 '20 at 13:59
  • Ok problem is because of reduce that sorting alphabetically. I've created new post check here: https://stackoverflow.com/questions/62559508/how-to-force-reduce-to-not-sorting-alphabetically-in-javascript – DiPix Jun 24 '20 at 16:13
  • sure I will check – Wahab Shah Jun 24 '20 at 16:25