skip to Main Content

Currently the response that is being sent back to client side looks like this:

[
  {
    "categoryName": "Orders",
    "categoryItems": [
      {
        "group": "Group B",
        "groupSettings": [
          {
            "settingName": "Group b description"
          }
        ]
      },
      {
        "group": "Group C",
        "groupSettings": [
          {
            "settingName": "Group c description"
          }
        ]
      },
      {
        "group": "Group A",
        "groupSettings": [
          {
            "settingName": "Group a description"
          }
        ]
      }
    ]
  },
  {
    "categoryName": "Notifications",
    "categoryItems": [
      {
        "group": "",
        "groupSettings": [
          {
            "settingName": "Notification setting"
          }
        ]
      }
    ]
  },
  {
    "categoryName": "Personalisation",
    "categoryItems": [
      {
        "group": "",
        "groupSettings": [
          {
            "settingName": "Personalisation setting"
          }
        ]
      }
    ]
  }
]

However, the expected layout is:

[
  {
    "categoryName": "Personalisation",
    "categoryItems": [
      {
        "group": "",
        "groupSettings": [
          {
            "settingName": "Personalisation setting"
          }
        ]
      }
    ]
  },
  {
    "categoryName": "Notifications",
    "categoryItems": [
      {
        "group": "",
        "groupSettings": [
          {
            "settingName": "Notification setting"
          }
        ]
      }
    ]
  },
  {
    "categoryName": "Orders",
    "categoryItems": [
      {
        "group": "Group A",
        "groupSettings": [
          {
            "settingName": "Group a description"
          }
        ]
      },
      {
        "group": "Group b",
        "groupSettings": [
          {
            "settingName": "Group b description"
          }
        ]
      },
      {
        "group": "Group c",
        "groupSettings": [
          {
            "settingName": "Group c description"
          }
        ]
      }
    ]
  }
]

How do I sort the categoryName to match the order that I expected? I am thinking about matching the sort order to an array of object with categoryName and sequence
properties, but I am stuck at the code.

My current code is as below:

const groupedData = _.chain(allData)
      .groupBy('sectionName')
      .map((allData, sectionName) => ({
        categoryName: sectionName,
        categorySettings: _.chain(allData)
          .groupBy('group')
          .map((groupSettings, group) => ({
            group: group,
            groupSettings: _.chain(groupSettings)
              .sortBy('ordering')
              .groupBy('title')
              .map((titleSettings, title) => ({
                settingName: title,
                settingDescription: titleSettings[0].description,
                settingInputs: _.map(titleSettings, ({name, value, inputSetting}) => ({
                  inputName: name,
                  inputValue: value,
                  inputConfig: inputSetting,
                })),
              }))
              .value(),
          }))
          .value(),
      }))
      .value();

2

Answers


  1. You can create an array with the expected order and use it to sort the groupedData array based on the categoryName

    const sortOrder = [
      { categoryName: "Personalisation", sequence: 1 },
      { categoryName: "Notifications", sequence: 2 },
      { categoryName: "Orders", sequence: 3 }
    ];
    
    const sortedGroupedData = _.chain(allData)
      ... // your function
      .value();
    
    //sort the array finally
    const finalSortedData = _.sortBy(sortedGroupedData, (item) => {
      const order = sortOrder.find(o => o.categoryName === item.categoryName);
      return order ? order.sequence : Infinity; // Infinity will make sure that any category not in sortOrder will be at the end
    });
    console.log(finalSortedData);
    
    

    (or) a more type safe solution

    You can create a mapping of categoryName to the required order i.e. index and then use that mapping to sort the data.

    I have reused your code. Considering you are using TS, i have made it typesafe too:

    //define an enum for checking during compile time
    enum CategoryName {
      Personalisation = "Personalisation",
      Notifications = "Notifications",
      Orders = "Orders",
    }
    
    //this creates a mapping of categoryName to its index in enum order
    const orderMap: Record<CategoryName, number> = {
      [CategoryName.Personalisation]: 0,
      [CategoryName.Notifications]: 1,
      [CategoryName.Orders]: 2,
    };
    
    const sortedGroupedData = _.chain(allData)
      .groupBy('sectionName')
      .map((allData, sectionName) => ({
        categoryName: sectionName as CategoryName, // typing sectionName as CategoryName
        categorySettings: _.chain(allData)
          .groupBy('group')
          .map((groupSettings, group) => ({
            group: group,
            groupSettings: _.chain(groupSettings)
              .sortBy('ordering')
              .groupBy('title')
              .map((titleSettings, title) => ({
                settingName: title,
                settingDescription: titleSettings[0].description,
                settingInputs: _.map(titleSettings, ({ name, value, inputSetting }) => ({
                  inputName: name,
                  inputValue: value,
                  inputConfig: inputSetting,
                })),
              }))
              .value(),
          }))
          .value(),
      }))
      .sortBy(item => orderMap[item.categoryName]) //sorting here
      .value();
    
    console.log(sortedGroupedData);
    

    You can use whichever you suits you better (obviously by making it type safe)

    Login or Signup to reply.
  2. I don’t know anything about lodash or Typescript, but here is a plain JavaScript solution that will place the elements with the listed properties first, in the custom-defined order, and any other elements (with categoryNames not mentioned in the lookup object order) alphabetically ordered at the end.

    I used a string ("00") for sorting instead of a numerical value as this allows for easy comparison with any non-numeric string. If, however, your array does not have these "other" properties you can simplify the comparison function by using numbers and simply subtracting one from the other.

    const data=[
      {
    "categoryName": "Orders",
    "categorySettings": "...the rest"
      },
      {
    "categoryName": "Notifications",
    "categorySettings": "...the rest"
      },
      {
    "categoryName": "Personalisation",
    "categorySettings": "...the rest"
      },
      { "categoryName": "other stuff",
    "categorySettings": "something else"
      }
    ],
    // define the sort order with this lookup object:
      order={Personalisation:"00", Notifications:"01",Orders:"02"};
    
    console.log(data.sort(({categoryName:a},{categoryName:b})=>(order[a]??a).localeCompare(order[b]??b)));
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search