Arranged list becomes depleted (Although Lodash's groupBy function still functions properly)

Check out the sample plunker here

Initially, I am grouping a collection by a specific key, which in this case is yob (year of birth).

I have two approaches:

  • I can create a custom function to group the collection, allowing for custom logic to be implemented
  • I can utilize _.groupBy function from lodash/underscore.js

I decided to test both methods - using lodash, I successfully grouped the collection by a key and the output can be seen in the plunker.

However, when I tried the custom method, specifically using studentsByYear, the array somehow becomes empty before being displayed. I have checked the output through console logging before returning the array, and it contains the desired data.

So, my question is why does my custom grouping method fail to work? Could I be overlooking something important in angular? Is it necessary to perform a deep copy of objects before returning them? If yes, please provide an explanation.


  <div ng-controller="myController">
    <h2> Using Lodash </h2>
    <ul ng-repeat="(yob, students) in myModel.studentsByYobLodash">
      <h3>{{ yob }}</h3>
      <div ng-repeat="s in students">
        <p> {{s.name}} </p>
      </div>
    </ul> 

    <h2>Not using Lodash </h2>
    <ul ng-repeat="(yob, students) in myModel.studentsByYob">
      <h3>{{ yob }}</h3>
      <div ng-repeat="s in students">
        <p> {{s.name}} </p>
      </div>
    </ul> 
  </div>

script

var app = angular.module("myApp", []);

app.factory('studentsFactory', [function () {
  var students = [{
    name: 'Tony',
    yob: '1987'
  },{
    name: 'Rachel',
    yob: '1988'
  }, {
    name: 'Eric',
    yob: '1988'
  }, {
    name: 'Jon',
    yob: '1988'
  }, {
    name: 'Tim',
    yob: '1989'
  }, {
    name: 'Bing',
    yob: '1987'
  }, {
    name: 'Valerie',
    yob: '1988'
  }, {
    name: 'Brandon',
    yob: '1987'
  }, {
    name: 'Sam',
    yob: '1987'
  }]

  return {
    getStudents: function () {
      return students;
    }
  }
}])

app.controller('myController', ['$scope', 'studentsFactory', function ($scope, studentsFactory) {
  $scope.myModel = [];
  $scope.myModel.students = studentsFactory.getStudents();

  $scope.myModel.studentsByYobLodash = studentsByYearUsingLodash($scope.myModel.students)
  $scope.myModel.studentsByYob = studentsByYear($scope.myModel.students);

  function studentsByYearUsingLodash (students) {
    return _.groupBy(students, 'yob');
  }

  function studentsByYear(students) {
    var arr = [];
    angular.forEach(students, function (student) {
      var key = student.yob;
      _.has(arr, key) ? arr[key].push(student) : (arr[key] = [student]);
    })

    return arr;
  }
}])

Answer №1

By structuring your code in this way, you are utilizing the key, value method for object iteration within ng-repeat. Sending myModel.studentsByYob as an array will result in an array with gaps, since some elements will be undefined. This is because the array object has properties like 1987, 1988, etc. which point to arrays of students. If you inspect the browser console, you will see the ng-repeat code highlighting errors due to the presence of multiple undefined keys. To address this issue, simply change:

var arr = [];

to

var arr = {};

View Plunkr example

Answer №2

There is an issue that arises when you initialize the arr variable inside the studentsByYear() function:

var arr = [];

It should actually be:

var arr = {};

Angular treats arrays and objects differently in iterators. When iterating over an array that does not start at index 0, using (key, value) will result in an unset key. Angular considers undefined == undefined, leading to a duplicate key error.


Interestingly, you could technically avoid this error once if your years of birth were:

[1, 2, 3, 4...] instead of [1987, ...]

In that case, you would not encounter an error, just an empty "0" at the top of your list.

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

However, if you have 2 non-sequential indices like:

[2, 3, 4...] // 0 and 1 are missing

then you will encounter the error again because 0 == undefined and 1 == undefined, resulting in 0 == 1 and triggering a duplicate error.

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

What is the best way to retrieve the innerHTML content of an anchor tag with Cheerio?

Looking to extract data from an HTML page, a simplified example is provided below. Upon running the code, I anticipate the output to be [ "foo", "baz", "quux", ] but instead encounter an error message stating "TypeError: anch ...

Make changes to the model and chosen selection of a dropdown menu created with ng-options

I've been stuck in this endless loop trying to figure this out - any assistance would be greatly appreciated. I'm looking to modify the model and selected option of a select menu that is created using ng-options. These are the values for the op ...

Tips on sending image information from node.js to an HTML5 canvas?

Currently in the process of developing a demo featuring a node.js C++ plugin, I encounter an issue with the conversion of an ARGB bitmap to RGBA format for HTML5 canvas integration. The performance of this conversion process is exceedingly slow, prompting ...

Close the parent electron window while keeping the child window open

I am currently working on a project where I need to create an electron app that displays a splash screen initially and then opens a new window before closing the splash screen. However, despite my efforts, I am facing challenges in achieving this functio ...

Contrast and combine information from two JavaScript arrays of objects

I am struggling with comparing two arrays of objects based on a key. My goal is to compare the values, subtracting them when the keys match and displaying negative values for those not found in my target array. Additionally, I want to include all target o ...

Effortless scrolling implementation

How can I make the scroll smooth and animated with this code structure? Check out my JSFiddle here: https://jsfiddle.net/v7qhzo8q/ The code structure is as follows: <nav id="nav"> <ul id="top"> <li><a href="#">Home</a> ...

Displaying a variety of images using a random generator in Ionic 1 / Cordova with ng-src

Currently, I am working with Ionic 1 / Cordova and facing an issue. I am attempting to choose a random image from an array to showcase on the page (making sure it changes every time the user visits). I have managed to make it randomly select a URL from the ...

What is preventing the function from successfully compiling text from various files that are uploaded using the HTML5 file reader into an array?

My current challenge involves attempting to upload two text files using the HTML 5 file reader. While I can successfully get the files into an array, encountering difficulty arises when trying to return that array from the function. One solution could be ...

The addition of the woocommerce_add_to_cart action is causing issues with the website's native add to cart

After creating a node express API that listens for post requests from the woocommerce_add_to_cart webhook, I noticed that the payload it receives is not very useful. body:{ action: 'woocommerce_add_to_cart', arg:'098uoijo098920sa489983jk&ap ...

Why isn't httpUploadProgress functioning correctly with Buffer data?

Recently, I have ventured into the world of node.js/express as I am attempting to create a multiple image uploading application utilizing cloudfront and an s3 bucket. My goal is to display a progress bar for the user by integrating socket.io for real-time ...

Creating a unique shader in Three.js to seamlessly blend with the default rendering algorithm

Looking to improve performance, my goal is to showcase hundreds of moving tetrahedrons in a scene by using instancedbuffergeometry along with a custom shader. Within the scene, there are also objects with regular geometry (non-buffer) and some lights. To ...

Capturing AJAX responses within a Chrome Extension

We are currently in the process of developing a Chrome extension to enhance an existing system by simplifying various tasks. This extension will heavily utilize AJAX technology, making it more efficient compared to web scraping or manually triggering even ...

Removing a delete option in ReactJs excluding the Component

Can someone help me with this issue? I am trying to use the delete button but I keep receiving an error. Thank you in advance for your assistance. Below is the code where I am trying to access the properties of a Toy class parent and then delete by Id usi ...

What are some ways to disable text selection when working with VueJS?

Let's say I have a component that displays some text. When I click on the text at the beginning and then shift-click on another part, the text between those two points gets selected. Is there a way to prevent this behavior using only VueJS? ...

Storing API data in localStorage using VueJS: A step-by-step guide

As I work on practicing building a simple SPA with VueJS, one of my current tasks involves listening to an API and storing certain data in the browser's localStorage. However, my experience with VueJS is still limited, so I'm unsure about how to ...

The command "npm run build" is not running successfully, likely due to npm not being able to interpret ES6 syntax

I am currently developing a web application using Vue.js and Flask. While I can successfully compile the Vue app on my laptop by running npm run build and integrating the static files into my Flask app, I encounter an issue when attempting to do this on a ...

Conceal a column within a table by double-clicking

I'm working on a project with a table, and I'd like to implement a feature where a column hides when double-clicked. I've seen various solutions for hiding columns on Stack Overflow, but I could use some guidance on where to add the ondblcli ...

Using angular.copy function to copy an array with a custom property

Let's use the example below to illustrate an issue: var ar = [4, 2, 3]; ar.$x = 'something'; var br = angular.copy(ar); console.dir(br); After copying ar to br, the $x property is no longer present. This is because when Angular copies an a ...

Invoke a C# function (returning a string) within ASP.NET to set the source attribute for an HTML element

I have developed some C# Methods that return a string output, such as "C:/tracks/audio1.mp3", and I want to use this as a reference for my ASP.NET project. Now, I am trying to incorporate my method "GetTrackPath()" into the HTML audio tag so that the meth ...

Unable to open drop-down menu in Bootstrap-select on ASP.NET web application by clicking

Currently, as I work on developing an ASP.NET web application, I find myself facing significant challenges in getting the bootstrap-select feature to function correctly. Despite browsing through various threads on SO for solutions, the problem remains unr ...