Mistalis Mistalis - 1 month ago 6
AngularJS Question

Group by on a complex object in AngularJS

I've an array that contains assignments of employees on tasks, it looks like something like this:

$scope.assignments = [
{
employee: {
id:"1", firstname:"John", lastname:"Rambo"
},
task: {
name:"Kill everyone", project:"Destruction"
},
date: {
day:"01/01", year:"1985"
}
},
{
employee: {
id:"2", firstname:"Luke", lastname:"Skywalker"
},
task: {
name:"Find daddy", project:"Star Wars"
},
date: {
day:"65/45", year:"1000000"
}
},
{
employee: {
id:"1", firstname:"John", lastname:"Rambo"
},
task: {
name:"Save the world", project:"Destruction"
},
date: {
day:"02/01", year:"1985"
}
}
];


I would like to group by employee, for having something like this:

$scope.assignmentsByEmployee = [
{ //First item
id:"1",
firstname:"John",
lastname:"Rambo",
missions: [
{
name:"Kill everyone",
date:"01/01",
year:"1985"
},
{
name:"Save the world",
date:"02/01",
year:"1985"
}
]
},
{ //Second item
id="2",
firstname:"Luke",
lastname:"Skywalker",
missions: [
name:"Find daddy",
date:"65/45",
year:"1000000"
]
}
];


Is their a simple way to do this ? I tried something with a double
forEach
, but it leads me nowhere.

Hope I'm understandable :)

Thanks !

Answer

You should just be able to loop through the assignments array and create a 'keyed array' (which just means using an object in JavaScript) on employee ID. Then you just fill up the missions array as required.

Something like

// initialise a holding object
var assignmentsByEmployee = {};

// loop through all assignemnts
for(var i = 0; i < $scope.assignments.length; i++) {
    // grab current assignment
    var currentAssignment = $scope.assignments[i];
    // grab current id
    var currentId = currentAssignment.employee.id;

    // check if we have seen this employee before
    if(assignmentsByEmployee[currentId] === undefined) {
        // we haven't, so add a new object to the array
        assignmentsByEmployee[currentId] = {
            id: currentId,
            firstname: currentAssignment.employee.firstname,
            lastname: currentAssignment.employee.lastname,
            missions: []
        };
    }

    // we know the employee exists at this point, so simply add the mission details
    assignmentsByEmployee[currentId].missions.push({
        name: currentAssignment.task.name,
        date: currentAssignment.date.day,
        year: currentAssignment.date.year
    });
}

These leaves assignmentsByEmployee as an object, but you can simply foreach through it and convert it back to an array if required. E.g:

$scope.assignmentsByEmployee = [];
for(var employeeId in assignmentsByEmployee) {
    $scope.assignmentsByEmployee.push(assignmentsByEmployee[employeeId]);
}