Как отобразить сгруппированный массив в Angular?

#angular #typescript

#angular #typescript

Вопрос:

У меня есть массив таких объектов

 [
  {"desc":"a", "menu": 1},{"desc":"b", "menu": 2},{"desc":"c", "menu": 1}, 
  {"desc":"d", "menu": 3},{"desc":"e", "menu": 3},{"desc":"f", "menu": 2}, 
  {"desc":"g", "menu": 1},{"desc":"g", "menu": 1},{"desc":"g", "menu": 4}, 
  {"desc":"g", "menu": 4},{"desc":"g", "menu": 4}
]
  

Извлекается из API.

Теперь я бы показал, что объекты с *ngFor помощью a, сгруппировав их по «меню» и добавив к нему метку следующим образом

Меню 1

{все объекты меню 1}

Меню 2

{все объекты меню 2}

Меню 3

{все объекты меню 3}

Я бы сделал что-то подобное в *ngFor

 *ngFor="let object of objects; let menu = 0"
     if menu !== object.menu
           menu === object.menu
       WRITE LABEL
  

Но как я мог бы реализовать это в реальном прецедентном коде?

Ответ №1:

Я думаю, мы должны сгруппировать его перед использованием *ngFor вот решение

  function groupBy(array, fn) {
    return array.reduce(
      (acc, current) => {
        const groupName = typeof fn === 'string' ? current[fn] : fn(current);
        (acc[groupName] = acc[groupName] || []).push(current);
        return acc;
      },
      {}
    );
  }

 function toArray(obj) {
    return Object.keys(obj).map(k => obj[k]);
  }
  
  const data = [
  {"desc":"a", "menu": 1},{"desc":"b", "menu": 2},{"desc":"c", "menu": 1}, 
  {"desc":"d", "menu": 3},{"desc":"e", "menu": 3},{"desc":"f", "menu": 2}, 
  {"desc":"g", "menu": 1},{"desc":"g", "menu": 1},{"desc":"g", "menu": 4}, 
  {"desc":"g", "menu": 4},{"desc":"g", "menu": 4}
]

const groupMenu = groupBy(data, (item) => item.menu);
  

Затем в шаблоне

 <group *ngFor="let group of groupMenu">
  <menu *ngFor="let menu of group">
   <label>{{menu.desc}}</label>
  </menu>
</group>
  

Ответ №2:

Вы можете использовать что-то вроде

 ngOnInit(){
    var groups = new Set(this.array.map(item => item.menu))
    this.result = [];
    groups.forEach(g => 
      this.result.push({
        menu: g, 
        values: this.array.filter(i => i.menu === g)
      }
    ))
  }
  

и в HTML отображать данные

 <p>
    Start editing to see some magic happen :)
</p>
<div *ngFor="let item of result" border="1">
    <table>
        <tr>
            <th>Desc</th>
            <th>Menu</th>
        </tr>
        <ng-container>
            <tr>
                <td colspan="2">{{item.menu}}</td>
            </tr>
            <tr *ngFor="let value of item.values">
                <td>{{value.desc}}</td>
            </tr>
        </ng-container>
    </table>
    <div>
  

Пожалуйста, проверьте stackblitz, который я сделал.
https://stackblitz.com/edit/angular-4ekz4n

Счастливого кодирования 🙂

Ответ №3:

Напишите оператор импорта в компоненте angular

 import { of } from 'rxjs';
import { groupBy, mergeMap } from 'rxjs/operators';
  

Затем в ngOnInit()

 ngOnInit():void{
on(
    {id: 1, name: 'JavaScript'},
    {id: 2, name: 'Parcel'},
    {id: 2, name: 'webpack'},
    {id: 1, name: 'TypeScript'},
    {id: 3, name: 'TSLint'}
).pipe(groupBy(a=>a.id)),
 mergeMap((group$) => group$.pipe(reduce((acc, cur) => [...acc, cur], []))),
)
.subscribe(p => console.log(p));
  

// Вывод

 [ { id: 1, name: 'JavaScript'},
{ id: 1, name: 'TypeScript'} ]
[ { id: 2, name: 'Parcel'},
  { id: 2, name: 'webpack'} ]
[ { id: 3, name: 'TSLint'} ]
  

Для получения дополнительной информации обратитесь к RxJS

Ответ №4:

Сначала вам нужно обновить структуру текущего массива до структуры, как показано ниже:

 [
  {
    menu: 1,
    desc: ["a", "b"]
  },
  {
    menu: 2,
    desc: ["a1", "b1", "c1", "d1"]
  }
]
  

Вы можете обновить, выполнив итерацию текущего массива в файле ts компонента и упорядочить, как показано в примере выше.

После этого вы можете использовать этот обновленный массив в *ngFor в html для отображения данных.