1

I am new to angular JS and wanted to use that to handle a json passed by ajax. To start with, I have made this testing code to make sure the data can be displayed correctly:

<head>
    <script src="path/to/angular.js"></script>
    <script>
        var app = angular.module('pageApp', []).config(function($interpolateProvider){
            $interpolateProvider.startSymbol('<<').endSymbol('>>');
        });
    </script>
</head>
<body ng-app="pageApp">
    <div class="container" ng-controller="tagging">
        Text input:<textarea ng-model="description" ng-change="checkTag()" required></textarea><br>
        Tag found om database: <span ng-repeat="tag in tags"> << tag >> </span><br>
    </div>
</body>

<script>
    //$http is not used now but will be used in the actual ajax handling.
    function taggingController($scope, $http)  {
        $scope.tags = [];
        $scope.checkTag = function () {
            var hardCode = [];
            hardCode[1] = "one";
            hardCode[3] = "three";
            hardCode[5] = "five";
            angular.forEach(hardCode, function(value, key) {
                console.log($scope.tags[key]);
                $scope.tags[key] = value
            });
        };
    };

    app.controller("tagging", taggingController);

</script>

However, the code doesn't work and gives the following error:

Error: [ngRepeat:dupes] Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: tag in tags, Duplicate key: undefined:undefined, Duplicate value: undefined

When the array is changed to index of consecutive numbers, it works. i.e.

hardCode[1] = "one";
hardCode[2] = "three";
hardCode[3] = "five";

Did I missed anything or Angular JS simply don't have the ability to handle non-consecutive number indexed array?

5
  • what are you hoping to accomplish by setting your own indices with gaps in them? Commented Jan 26, 2015 at 5:27
  • The actual array is set when a json is returned from server through ajax, where the index is the id of that tag entry. Commented Jan 26, 2015 at 5:29
  • well then it is an object if it is being json_encoded it will look like {3:"three", 5:"five"}. This sort of indexing is not needed much. Far more common to have array of objects like [{id:3,txt: "three"},{id:5,txt:"five"}] Commented Jan 26, 2015 at 5:30
  • Yes, then I will loop through the objects to set my array. The actual json is like {3:{word: "three", another long list of properties}, 5:{word: "five", another long list of properties}} Putting it in an array with only the properties needed improves readability. Also, It is not a direct assign. Using array to store item helps deduplication by setting actualArray[index] = $return_json['word'] Commented Jan 26, 2015 at 5:36
  • yes, and length is available to count them, easy to push to an array and can't sort objects etc Commented Jan 26, 2015 at 5:38

2 Answers 2

7

Angular tries to determine if the object is array like object or not. Once it determines, it sets its trackBy property based on the first predicate. Then it builds its collection.

if (isArrayLike(collection)) {
        collectionKeys = collection;
        trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
      } else {
        trackByIdFn = trackByIdExpFn || trackByIdObjFn;
        // if object, extract keys, in enumeration order, unsorted
        collectionKeys = [];
        for (var itemKey in collection) {
          if (collection.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
            collectionKeys.push(itemKey);
          }
        }
      }

after that it uses a regular for loop

for (index = 0; index < collectionLength; index++) {

You can see the code here: angular-ngRepeat directive

Because angular determines you are using an array like object, it tries to iterate through the array, index by index, and it runs into undefined. If you have to use array with 'holes' in it and use ng-repeat, you should consider using an object instead of an array:

        var hardCode = {};
        hardCode["1"] = "one";
        hardCode["3"] = "three";
        hardCode["5"] = "five";
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your suggestion of changing [] to {}. This is exactly what I wanted. The explanation is great too.
1

The problem is you have two undefined in the array in the index 2 and 4. In order to resolve this either add values to those indexex 2 and 4 or, track the ng-repeat by index like below

<span ng-repeat="tag in tags track by $index"> << tag >> </span><br>

Comments

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.