49

I'm using a UI.Bootstrap accordion and I've defined my heading like so:

<accordion-group ng=repeat="(cname, stations) in byClient">
    <accordion-heading>
        {{ cname }} <span class="pull-right"> {{ Object.keys(stations).length }} Stations</span>
    </accordion-heading>

When that displays the Object.keys(stations).length resolves to nothing. If I put that same length call in my controller I get back the expected count. Is there something preventing the method call from working in AngularJS?

The rest of the accordion that uses stations acts as expected, so I know that it's being populated properly. The byClient data structure basically looks like so:

{
    "Client Name" : {
        "Station Name": [
            {...},
            {...}
        ]
    }
 }
1
  • Try {{ (stations | keys).length }} stations Commented Jun 4, 2020 at 8:47

6 Answers 6

88

Yes, That is because Object is a part of window/global and angular cannot evaluate that expression against the scope. When you specify Object.keys in your binding angular tries to evaluate it against the $scope and it does not find it. You could store the reference of object.keys in some utility in rootScope and use it anywhere in the app.

Something like this:-

angular.module('yourApp',[deps...]).run(function($rootScope){
  //Just add a reference to some utility methods in rootscope.
  $rootScope.Utils = {
     keys : Object.keys
  }

  //If you want utility method to be accessed in the isolated Scope 
  //then you would add the method directly to the prototype of rootScope 
  //constructor as shown below in a rough implementation.

  //$rootScope.constructor.prototype.getKeys = Object.keys;

});

and use this as:-

<span class="pull-right"> {{ Utils.keys(stations).length }} Stations</span>

Well this will be available to any child scopes except for isolated scopes. If you are planning to do it on the isolated scope (eg:- Isolated scoped directives) you would need to add the reference of Object.keys on the scope, or as you expose a method on the scope which will return the length.

Or better yet , create a format filter to return the keylength and use it everywhere.

app.filter('keylength', function(){
  return function(input){
    if(!angular.isObject(input)){
      throw Error("Usage of non-objects with keylength filter!!")
    }
    return Object.keys(input).length;
  }
});

and do:-

{{ stations | keylength }}

Demo

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

7 Comments

Just as i would have said it +1
very nice. You have given two perfect solutions! Thanks :)
If you are using an isolate scope, you will need to use {{ $root.Utils.keys(stations).length }}
@AJRichardson That is a very good point you made there. What you can do is instead of adding it in the rootScope instance add it to the prototype. i.e $rootScope.constructor.prototype.getKeys = Object.keys. It should then be available in the isolate scope as well. Similar to what i did here
why this not exists by default in Angular, is so useful !
|
4

Use the function to determine the number of object properties:

$scope.keyLength = function (obj) {
    return Object.keys(obj).length;
}

and use:

{{ keyLength(myObj) }}

Comments

2

I think filters are the most AngularJS way of handling structures in template code:

angular.module('app.filters').filter('objectKeysLength', [function() {
    return function(items) {
        return Object.keys(items).length;
    };
}]);

angular.module('app.filters').filter('objectKeys', [function() {
    return function(item) {
        if (!item) return null;
        var keys = Object.keys(item);
        keys.sort();
        return keys;
    };
}]);

Comments

0

In case someone searches for angular 2 and higher solution. It now hat keyvalue pipe, which can be used to interate over objects

Comments

0

I could not get any of the other answers to work in AngularJS 1.6. What worked for me using $window to acccess Object.keys like this $window.Object.keys({ 'a': 1, 'b': 2 })

Comments

0

Here's a solution that worked for me :

export class xyzcomponent{
    Key = Object.keys;
}

Now in the component html file, you can use something like that :

<li *ngFor="let i of Key(stations)">.........</li>

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.