Chromium browsers exhibit strange behavior with AngularJS orderBy, causing issues with clearing sorting selections

There is a particular issue that is really frustrating me in one of my projects.

The code I have is quite similar to this example (I tried to replicate it as closely as possible, but the actual code doesn't seem to be relevant because I can't reproduce the issue there anyway): http://plnkr.co/edit/SCUCsxLgu2zFzMhZ0whs?p=preview

The problem arises when I set predicate='' - the sorting doesn't completely clear. Angular seems to rearrange my elements in a different order (as seen in this screenshot with predicate=''):

When I removed the orderBy, everything displayed in the correct order (similar to how it was retrieved from the repository). Despite numerous attempts with orderBy, I couldn't fully reset the sorting.

I came across a similar case here: AngularJS ngRepeat orderBy in Chrome, but it turns out that my situation is not related to that specific issue.

Being patient, I delved into the angular.js file (AngularJS v1.3.15) for debugging purposes. The critical line appears to be:

return slice.call(array).sort(reverseComparator(comparator, reverseOrder));

Before slice.call(array), the array maintains its order. However, the result gets jumbled up after executing the sort function. This prompted me to do the following:

function comparator(o1, o2) {
  for (var i = 0; i < sortPredicate.length; i++) {
    var comp = sortPredicate[i](o1, o2);
    if (comp !== 0){
      console.log(7);  // <---------------------
      return comp;
    }
  }
  console.log(0);      // <---------------------
  return 0;
}

function reverseComparator(comp, descending) {
  return descending
      ? function(a, b) {return comp(b,a);}
      : comp;
}

To my surprise, on setting predicate='', my console outputs only zeros. Additionally, running:

slice.call(array).sort

...yields:

function sort() { [native code] }

So, the reason behind this unexpected sorting remains unknown to me. Interestingly, this issue only occurs in Chromium-based browsers (tested on Chrome and Opera). FireFox and IE11 clear the sorting as expected.

Initially, I considered this to be a bug in Chromium, yet I haven't been able to replicate it in the Plnkr setup. I'm left wondering if there's something different about the data that could be causing this discrepancy...

I even tried disabling all my Chrome extensions, but it had no impact on the issue either.

Given the popularity of both Chromium and Angular, has anyone else encountered this anomaly before?

Any insights or suggestions on what might be causing this issue would be greatly appreciated!

UPDATE:

Finally, I believe I've managed to reproduce the problem by adding more items to my array. Check it out here: http://plnkr.co/edit/SCUCsxLgu2zFzMhZ0whs?p=preview

(celebration time! :D)

I plan to report this to the Angular team in hopes that they, being Google, might address and resolve this issue with Chromium as well. :D

Answer №1

According to the ECMAScript guidelines

It is important to note that the sorting process may not be stable, meaning elements that are equal in comparison may not stay in their original order.

Therefore, it's crucial to understand that this behavior is intentional and not a browser bug.

When examining the Angular code, special consideration is given to an empty predicate:

if (predicate === '') {
  // By treating an empty predicate as no predicate at all, we can compare identity
  return reverseComparator(compare, descending);
}

The function for compare looks like this:

function compare(v1, v2) {
  var t1 = typeof v1;
  var t2 = typeof v2;
  if (t1 === t2 && t1 === "object") {
    v1 = objectToString(v1);
    v2 = objectToString(v2);
  }
  ...

The objectToString function is defined as follows:

function objectToString(value) {
  if (value === null) return 'null';
  if (typeof value.valueOf === 'function') {
    value = value.valueOf();
    if (isPrimitive(value)) return value;
  }
  if (typeof value.toString === 'function') {
    value = value.toString();
    if (isPrimitive(value)) return value;
  }
  return '';
}

If your objects do not have their own valueOf or toString methods, they will end up being considered equal (likely resulting in "[object Object]"). This aligns with the specifications outlined by ECMAScript.

Answer №2

After much consideration, I have decided to implement a solution using custom filters like the following:

(function () {

    function isStringEmpty(str) {
        return str === '' || str === undefined || str === null;
    }

    angular.module('CustomFilters', [])
        .filter('okOrderBy', ['$filter', function ($filter) {

            return function (array, predicate, reverse) {
                if (isStringEmpty(predicate)) return array;
                return $filter('orderBy')(array, predicate, reverse);
            };
        }
        ])
        .filter('arrayOrderBy', [function () {

            function Comparator(predicate, reverse) {
                return reverse ? function (a, b) {
                    a = a[predicate];
                    b = b[predicate];
                    if (a === b) return 0;
                    return a < b ? 1 : -1;
                } : function (a, b) {
                    a = a[predicate];
                    b = b[predicate];
                    if (a === b) return 0;
                    return a < b ? -1 : 1;
                };
            }

            return function (array, predicate, reverse) {
                if (isStringEmpty(predicate)) return array;
                return array.slice(0).sort(new Comparator(predicate, reverse));
            };
        }
        ]);

})();

The second approach functions independently of Angular filters and personally, I find it more appealing.

However, it has limitations such as only working with arrays of objects, requiring property names as predicates, and not accommodating "multiple column" sorts. On the other hand, the first option should be versatile enough to handle a wider range of scenarios.

I faced a tough decision when determining which answer to accept since all responses were valuable and enlightening. I appreciate the contributions from everyone involved. Ultimately, I am leaning towards selecting this particular answer for its efficiency in addressing the issue compared to the alternative proposed by user "YOU."

Answer №3

Here's a different strategy. Avoid sorting when it's not necessary.

It's great that Angular allows such flexibility.

<tr ng-repeat="friend in (predicate ? (friends | orderBy:predicate:reverse) : friends)">
  <td>{{friend.name}}</td>
  <td>{{friend.phone}}</td>
  <td>{{friend.age}}</td>
</tr>

http://plnkr.co/edit/KIdAKPtA3JDtRMDD50VI?p=preview

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

Experiencing excessive memory usage when attempting to load a large JSON file in Firefox

We are in the process of developing a client-based application using HTML5 and indexedDB on Firefox 28. When large amounts of data are loaded to Firefox for the first time using AJAX requests in JSON format, each JSON response is approximately 2MB (gzipped ...

failed to succeed when attempting to yarn install

For the past few days, I've been facing difficulties installing my dependencies using my package.json due to CPP errors. The installation process fails consistently with npm install. 1 error generated. make: *** [Release/obj.target/binding/src/binding ...

in node.js, virtual machine scripts can import modules using the require function

I am currently developing a command-line interface using node.js that runs an external script > myapp build "path/to/script.js" myapp is a node.js application that executes the script provided as a command-line argument. In simple terms, it performs ...

Displaying different elements using an anchor <a> tag

Within this example, I've created two functional components that mimic separate pages with differently colored <div> boxes. const Home = () => <div style={{background:'red', height: 100, width: 100}}></div>; const ...

Assigning a background image based on the quantity of items in an array or object

I'm having trouble appending divs and setting their background image based on the number of items in an array or object. Despite adding the divs correctly, all of them end up with the same background image when only three should have it. Can someone e ...

"Developing an Ionic app that utilizes Angular to send POST requests to a socket

I had a functional ionic app that communicated with a node server running a socket.io server. The socket server is receiving the POST request, but the body is empty. It used to work flawlessly. I can successfully send data using a REST client (like PAW o ...

Using jQuery to calculate mathematical operations in a form

I've been working on creating a form that calculates the total cost based on selected options. So far, I've managed to get it working for three options, but I'm stuck on how to calculate the subtotal by adding the variables "vpageprice" and ...

Struggling to make a click event work in aframe

Attempting to develop an inventory system for a game using the AFrame library has been quite challenging. I have a specific custom component in place that should make the item I am picking up invisible while making the in-hand item visible. However, for so ...

"Learn the steps to enable a click-to-select feature for an item, allowing you to drop it in a different location

I've been spending quite some time trying to come up with a solution for my dilemma. The issue arises because I'm not looking to use drag and drop functionality. https://i.stack.imgur.com/Nh1Db.png My goal is to have 3 divs named 1,2,3 as desig ...

Troubleshooting issue with ng-hide in AngularJS when using multiple filters

I'm struggling to implement two filters using ng-hide. Check out this fiddle where I've showcased the issue: http://jsfiddle.net/czPf6/2/ I have a piece of code that dynamically selects which filter to use based on input values from an input box ...

Can we utilize conditions to both select and deselect items using JavaScript and PHP together?

I have a selection list with checkboxes that is dynamically generated based on certain conditions in the code snippet below. if ($data_inteiro_01 <= $data_inteiro_02) { if ($parcela[$i] === 0) { $display = 'disabled'; } } els ...

Using Titanium for Android to Display High-Quality Images

My goal is to showcase a high-resolution image (minimum size of 2000x2000) on an Android device using Titanium, allowing users to scroll around it similar to a scroll view on iOS. However, I am aware that Android does not offer the same type of scroll view ...

React Scheduler by Bryntum

After successfully discovering some functions related to various actions, I find myself still in need of additional functions: Currently, I am utilizing these functions by passing them directly as props to the Scheduler React Component: - onBeforeEventSa ...

Issues with Line Chart in D3: Scaling and Zoom not functioning as expected due to ClipPath limitations

I am utilizing D3 version 4 to process data and create a graph based on dates. Although I have successfully adjusted everything to be compatible with zoom functionality, I am struggling to prevent the line from extending beyond the chart axes. I would pre ...

What sets apart elem['textContent'] from elem.textContent?

When dealing with a HTMLElement in JavaScript, is there any distinction between the following lines of code: elem['textContent'] = "Test"; versus elem.textContent = "Test"; This question arises when setting the text content of an HTMLElement. ...

Alter the datatype of a struct's array of pointers in real-time

I am currently working on coding an array of pointers for variables within a struct. The issue I am facing is that the variables in the struct have varying data types. #include "stdlib.h" typedef struct val { unsigned char a; unsigned char b; unsigned ...

Instructions on changing class when input length is not equal to zero

Is there a way to dynamically add a class to an input[type="email"] when its length is greater than 0 and remove it when the input length reaches 0? I'm not very proficient in JavaScript, so the solution could be implemented using vue.js or pure Java ...

How to categorize an array of objects based on a specific property while preserving the original object attributes

I have an array of objects with a specific property that I want to group by. My objective is to create a new array where all the objects have the same properties, but with an additional property that combines all the "value" properties into an array. Here ...

How can you ensure that the results are displayed only when all the fields in the form are properly

Take a look at the code below: <html> <head> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js" type="text/javascript"></script> <script type="text/javascript"> $(document).ready(function(){ ...

React hooks causing the for loop to only work on the second iteration

I am working on a project where I need to implement tags, similar to what you see on this website. Before adding a tag, I want to ensure that it hasn't already been selected by the user. I have set up a for loop to compare the new tag with the existin ...