How can I use AngularJS orderBy to sort by a specific object's string property?

Is there a way to prioritize items in a task list based on both their date of addition and their listed priority? I've managed to sort the tasks by date, but I'm looking for a solution that will organize items with the 'HIGH' priority at the top of the list.

UPDATE: Ideally, I want the sorting to occur based on the 'HIGH' property when it is selected from the 'Sort By' dropdown menu located above the task list.

Codepen: http://codepen.io/anon/pen/ryyQzy.

HTML:

<md-list class="md-padding">

                   <div layout="row">

                        <md-input-container class="md-block" flex="70">

                            <input type="text" ng-model="search" name="search" placeholder="Search by Task Name"></input>  

                        </md-input-container>

                        <md-input-container flex="30">

                            <md-select name="priority" ng-model="task.priority" placeholder="Sort By">

                                <md-option value="Low">Newest First</md-option>

                                <md-option value="HIGH">High Priority First</md-option>

                            </md-select>

                        </md-input-container>

                    </div>

                    <md-subheader class="md-no-sticky">Current Tasks ({{taskList.length}})</md-subheader> 

                    <md-list-item class="md-3-line" ng-repeat="task in taskList | orderBy:sortByNewest | filter:search">

                       <div class="md-list-item-text" layout="column">

                            <p>{{task.name}}</p>

                            <p>Priority: {{$location.path('/')}}</p>

                            <span class="weak">Added {{task.addedOn | date: 'medium'}}</span>

                        </div>

                        <md-checkbox class="md-secondary" ng-model="task.completed"></md-checkbox>

                        <md-divider ng-if="!$last"></md-divider>

                    </md-list-item>

                </md-list>

JS:

var app = angular.module('todoApp', ['ngMaterial']);

function menuController ($scope, $mdDialog) {
    var originatorEv;
    this.openMenu = function($mdOpenMenu, ev) {
        originatorEv = ev;
        $mdOpenMenu(ev);
    };
};  

app.controller('todoController', function($scope, $mdDialog, $mdToast, $filter) {

    $scope.sortByNewest = '-addedOn';
    //$scope.sortByPriority = ' ';

    $scope.taskList = [
        { name: 'Task 1', priority: 'Low', completed: false, addedOn: 1488722128000 },
        { name: 'Task 2', priority: 'HIGH', completed: false, addedOn: 1488722128000 },
    ];

    $scope.addTask = function() {
        if (angular.isUndefined($scope.taskName) || $scope.taskName.length === 0) {
            var alert =  $mdDialog.alert()
                .parent(angular.element(document.querySelector('#popupContainer')))
                .clickOutsideToClose(true)
                .title('Error')
                .textContent('You must enter a task name and select a priority level')
                .ok('Close');
            $mdDialog.show( alert )
                .finally(function() {
                    alert = undefined;
                });
        }
        else {
            $scope.taskList.push({name: $scope.taskName, priority: $scope.task.priority, addedOn: Date.now()});
            $scope.taskName = "";
            $scope.task.priority = "";
            var pinTo = $scope.getToastPosition();
            $mdToast.show (
                $mdToast.simple()
                .textContent('Task Added')
                .position(pinTo)
                .hideDelay(3000)
            )
        }
    };

    $scope.selectAll = function() {
        angular.forEach($scope.taskList, function(task) {
            task.completed = true;
        });  
    };

    $scope.selectNone = function() {
        angular.forEach($scope.taskList, function(task) {
            task.completed = false;
        });  
    };

    $scope.delete = function(ev) {

        var completedTasks = $filter('filter')($scope.taskList, { completed: true}, true);

        if (completedTasks.length > 0) {
            console.log('show dialog box to confirm');   
            var confirm = $mdDialog.confirm()
                .title ('Are you sure you want to delete the selected tasks?')
                .textContent ('Deleted tasks can\'t be recovered.')
                .targetEvent (ev)
                .ok ('Confirm')
                .cancel ('Cancel')
            clickOutsideToClose: false;
            $mdDialog.show(confirm).then(function() {
                if (completedTasks.length > 1) {
                    var pinTo = $scope.getToastPosition();
                    $mdToast.show (
                        $mdToast.simple()
                        .textContent('Tasks Deleted')
                        .position(pinTo)
                        .hideDelay(3000)
                    )
                }
                else {
                    var pinTo = $scope.getToastPosition();
                    $mdToast.show (
                        $mdToast.simple()
                        .textContent('Task Deleted')
                        .position(pinTo)
                        .hideDelay(3000)
                    )
                }
                $scope.status = 'Tasks Deleted';
                var i = $scope.taskList.length;
                while (i--) {
                    var task = $scope.taskList[i];
                    if(task.completed) {
                        $scope.taskList.splice(i, 1);
                    }
                }

            }, 
            function() {
                $scope.status = 'Deletion Cancelled';
            });
        } 

        else {
            $mdDialog.show(
                $mdDialog.alert()
                    .parent(angular.element(document.querySelector('#popupContainer')))
                    .clickOutsideToClose(true)
                    .title('Error')
                    .textContent('You must select at least one task to delete.')
                    .ok('Close')
                    .targetEvent(ev)
            );
        }
    };

    function DialogController($scope, $mdDialog) {
        $scope.hide = function() {
            $mdDialog.hide();
        };

        $scope.cancel = function() {
            $mdDialog.cancel();
        };

        $scope.answer = function(answer) {
            $mdDialog.hide(answer);
        };
    };

    var last = {
        bottom: false,
        top: true,
        left: false,
        right: true
    };

    $scope.toastPosition = angular.extend({},last);

    $scope.getToastPosition = function() {
        sanitizePosition();
        return Object.keys($scope.toastPosition)
        .filter(function(pos) { return $scope.toastPosition[pos]; })
        .join(' ');
    };

    function sanitizePosition() {
        var current = $scope.toastPosition;
        if ( current.bottom && last.top ) current.top = false;
        if ( current.top && last.bottom ) current.bottom = false;
        if ( current.right && last.left ) current.left = false;
        if ( current.left && last.right ) current.right = false;
        last = angular.extend({},current);
    };

});

app.controller('toastController', function($scope, $mdToast) {
    $scope.closeToast = function() {
        $mdToast.hide();
    }

});

Answer №1

orderBy requires the property names of the objects it is sorting. Therefore, within your select options, you need to specify these property names like this:

<md-select name="sortBy" placeholder="Sort By" ng-model="sortBy">
  <md-option value="addedOn">Newest First</md-option>
  <md-option value="priority">High Priority First</md-option>
</md-select>

If a string is encountered within these properties, orderBy will sort the array alphabetically. This is convenient for you since High comes before Low.

According to the Angular Documentation:

The default comparator should work for most cases, comparing numbers numerically, strings alphabetically (case-insensitive), falling back to index for objects, and sorting different types by type.

Check out Angular's documentation on orderBy here!

Answer №2

Make sure to utilize

ng-model="search.name" and ng-model="search.priority"
. This way, it will gather all search criteria from the search object. (filter:search)

Take a look at the updated version on Codepen

Please adjust your view according to the following: Search by Task Name model should be ng-model="search.name" instead of ng-model="search" Sort By model should be ng-model="search.priority" instead of ng-model="sortBy"

<div layout="row">

  <md-input-container class="md-block" flex="70">

    <input type="text" ng-model="search.name" name="search" placeholder="Search by Task Name"></input>

  </md-input-container>

  <md-input-container flex="30">

    <md-select name="priority" ng-model="search.priority" placeholder="Sort By">

      <md-option value="Low">Newest First</md-option>

      <md-option value="HIGH">High Priority First</md-option>

    </md-select>

  </md-input-container>

</div>

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

Develop your own personalized Angular schematics that produces a file that begins with an underscore

Having trouble with custom Angular schematics file naming. I'm trying to create a theme SCSS file that starts with an underscore followed by a double underscore as a delimiter. For instance, I want the file name to be _mouse-theme.scss, using the nam ...

Route is not simply a component in this context. When using Routes, all component children must be either a Route or wrapped within

I am currently working on my App.js file and encountering an issue while creating paths. I have wrapped a Route element around my IsUserRedirect, but the error persists. import React, {Fragment} from 'react'; import * as ROUTES from './cons ...

Issue with collecting data in Meteor Collection

After making some edits to another file and increasing the complexity of my application, a tracker function that was previously working fine is now experiencing issues. It is no longer returning any data for vrLoan fundingData This is a snippet of my c ...

Tips for updating parent data with multiple values from a child component

Check out the code snippet below. I seem to be stuck on a crucial component. Despite going through the documentation and watching tutorials on Vue2, I can't seem to grasp this key element. Any assistance would be greatly appreciated. If my approach i ...

What is the best approach to unit testing this React Component?

I have created a component that acts as a wrapper for another component. My question is, how should I approach unit testing for this component? Besides checking the state and method calls to ensure they update the state correctly. Other than rendering pro ...

Tips on effectively transferring formarray to another component

I'm attempting to pass a formarray to a child component in order to display the values within the formarray there. Here is my current code, but I am struggling to figure out how to show the formarray values in the child component. app.component.html ...

Guidelines on resolving the issue of Unsupported platform for [email protected]: requested {"os":"darwin","arch":"any"} (existing: {"os":"win32","arch":"x64"})

Trying to install Parallelshell but encountering a persistent warning. I've checked the package file multiple times without finding a solution. Can someone assist me with this issue? ...

When using @testing-library/react (rtl), the 'waitFor' function achieves success even without the need for the 'await' keyword

waitFor() is causing my test to fail while waitFor() (without await) makes it pass. The official documentation states: Async methods return a Promise, so you must always use await or .then(done) when calling them. (https://testing-library.com/docs/guide ...

Submit data from one form to another form located within an iframe

I am currently using a JX Browser that allows content to be displayed in an iframe. My goal is to automatically transfer the username and password of a user logging into my ticketing software to another form within an iframe. The page within the iframe is ...

Is Highcharts-angular (Highcharts wrapper for Angular) compatible with Angular 4?

I have attempted to install various versions of highcharts-angular, ranging from 2.0.0 to 2.10.0. However, I consistently encounter the same error when running the application. The error message states: Metadata version mismatch for module C:/dev/Angular- ...

How to convert an array of keys and an array of values into an array of objects using JavaScript

My question is similar to the one found here: Merging keys array and values array into an object using JavaScript However, I am unable to find a solution for my specific scenario. If I have these two arrays: const keys = ['x', 'y', &ap ...

Create an Interactive Data Visualization with JSON using CanvasJS Charts

Having some trouble creating a chart using CanvasJS. After fetching data from the API and checking the JSON array, I encounter two errors when attempting to generate dataPoints for the graph: "data invalid" on the data field and "NaN" on the value field. ...

Deferred computed property fails to recognize the final character entered into the input field

I am facing an issue with my automated tests using selenium. The problem lies with a particular input field in a web form: <input data-bind="value: searchText, valueUpdate: 'afterkeydown'"></input> Here is the model associated with ...

React - Exploring the depths of functional components

Picture this: a straightforward form that showcases several unique components with customized layouts. The custom components include: <UsernameInput />, <PasswordInput />, <DateTimePicker />, <FancyButton />, <Checkbox /> Th ...

Easy Sorting with Counting Sort Algorithm in PHP

For my PHP project, I need to sort some data using a linear time, simple counting method: $ar = array(7, 2, 0, 3, 8, 0, 12, 7, 6, 7); $count = array(); foreach ($ar as $v) $count[$v]++; $sorted = array(); foreach ($count as $v => $c) for ($ ...

Adjust the href attribute of a link dynamically using the value input from a text field immediately

Is there a way to dynamically change the href attribute of a link when a user types in an input field? And is it possible to detect when a user pastes content into the input field as well? Would appreciate any suggestions on how to accomplish this using j ...

Receiving a JSON object in response after sending data to a server using JavaScript

I am facing an issue with passing an email and password on login click to a database using PHP. After testing the email and password combination, PHP sends back a JSON object. While I have verified that the PHP code is functioning correctly and returns a J ...

The options in the dropdown menu vanish when interacting with a jQuery feature that relies on

Recently, I have found AJAX, JSON, and jQuery to be indispensable tools in my coding endeavors. The application I am working on is a replacement for a flawed one, and it is coming along nicely. Despite making progress with the AJAX method, I have encounte ...

Verify for any alterations in the code by utilizing the inspect element feature

Currently dealing with a security concern regarding my older Java application. Is there a method available to detect any modifications made to my code (HTML or script) through Developer Tools on the user's end? This would allow me to prevent form subm ...

Using an AngularJS directive that has a dynamic ID may cause issues with d3's ability to append

I encountered a situation where my angularJS directive works fine when I specify a hardcoded ID for appending elements, but fails to append when the ID is dynamically generated. Surprisingly, there are no errors reported by d3 or the browser. However, upon ...