Отображать несколько одинаковых значений только один раз, пока другие выполняют цикл с использованием ngFor в Angular

#angular #typescript #ngfor #angular10

#angular #машинописный текст #ngfor #угловой 10

Вопрос:

У меня есть следующий образец набора данных, который поступает с сервера.

 [
    {
        subMenuId: 1,
        submenu: 'Users',
        menu: 'Administration',
        url: '/pms/admin/usrs-dsh',
        icon: 'fas fa-cogs',
    },
    {
        subMenuId: 2,
        submenu: 'Roles',
        menu: 'Administration',
        url: '/pms/admin/roles-dsh',
        icon: 'fas fa-cogs',
    },
    {
        subMenuId: 3,
        submenu: 'Menu Items',
        menu: 'Administration',
        url: '/pms/admin/menus-dsh',
        icon: 'fas fa-cogs',
    },
    {
        subMenuId: 4,
        submenu: 'Banks',
        menu: 'Administration',
        url: '/pms/admin/banks-dsh',
        icon: 'fas fa-cogs',
    },
    {
        subMenuId: 5,
        submenu: 'Branches',
        menu: 'Administration',
        url: '/pms/admin/branches-dsh',
        icon: 'fas fa-cogs',
    },
    {
        subMenuId: 6,
        submenu: 'Dashboard',
        menu: 'PD3',
        url: '/pms/pd3/dsh',
        icon: 'fas fa-cogs',
    },

];
  

И я хочу отобразить эти данные следующим образом. Но в настоящее время при отображении значений основного уровня данных повторяются с каждым значением подуровня.
Ожидаемый результат:
Ожидаемый результат

Мой вывод:
мой вывод

Html-файл:

  <tr *ngFor="let m of userPermissions;">
                        <td>
                            <label class="ml-3 form-check-label">{{m.menu}}</label>
                        </td>
                        <td>
                            <div>
                                <input (change)="changeSubMenus($event, m.menu,m.subMenuId)" type="checkbox" class="ml-0 form-check-input">
                                <label class="ml-3 form-check-label">{{m.submenu}}</label><br>
                            </div>
                        </td>
                    </tr>
  

TS-файл:

 getMenus(){
  this.userPermissions = this.adminService.allMenus;
  
  this.userPermissions.forEach((val) =>{
     // console.log(val)
     // TODO: remove multiple main level values and display sub level values with one main level value
  })
  

}

Есть ли какой-нибудь способ добиться этого? Спасибо

Ответ №1:

Вам необходимо изменить объекты в массиве, чтобы выполнить требуемое требование. Для этого вы можете использовать reduce, как показано ниже.

Вам нужно иметь структуру объекта, подобную приведенной ниже, чтобы упростить задачу

 modifiedMenu = [{
  menu: < Main Menu 1 > ,
  subMenu: [ < submenu item > , < submenu item > , ...]
}, {
  menu: < Main Menu 2 > ,
  subMenu: [ < submenu item > , < submenu item > , ...]
}, ...]
  

Итак, исходный

 userPermissions = this.menus.reduce((acc, ele) => {
  if (acc.length === 0) {
    acc.push(this.getModifiedMainMenu(ele));
    return acc;
  } else {
    const existedMenu = acc.find(m => m.menu === ele.menu);
    if (existedMenu) {
      existedMenu.subMenu.push(this.getSubMenu(ele));
      return acc;
    } else {
      acc.push(this.getModifiedMainMenu(ele));
      return acc;
    }
  }
}, []);

getModifiedMainMenu(obj) {
  return {
    menu: obj.menu,
    subMenu: [this.getSubMenu(obj)]
  };
}

getSubMenu(obj) {
  return {
    menu: obj.menu,
    subMenuId: obj.subMenuId,
    submenu: obj.submenu,
    url: obj.url,
    icon: obj.icon
  };
}
  

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

 <tr *ngFor="let m of userPermissions;">
  <td>
    <label class="ml-3 form-check-label">{{m.menu}}</label>
  </td>
  <td>
    <div *ngFor="let subMenu of m.subMenu">
      <input (change)="changeSubMenus($event, subMenu.menu, subMenu.subMenuId)" type="checkbox" class="ml-0 form-check-input">
      <label class="ml-3 form-check-label">{{subMenu.submenu}}</label>
    </div>
  </td>
</tr>
  

Рабочий стекблитц