2

I'm trying to build a list of people with dividers for each letter (similar to a phone's address book).

people = ['Angela','Annie','Bob','Chris'];

Result:

A
Angela
Annie
B
Bob
C 
Chris

I want to do something similar to this pseudocode using Angular:

<div id="container" ng-init="lastCharacter = ''">
   @foreach(person in people)
      @if(firstCharacter(person.name) != lastCharacter)
         <div class="divider-item">{{firstCharacter(person.name)}}</div>
         {{lastCharacter = firstCharacter(person.name)}}
      @endif
      <div class="person-item">{{person.name}}</div>
   @endforeach
</div>

What is the easiest way to achieve this? I couldn't come up with an elegant solution using ng-repeat.

2 Answers 2

1

You should create a custom filter and move the grouping logic inside that:

app.filter('groupByFirstLetter',function(){
  return function(input){
    var result = [];

    for(var i = 0;i < input.length; i++){
      var currentLetter = input[i][0]

      var current = _.find(result, function(value){
        return value.key == currentLetter;
      });

      if(!current){
        current = {key: currentLetter, items: []}
        result.push(current);
      }

      current.items.push(input[i]);
    }


    return result;
  };
});

Then the view gets simple:

    <div ng-repeat="personGroup in people | groupByFirstLetter">
      <div class="divider-item">{{personGroup.key}}</div>
      <div class="person-item" ng-repeat="person in personGroup.items">
        {{person}}
      </div>
    </div>

Here's a little working example in plunker : http://plnkr.co/edit/W2qnTw0PVgcQWS6VbyM0?p=preview It's working but it throws some exceptions, you will get the idea.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for responding. This solution causes the "personGroup in people..." div to repeat for each letter group. Is there a solution that does not require a container? <div class="divider-item">A</div><div class="person-item">Angela</div><div class="divider-item">B</div><div class="person-item">Bob</div>
@KyleT I updated it with ng-repeat-start plnkr.co/edit/0v9tNtYcUgS6t5OBXUne?p=preview
1

try (use sorted list)

<div id="container" ng-repeat="person in people">
         <div class="divider-item" 
              ng-if="$index == 0 || ($index > 0 && firstCharacter(person.name) != firstCharacter(people[$index-1].name))">{{firstCharacter(person.name)}}</div>

         <div class="person-item">{{person.name}}</div>
</div>

hope, you have firstCharacter function defined in scope. Or you can simpley use person.name.charAt(0).

edit: as this will contain id container for all person. so best would be using an inner div inside container and run ng-repeat on there

<div id="container" >
    <div ng-repeat="person in people">
         <div class="divider-item" 
              ng-if="$index == 0 || ($index > 0 && firstCharacter(person.name) != firstCharacter(people[$index-1].name))">{{firstCharacter(person.name)}}</div>

         <div class="person-item">{{person.name}}</div>
    </div>
</div>

3 Comments

i have rewritten the ng-repeat part. please check
This causes the container to repeat with each person. I only need the container once.
you can wrap ng-repeat in a inner div

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.