Search code examples
arraysangularsortingdynamic

Angular - Passing a dynamic string property name to Sort and object array


I am trying to dynamically sort a simple object by the property name.

  sampleArr: {
    name: string;
    age: number;
    }[ ] = [
    { name: "Michael", age: 21},
    { name: "Adam", age: 35 },
    { name: "Zoe", age: 11 },
    ];

I understand that sorting by the string column is different to sorting by the number column so let's put that aside for the moment. Let's focus on the string column.

this.sampleArr.sort((a, b) => a.name.localeCompare(b.name))

The code above work perfectly fine. However, I have hard coded the name column. I would like to make that dynamic.

Let's say I had an array with multiple string fields where I give the user the choice to chose the column to sort by. For example...I want to be able to pass in the column name as a string (sortBy) and use that to determine the field to sort by.

So essentially, I would be replacing the hard coded a.name and b.name with a[sortBy] and b[sortBy]

sampleArrSort(sortBy: string) {
    // this.sampleArr.sort((a, b) => a.name.localeCompare(b.name))
    this.sampleArr.sort((a, b) => a[sortBy].localeCompare(b[SortBy]))

    console.log(this.sampleArr);
  }

However, I get the following error.

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ name: string; age: number; }'.
  No index signature with a parameter of type 'string' was found on type '{ name: string; age: number; }'.ts(7053)

Does anyone know how to solve this?

Thanks for your help.

I have searched everywhere and can't seem to adapt code snippets that I have found to my scenario. I may need to use keyOf? I am not sure


Solution

  • If you want to dynamically pass the property names it is important that all of the values can be passed to the sampleArrSort function.

    You can create an interface of your array item and use said interface to pass a keyof Person to the sampleArrSort function.

    Since you have both string and also number values, you will need to check the types of the values inside the sampleArrSort function and compare the values accordingly.

    Playground

    interface Person {
        name: string;
        age: number;
        }
    
    const sampleArr: Person[] = [
        { name: "Michael", age: 21},
        { name: "Adam", age: 35 },
        { name: "Zoe", age: 11 },
        ];
    
    function sampleArrSort(sortBy: keyof Person): void {
        sampleArr.sort((a, b) => {
            const valueA = a[sortBy];
            const valueB = b[sortBy];
    
            if (typeof valueA === 'string' && typeof valueB === 'string') {
                return valueA.localeCompare(valueB);
            } else if (typeof valueA === 'number' && typeof valueB === 'number') {
                return valueA - valueB;
            } else {
                throw new Error(`Unsupported type for sorting: ${typeof valueA}`);
            }
        });