Search code examples
javascriptangularjsangularjs-ng-repeatangularjs-filtercontact-list

How do I use AngularJS to alphabetize a contact list with headers as the first character?


I have a list such as this

Aperson

Cperson

APerson2

BPerson

and I want it to appear as so

A

Aperson Aperson2

B

Bperson

C

Cperson

I found a post here explaining it: http://pmosd.blogspot.com/2013/07/headers-in-angularjs-ng-repeats.html

but as an Angular noob, I'm not sure where to place the function and filter in the js file and how to properly code it into my html. I tried following the post that I linked, but my unordered list with the contact names would not show up in the browser. Here are my current JS and HTML files. I have tried placing the filter and function in various places, but this is from my most recent attempt.

Directory.js:

'use strict';

var myApp = angular.module('myappname');

myApp.controller('DirectoryCtrl', function ($scope) {
    $scope.contacts = [{
        'fname': 'Randy',
        'lname': 'Johnson',
        'location': 'Seattle, WA'
    }, {
        'fname': 'Andy',
        'lname': 'Pettite',
        'location': 'Bronx, NY'
    }, {
        'fname': 'Jon',
        'lname': 'Lester',
        'location': 'Boston, MA'
    }];

});


myApp.filter("headerChunk", function () {
    return function (orig, same, getChunkID) {
        if (!(orig instanceof Array)) return orig;
        if (orig.length == 0) return orig;

        var result = [];

        var cur = [];

        var i = 0
        for (i = 0; i < orig.length; i++) {
            if (i == 0 || same(orig[i], orig[i - 1])) {
                cur.push(orig[i]);
            } else {
                result.push({
                    id: getChunkID(orig[i - 1]),
                    items: cur
                });

                cur = [orig[i]];
            }
        }

        result.push({
            id: getChunkID(orig[orig.length - 1]),
            items: cur
        });

        for (i = 0; i < result.length; i++) {
            result[i].$$hashKey = i;
        }

        return result;
    }
});

$scope.filteredData = $filter("headerChunk")(
    $scope.filteredData,

    // The first argument is a function 'same' that is responsible for determining
    // whether two objects of the collection belong in the same category. We desire
    // two persons to go in the same category is their names start with the same first
    // letter:
    function (p1, p2) {
        return (p1.name.charAt(0) == p2.name.charAt(0));
    },

    // The second function 'getChunkID' is responsible for "naming" the resulting chunk.
    // We wish for the chunks to be identified by the letter that their constituents'
    // names start with:
    function (p) {
        return p.name.charAt(0);
    }
);

directory.html:

<div ng-repeat="group in contacts | orderBy:name | headerChunk:sameFunc:idFunc">
<ul>
    <li ng-repeat="item in group.items">
      {{item.lname}}, {{item.fname}}<br>
      {{item.location}}
        <hr>
    </li>
</ul>

Not sure what to do anymore.


Solution

  • Did you read the comments? the first person did it with underscore.js, so do it with underscore.js or lodash.js.

    // include the script
    <script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>
    
    
    <div ng-repeat="(k,v) in sortedcontacts">
    <span>{{k}}</span>
    <ul>
        <li ng-repeat="item in v">
          {{item.lname}}, {{item.fname}}<br>
          {{item.location}}
            <hr>
        </li>
    </ul>
    </div>
    
    
    
    'use strict';
    
    var myApp = angular.module('myappname');
    
    myApp.controller('DirectoryCtrl', function ($scope) {
    $scope.contacts = [
        {'fname': 'Randy',
         'lname':'Johnson',
         'location': 'Seattle, WA'},
        {'fname': 'Andy',
         'lname':'Pettite',
         'location': 'Bronx, NY'},
        {'fname': 'Jon',
         'lname':'Lester',
         'location': 'Boston, MA'}
    ]; 
    
    $scope.sortedcontacts = _.groupBy($scope.contacts, function(item) {return item.fname[0]; });
    });
    
    // you don't need those filter codes