Sorting an array of nested objects in TypeScript or JavaScript can be achieved by using a common property that all objects have in common

Currently, I am diving into TypeScript and JS but encountering various challenges. One particular problem that is causing me trouble involves handling an array of Application objects with a nested structure. Each Application object consists of Document Types, which in turn contain Documents with Metadata.

Essentially, each Application has an array of Document Type, each Document Type has an array of Document, and each Document includes Metadata information. All three types - Application, Document Type, Document - have a property named 'name' within them.

My goal is to sort the entire array of Application objects, along with their nested objects, based on the ascending order of the 'name' property for each object. Despite attempting multiple examples, my sorting function only organizes the root level objects (Application) without considering the nested objects.

I've made an attempt with this example:

var simplePropertyRetriever = function(obj:any) {
      return obj.name;
     };

function sortArrayByName(propertyRetriever, arr:Application[]) {
   arr.sort(function (a, b) {
        var valueA = propertyRetriever(a);
        var valueB = propertyRetriever(b);

        if (valueA < valueB) {
            return -1;
        } else if (valueA > valueB) {
            return 1;
        } else {
            return 0;
        }
    });

  };

I would appreciate any guidance on how to achieve this desired sorting methodology. Below is a sample JSON structure showcasing the objects in descending order for better comprehension:

[
 {
  "name": "Application 2",
  "children": [
   {
    "name": "Operations Manual",
    "children": [
     {
      "name": "2nd-opsManual-app1",
      "metadata": {
       "size": 56,
       "fileExtension": "docx"
      }
     },
     ...
    ]
   },
   ...
 ]
},
{
  "name": "Application 1",
  "children": [
   {
    "name": "User Manual",
    "children": [
     {
      "name": "1st-userManual-app1",
      "metadata": {
       "size": 56,
       "fileExtension": "pdf"
      }
     },
     ...
    ]
   },
   ...
 ]
}
]

Answer №1

One way to organize the array is by iterating through it and sorting its children.

function sort(array) {
    array.forEach(({ children = [] }) => sort(children));
    array.sort((a, b) => a.name.localeCompare(b.name));
}

var data = [{ name: "Application 2", children: [{ name: "Operations Manual", children: [{ name: "2nd-opsManual-app1", metadata: { size: 56, fileExtension: "docx" } }, { name: "1st-opsManual-app1", metadata: { size: 56, fileExtension: "pdf" } }] }, { name: "Interface Contracts", children: [{ name: "2nd-IntContracts-app1", metadata: { size: 56, fileExtension: "docx" } }, { name: "1st-IntContracts-app1", metadata: { size: 56, fileExtension: "pdf" } }] }] }, { name: "Application 2", children: [{ name: "User Manual", children: [{ name: "2nd-userManual-app2", metadata: { size: 56, fileExtension: "docx" } }, { name: "1st-userManual-app2", metadata: { size: 56, fileExtension: "pdf" } }] }, { name: "System Design", children: [{ name: "2nd-SystemDesign-app2", metadata: { size: 56, fileExtension: "docx" } }, { name: "1st-SystemDesign-app2", metadata: { size: 56, fileExtension: "pdf" } }] }] }];

sort(data);

console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Answer №2

Your current code implementation successfully performs a shallow sort. However, if you also require sorting the children of each application object, you can achieve this by calling the sortArrayByName function recursively on the children of each application object (if they are present).

var propertyGetter = function(obj) {
  return obj.name;
 };

function sortArrayByName(propertyGetter, arr) {
 arr.forEach(function(obj) {
      if (Array.isArray(obj.children)) {
        sortArrayByName(propertyGetter, obj.children);
      }
 });
 arr.sort(function (a, b) {
      var valueA = propertyGetter(a);
      var valueB = propertyGetter(b);

      if (valueA < valueB) {
          return -1;
      } else if (valueA > valueB) {
          return 1;
      } else {
          return 0;
      }
  });
};

const appData = [
 {
  "name": "Application 2",
  "children": [
   {
    "name": "Operations Manual",
    "children": [
     {
      ...
     },
     ...
    ]
   },
   ...
  ]
 },
 {
  "name": "Application 2",
  "children": [
   {
    ...
   },
   ...
  ]
 }
];

sortArrayByName(propertyGetter, appData);

console.log(appData);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Chrome poses an issue with the placement of a button

There seems to be an issue with the button on Google Chrome. Sometimes it appears in the correct place, but upon refreshing the page, it shifts to the wrong position. This problem does not occur in other browsers: This is a specific problem related to Chr ...

Organize table cells based on decimal places

Organize the table cells based on their decimal points. Plunker Sample JSON: [ { "data1": [ { "name": "Download", "id": "1.1.1" }, { "name": "Download", ...

Employ Jade as the template engine for your Angular 2 project

As I transition to developing MEAN apps with Angular2 instead of Angular1.x, I am encountering a challenge involving the use of jade/pug as my template engine in angular2. I came across a tutorial on how to implement this using webpack, but it seems to b ...

Is there a way to implement jQuery on dynamically added content?

I created a page that closely resembles a Facebook wall, with posts, comments for each post, and a "send" button to add new comments. In this example: The posts are identified by the class "mypost". The "send-comment" button is located within a div with ...

Encountered an error while attempting to proxy request from localhost:8000 to http://localhost:4000. Connection refused (ECONNREFUSED) was the cause of the issue

Trying to build a Gatsby App with the help of this Starter kit found at this GitHub link But every time I update my node packages and run Gatsby Develop, I encounter an HPM Error when trying to access my page. The project compiles without any issues, but ...

IE11/Edge exhibits slow performance with components that have large datasets exclusively

Take a moment to analyze the following code snippet: <GridBody Rows={rows} />. Let's say that in this scenario, rows.length could reach 2000 or more, with each array containing approximately 8 columns. I have encountered a performance bottleneck ...

The entity known as Sentry has not been specified

After following a tutorial by JSMastery, I successfully created a portfolio website using Next.js. We also integrated Sentry into our app to allow users to report bugs. Everything was working perfectly fine on my local machine and even after deploying it o ...

Typescript challenge: Implementing a route render attribute in React with TypeScript

My component has props named project which are passed through a Link to a Route. Here's how it looks (the project object goes in the state extended property): <Link to={{ pathname: path, state: { project, }, }} key={project. ...

Utilizing Nodemailer and ReadableStreams to send email attachments stored in S3

My current challenge involves sending emails with Nodemailer that include attachments hosted in S3, utilizing JS AWS SDK v3. The example provided in the Nodemailer documentation demonstrates how to send an attachment using a read stream created from a file ...

What is the best way to retrieve the js window object within emscripten's EM_JS function?

I'm looking to access the window.location in an EM_JS method in order to call a JavaScript method from C++. My attempted approach was: EM_JS(const char*, getlocation, (), { let location = window.location; let length = lengthBytesUTF8(location ...

When using iOS, the video compressing process stops automatically if the screen is no longer active while the file input

I am working on a web application that includes a file upload feature for large videos, typically 30 minutes or longer in duration. When a user on an iOS device selects a video to upload, the operating system will automatically compress it before triggerin ...

The Closure compiler changes the names of classes

I have a question that might seem simple, but I'm having trouble finding the solution. How can I prevent the Closure Compiler from renaming the SomeClassName class that is dependent on jQuery? (function($) { /** * SomeClassName * @constructo ...

Maximize your Mongoose querying abilities by sorting on two attributes for optimal results

Here are some example MongoDB records: [ {first: "Sample", middle: "X", last: ""}, {first: "Sample", middle: "Y", last: ""}, {first: "Sample", middle: "", last: "Z"}, {first: "Sample", middle: "W", last: ""} ] Results: If .arrange({middl ...

Stop Internet Explorer from automatically scrolling when it gains focus

Please access this fiddle using internet explorer (11): https://jsfiddle.net/kaljak/yw7Lc1aw/1/ When the page loads, the <p> tag is focused and Internet Explorer slightly scrolls the element so that the table border becomes invisible... document.qu ...

When attempting an Axios request, the backend method cannot be accessed

I am facing an issue when using Axios request to access a method in the backend. I am constrained by pre-existing code in both frontend and backend that limits how much I can modify or add. Frontend: const response = await axiosConfig.put<IReserved&g ...

Clearing the content div and making it reappear using javascript

I am currently utilizing jQuery's CustomBox modal feature. While it is functioning properly, I am seeking a way to hide the div behind the modal (excluding the background image) when the modal is activated. I have successfully achieved this, but I am ...

removing a property from an object using AngularJS

Currently, I am working on a project involving AngularJS. The main goal of this project is to create a dynamic JSON generator using AngularJS. I have already developed the initial version and it works well. However, there is a minor issue with my applicati ...

The webpage must be designed to be compatible with screen resolutions starting from 800 x 600 pixels and higher, utilizing Angular

I am working on developing a webpage that is specifically designed to work for resolutions of 800 x 600 pixels and higher. Any other resolutions will display the message "This website can only be accessed from desktops." Here is my approach using jQuery: ...

Is the Property Decorator failing to substitute the definition?

My code is similar to the following scenario, where I am attempting to replace a property based on a decorator export function DecorateMe() { return function(component: any, propertyKey: string) { Object.defineProperty(component, propertyKey, ...

Route Angular 4 application static resources to a /PORT directory rather than the primary domain

Our Angular 4 application is integrated within a Node + Express app and started like a typical node app, such as: node index.js On a local machine, the Angular app is served from the /client directory: app.use(express.static(__dirname + "/client")); Onc ...