Sorting objects by multiple fields in JavaScript (AngularJS) is not supported

ILLUSTRATION: http://jsfiddle.net/w38E8/4/

Take a look at the example provided above.

CONTROLLER:

function SortCtrl($scope) {
$scope.students = [{
    'name': 'AAA',
        'year': 'sophomore',
        'score': 100,
}, {
    'name': 'ABA',
        'year': 'freshman',
        'score': 70,
}, {
    'name': 'ABC',
        'year': 'freshman',
        'score': 30,
}, {
    'name': 'BAA',
        'year': 'junior',
        'score': 90,
}, {
    'name': 'BAB',
        'year': 'junior',
        'score': 70,
}, {
    'name': 'BBA',
        'year': 'junior',
        'score': 50,
}, {
    'name': 'CAA',
        'year': 'sophomore',
        'score': 30,
}, ];

$scope.sortArr = ['name']; // This array sorts the students                        

$scope.sortClass = function (field) { // asc:BLUE, desc:RED
    var fieldIdx = getIndexInArray(field, $scope.sortArr);
    if (fieldIdx > -1) {
        return $scope.sortArr[fieldIdx].indexOf('-') > -1 ? 'desc' : 'asc';
    }
    return '';
};

$scope.changeSort = function (field, $event) { 
    var fieldIdx = getIndexInArray(field, $scope.sortArr);

    if (fieldIdx > -1) {
        if ($event.shiftKey) {

        } else if ($scope.sortArr.length > 1) {
            $scope.sortArr = [field];
            fieldIdx = getIndexInArray(field, $scope.sortArr);
        }
        $scope.sortArr[fieldIdx] = $scope.sortArr[fieldIdx].indexOf('-') > -1 ? $scope.sortArr[fieldIdx].replace('-', '') : '-' + field;
    } else {
        if ($event.shiftKey) {
            $scope.sortArr.push(field);
        } else {
            $scope.sortArr = [field];
        }
    }

    var length = $scope.sortArr.length;

    $scope.students.sort(function (a, b) {
        var sortA = '';
        var sortB = '';
        var fieldA = '';
        var fieldB = '';

        for (var i = 0; i < length; i++) {
            if (field == 'year') {
                if (field == $scope.sortArr[i].replace('-', '')) {
                    fieldA += customOrder(a.year);
                    fieldB += customOrder(b.year);
                } else {
                    sortA += customOrder(a.year);
                    sortB += customOrder(b.year);
                }
            } else {

                if (field == $scope.sortArr[i].replace('-', '')) {
                    fieldA += a[$scope.sortArr[i].replace('-', '')];
                    fieldB += b[$scope.sortArr[i].replace('-', '')];
                } else {
                    sortA += a[$scope.sortArr[i].replace('-', '')];
                    sortB += b[$scope.sortArr[i].replace('-', '')];
                }
            }
        }


        if (sortA != sortB) { 
            if (sortA < sortB) return -1;
            if (sortA > sortB) return 1;
            return 0;
        }

        if ($scope.sortArr[getIndexInArray(field, $scope.sortArr)].indexOf('-') > -1) return fieldA == fieldB ? 0 : (fieldA < fieldB ? 1 : -1);
        else return fieldA == fieldB ? 0 : (fieldA < fieldB ? -1 : 1);
    });
};



function getIndexInArray(field, arr) {
    var idx = -1;

    angular.forEach(arr, function (value, index) {
        if (field == value.replace('-', '')) {
            idx = index;
        }
    });
    return idx;
};

function customOrder(type) {
    switch (type) {
        case 'freshman':
            return 0;
        case 'sophomore':
            return 1;
        case 'junior':
            return 2;
        case 'senior':
            return 3;
    }
};
};

The given example demonstrates how multiple fields can be sorted by holding down the shift key. Additionally, each click on the header changes the order.

The challenge lies in not being able to sort objects YEAR:DESC and then name:ASC. The following snippet seems to be causing the problem:

if (sortA != sortB) { 
    if (sortA < sortB) return -1;
    if (sortA > sortB) return 1;
    return 0;
}

I am unsure how to resolve this issue. Any assistance would be greatly appreciated as I have been grappling with this for quite some time!

ILLUSTRATION: http://jsfiddle.net/w38E8/4/

Answer №1

Success! I finally managed to make it work.

function compareAscending(a, b) { if(a < b) return -1; else if(a > b) return  1; else return 0;};
function compareDescending(a, b) { if(a < b) return  1; else if(a > b) return -1; else return 0;};
var arrayLength = $scope.sortArr.length;

$scope.students.sort(function (a, b) {
    for (var i = 0; i < arrayLength; i++) {
        var field = $scope.sortArr[i],
            sortFunction = compareAscending;
        if(field.charAt(0) === "-") {
            sortFunction = compareDescending; field = field.substring(1);
        }
        if(field === "group") field = "score";
        if(a[field] === b[field]) continue;
        if(field === "year") return sortFunction(customOrder(a[field]), customOrder(b[field]));
        else return sortFunction(a[field], b[field]);
    }
    return 0;
});

Give it a try at http://jsfiddle.net/9W3bC/

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

borders in motion

I am currently working with this jQuery code. //this is the main javascript $(document).ready(function(){ $('nav.menu a').hover( function () { $('nav.menu').find(".current_item").removeClass("current_item"); ...

Using AJAX to populate a dropdown menu in a CodeIgniter application

I'm having an issue with using AJAX to populate a dropdown option. Here is the JavaScript code I am using: <script type="text/javascript"> $(document).ready(function(){ $("#sepatu").click(function(e){ e.preventDefault() ...

Searches for Mongoose Queries

Here is the table structure: "products": [ { "reviews": [], "_id": "5ece6d09cab302507c5d147e", "category": { "_id": "5ece6c07cab302507c5d1478", "type": "Marketing", = I need to r ...

What are some effective methods for troubleshooting npm modules?

Typically, the process involves installing React with yarn/npm install react and then using it by importing React from 'react' Imagine you need to debug a React source code, so you clone a GitHub repository. But how do you incorporate this sour ...

Incorporate a division based on the selection made from a jQuery dropdown menu

Is there a way to dynamically display a div to the right of a drop-down menu based on the user's selection using DOM manipulation? For reference, you can view an example of my current progress here: http://jsbin.com/#/afojid/1/edit The initial drop ...

Is it possible to move the res.send() outside of the function in node.js?

I currently have the following code: var server = http.createServer(function(req,res){ res.writeHead(200,{'Content-Type': 'text/html; charset=utf-8'}); var oo = require('/test.js'); oo(connection, function (e, res ...

How to Choose Two Checkboxes from a Set of Multiple Checkboxes in AngularJS

I am looking to choose just two checkboxes from a selection of multiple checkboxes that are not nested in a list. <input type="checkbox" class="two-checkbox" id="curr-EUR" ng-model="reqObject.EUR" ng-click="checkChanged()">EUR</input> <inpu ...

Is a single f.select impacting another f.select in the same form? (undesired)

I am facing an issue where adding a new HTML element like: <%= f.date_select :date, { id: "date-select"} %> is impacting my existing collection select: <%= f.collection_select :id, Customer.where(business_id: current_c ...

Transitioning AngularJS to utilize imports and exports

We are in the process of transitioning our project from AngularJS (v1.6) + TypeScript to the latest version of Angular. To prepare for this upgrade, we want to start implementing components similar to how they are written in Angular. Currently, we are not ...

Executing multiple requests simultaneously with varying identifiers following a waiting period

I am looking to send a GET request using the user_id key retrieved from the userData object. This is how the request should be structured: Let's assume we have userData defined as follows: var userData = [ { id: 1, user_id: ...

The connection to Cordova.js is established, but the deviceready event is not

I've included cordova.js in my project, called app.initialize();, but for some reason deviceready event is not being triggered. Any ideas on what might be causing this issue? Here's the JavaScript code: var app = { initialize: function() { ...

Customize the appearance of the Material UI expansion panel when it is in its expanded

Is there a way to customize the height of an expanded expansion panel summary? Specifically, I am looking to remove the min-height property and set the summary panel's height to 40px instead of the default 64px. I have attempted to make this change in ...

Transitioning from one bootstrap modal to another in quick succession may lead to unexpected scrolling problems

I'm facing a challenge with two modals where scrolling behavior becomes problematic when transitioning from one to the other. Instead of scrolling within the modal itself, the content behind it is scrolled instead. In order to address this issue, I im ...

Using Knockout along with Ajax content leads to various binding issues

After creating a complex web application with numerous pages, I encountered an issue while implementing Ajax-optimized page loading for Knockout-driven pages. The structure of my pages includes: <body> <div id="content"> </div> < ...

The jQuery autocomplete feature is malfunctioning, as it is unable to display any search

Creating a country list within an ajax call involves working with an array of objects: $.ajax({ url: '//maps.googleapis.com/maps/api/geocode/json?address=' + zipCode + '&region=AT', type: 'GET', dataType: &apo ...

Discover the secret to instantly displaying comments after submission without refreshing the page in VueJS

Is there a way to display the comment instantly after clicking on the submit button, without having to refresh the page? Currently, the comment is saved to the database but only appears after refreshing. I'm looking for a solution or syntax that can h ...

A guide to populating a table with JSON data that includes empty cells in AngularJS

I'm dealing with JSON data that includes employee names and salaries over multiple days (1-5). My goal is to display this information in an HTML table using AngularJS, mimicking the layout of the required table below. JSON Data: [{ name: "Jo ...

Why isn't my NPM package functioning properly within the Laravel framework?

I recently developed an npm package for my personal use, but encountered a ReferenceError when attempting to utilize it in a Laravel project. Here's the breakdown of what I did: I followed a tutorial on initializing an npm package, and it functioned p ...

Retrieving the value of an inner div upon clicking the outer div

I currently have a collection of button divs, each containing distinct information: <div class="button"> <div id="first"> Johny </div> <div id="second"> Dog </div> <div id="third"> Pasta & ...

Basic library using babel, TypeScript, and webpack - Error: (...) is not a recognized function; within Object.<anonymous>

Recently, I encountered a strange issue while trying to bundle a simple function using babel, typescript, and webpack. You can find the example that is not working at this link. To test it, simply download the code, run npm/yarn install, npm/yarn run buil ...