Is there a way to sort results in AngularJS based on a subset of child results?

Imagine I possess the subsequent item:

{
    "bands": [{
        "name": "The Wibbles",
        "formed": 1992,
        "albums": [{
            "name": "A New Wibble",
            "songs": [{
                "name": "Song One",
                "time": "3:12"
            }, {
                "name": "Song Two",
                "time": "2:34"
            }, {
                "name": "Song Three",
                "time": "2:21"
            }, {
                "name": "Song Four",
                "time": "3:44"
            }, {
                "name": "Song Five",
                "time": "3:54"
            }]
        }, {
            "name": "The Wibbles Strike Back",
            "songs": [{
                "name": "Song Six",
                "time": "8:12"
            }, {
                "name": "Song Seven",
                "time": "7:34"
            }, {
                "name": "I Killed a Girl",
                "time": "8:21"
            }, {
                "name": "Monkey Fighters",
                "time": "7:44"
            }, {
                "name": "Funkallica",
                "time": "9:54"
            }]
        }]
    }]
}

If I were to utilize AngularJS (and possibly underscore.js), how could albums be organized by the shortest track, overall album length, or by the quickest average duration of the tracks in each album?

Subsequently, if a new band was to be introduced, how would the bands themselves be sorted based on these criteria (shortest track / album duration / average track duration)?

Answer №1

Arranging number strings in ascending order can be complicated, but we can definitely handle it. Consider the example presented in the HTML code below:

<div ng-repeat="band in bands">
  <h1>{{ band.name }}</h1>
  <div ng-repeat="album in band.albums">
    <h2>{{ album.name }}</h2>
    <ul>
      <li ng-repeat="songs in album.songs">
        <h3>{{ song.name }}</h3>
        <em>{{ song.time }}</em>
      </li>
  </div>
</div>

To sort the albums based on the shortest track:

<div ng-repeat="band in bands">
  <h1>{{ band.name }}</h1>
  <div ng-repeat="album in band.albums | orderBy:shortestTrackByAlbum">
    <h2>{{ album.name }}</h2>
    <ul>
      <li ng-repeat="song in album.songs">
        <h3>{{ song.name }}</h3>
        <em>{{ song.time }}</em>
      </li>
    </ul>
  </div>
</div>

To customize the sorting using a function with Angular's orderBy, pass the function itself (not the result) to the current Scope. In this case, use `orderBy:shortestTrackByAlbum'.

$scope.bands = [...];
$scope.shortestTrackByAlbum = function(album) {
  var times = [];
  for (var i = 0; i < album.songs.length; i++) {
    var minutesAndSeconds = album.songs[i].split(':'),
        m = parseInt(minutesAndSeconds[0], 10),
        s = parseInt(minutesAndSeconds[1], 10);
    times.push(m * 60 + s);
  }
  return Math.min.apply(null, times);
};

By converting the times to seconds from the data provided, we identify the smallest number of seconds among tracks. This smallest number is then compared with the smallest numbers of other albums for sorting.

This approach allows you to create functions for various scenarios. Refer to this Plunker for a basic illustration.

For user-controlled sorting, consider implementing the following:

<select ng-model="sortingMethod"
        ng-options="m.fn as m.name for m in methods"></select>

...
  <div ng-repeat="album in albums | orderBy:sortingMethod">
...
$scope.methods = [
  {
    name: 'Shortest Track',
    fn: $scope.shortestTrackByAlbum
  },
  {
    name: 'Total Album Length',
    fn: $scope.totalAlbumLengthByAlbum
  },
  {
    name: 'Shortest Average Length',
    fn: $scope.shortestAverageLengthByAlbum
  }
];

$scope.shortestTrackByAlbum = function(album) { ... };
$scope.totalAlbumLengthByAlbum = function(album) { ... };
$scope.shortestAverageLengthByAlbum = function(album) { ... };

Explore the documentation on Angular Filters and specifically Angular's OrderBy for more insights.

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

Changing the Class of an Element in a Different Component with Angular 2+

Currently in a project utilizing Angular 4, I have implemented two components: app.component and other.component Within app.component.html, there exists a div with the name attribute myClass. <div class="myClass"></div> In the other.componen ...

Top method for constructing a JSON object by combining data from two queries and a joining table

Currently, I am developing a small webservice in Node.js to handle commands in a restaurant using Express.js. In my database, I have the following tables: DISH(id,name) COMMAND(id,table,status) COMMAND_DISH(idCommand,idDish,quantity) I am interested in ...

Clever method for enabling image uploads upon image selection without needing to click an upload button using JQuery

Is there a way to automatically upload the file without having to click the upload button? Detail : The code below shows an input field for uploading an image, where you have to select the file and then click the "Upload" button to actually upload it: & ...

What is the reason that the Mongoose updateMany() function only functions properly when combined with .then

Currently delving into the intricacies of Mongoose, I am perplexed as to why updateMany() requires a .then() at the end in order to be executed. For instance, here is the snippet that I'm endeavoring to execute, with the intention of altering the rat ...

Updating the mat-icon in a row when a button is clicked

I am currently working on implementing the mat-table in my project. I am facing an issue where I need to change the mat-icon of a button based on a click event, but I only want this change to apply to a single row in the table. At the moment, I am able to ...

JavaScript and AJAX: Dynamically Create URLs

I don't have any experience with web development, so could you please explain in detail? If my questions are unclear, feel free to ask for more information. Imagine I have a webpage with the following URL: www.mycompany.com/category1 This page has ...

Instructions for validating an AngularJS input field using a textbox

I'm having an issue with allowing special characters in the ng-pattern of a textbox named "students." Here is the code snippet from the view file: <div ng-repeat="s in config.students"> <div class="form-group"> <label class ...

Getting the Value of an Object in an Array in My Angular Project

Within my Angular Application, I am receiving an array of objects from an API: "register":[ { "club": 8, "players": 100, "officials": 10 }, { "male": 7, "female": 2, "other": 1 }, { "Brazil": 5, "France": 1, "Italy": 2, "England": 2 } ] I want to specifi ...

Sliding the cursor downward to unveil a panel? (utilizing MooTools)

I'm looking to implement a feature where a DIV panel slides in when the user clicks and drags a smaller tab. While there are tutorials available for sliding elements on click, I specifically need the panel to slide in only when the user interacts with ...

Encountering the "Error: JSON.parse: unexpected character" when trying to retrieve JSON data using AngularJS

I've been struggling with this issue for the past few days. Every time I attempt to fetch a JSON object using Angular's $http.get method, I encounter the error message "Error: JSON.parse: unexpected character". The JSON data is generated using P ...

Can ng-packagr create scripts that are compatible with running in a web browser like regular JavaScript?

Is it feasible to utilize ng-packagr to compile a library into a single script file that can be executed on a web browser by importing it as <script src="bundle.js"></script>? For instance, if I have a main.ts file that contains cons ...

"Efficiently calculate the total sum of columns in a datatable using dynamic JavaScript across

For further clarification, this question is an extension of a previous inquiry, which can be viewed here. In the following code snippet, I am calculating the column sum of a Shiny datatable using Javascript in order to display it directly below the table. ...

Arrangement of bootstrap and CSS library in header has an impact on the styling of h3 Tag

After rearranging the order of the online Bootstrap and offline CSS library, I noticed an impact on the h3 element in my HTML document. To further clarify this conflict, let me provide more details. <link rel="stylesheet" href="https://maxcdn.boot ...

Struggling to find a way to connect individual points on a map

Looking for some guidance in d3 as a beginner. My goal is to plot a series of coordinates onto a map. After starting with Mike Bostock's airports voronoi map, I managed to get the base map set up successfully. The issue arises when trying to display ...

Utilizing asynchronous JavaScript imports within exported classes

Currently, I have a package with async/dynamic exports that I import in the following manner: (async function() { const libEd = await import("../../.cache/ed25519wars/index.js"); })(); I plan to re-expose certain functions from libEd within a class str ...

Experiencing difficulties when attempting to show or hide elements using jQuery

I spent several hours trying to figure this out and couldn't get it right. Is it feasible to create a jQuery script that will perform the following action when a <span> element is clicked: Check if any of the <p> elements are current ...

There seems to be a problem with the rendering of select options

React Component for Region Selection import React from 'react'; import { getRegions } from '../helpers' class RegionSelect extends React.Component { constructor(props) { super(props); this.state = { regions: [], ...

Ways to create a shorter upper line compared to the lower line (inside a div)

I'm dealing with an unordered list that has 3 list items, each represented by a green box containing an image and 3 divs (title, location, price). My main focus is on the title div of each box. If the title is long enough to span 2 lines, I need the ...

Using a factory function within a Typescript declaration file, both with and without the utilization of the new keyword

Here is an example of a factory function created in ES5: function MyClass(val) { if (!(this instanceof MyClass)) { return new MyClass(val); } this.val = val; } You can call this function with or without the new keyword: var a = new ...

Guide to successfully finish $.get() after submitting a form with jQuery

I'm currently utilizing a third-party shopping cart system that sends a registration form to a .cgi script. My goal is to send the form details to both me and the customer using a jQuery $.get() function call. The $.get method calls a registration.m ...