AngularJS中ngRepeat如何跳过$$hashKey?动态表格列名问题
Let's break down your issues step by step, starting with a recap of your setup: you're trying to dynamically generate tables from an object where each category (from the categories array) maps to an array of items. Right now, you're seeing an unexpected $$hashKey column even though you added an ng-if condition to exclude it, and you're unsure about the proper way to fetch column names.
Your Data Structure
{ categories: ["kids", "home"], home: [ { name: "home 1.1", title: " home1.2" }, { name: "home 2.1", title: "home 2.2" }, { name: "home 3.1", title: "home 3.2" }, { name: "home 4.1", title: "home 4.2" }, { name: "home 5.1", title: "home 5.2" } ], kids: [{ name: "kids 1.1", title: "kids 1.2" }] }
Your Current Code
JavaScript
var app = angular.module("app", []); app.controller("MainCtrl", function($scope) { $scope.data = { /* ... your data as above ... */ }; $scope.getKeys = function(obj) { if (!$scope.data.hasOwnProperty(obj)) { return []; } return Object.keys($scope.data[obj][0]); } });
HTML
<html ng-app="app"> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js"></script> </head> <body ng-controller="MainCtrl"> <table ng-repeat="d in data.categories"> <tr> <th ng-repeat="l in getKeys(d)" ng-if="$index != getKeys(d).length - 1"> {{$index != getKeys(d).length - 1}} {{l}} </th> </tr> <tr ng-repeat="k in data[d]"> <td>{{k.name}}</td> <td>{{k.title}}</td> </tr> </table> </body> </html>
1. Why is the $$hashKey column showing even when the ng-if condition is false?
First, know that AngularJS automatically adds a $$hashKey property to objects in arrays used with ng-repeat—this helps it track items efficiently for updates. When you call Object.keys($scope.data[obj][0]), it includes this internal property, making your keys array longer than you intended.
As for why your ng-if isn't hiding it: Angular runs frequent digest cycles, and every cycle re-executes your getKeys(d) function. This means the array returned by getKeys is a new reference each time, causing ng-repeat to re-render the <th> elements. The $index and getKeys(d).length don't align consistently during these cycles, so the final column (with $$hashKey) slips through.
On top of that, object key order wasn't guaranteed in older JavaScript versions, so assuming $$hashKey is always the last key isn't reliable even if the digest cycle wasn't an issue.
2. What's the correct way to get table column names?
You need to explicitly exclude Angular's internal properties like $$hashKey when fetching your column keys. Here are three solid approaches:
Option 1: Filter out internal properties in getKeys
Modify your getKeys method to exclude any keys starting with $$ (Angular's convention for internal properties):
$scope.getKeys = function(obj) { if (!$scope.data.hasOwnProperty(obj) || $scope.data[obj].length === 0) { return []; } // Filter out keys starting with $$ return Object.keys($scope.data[obj][0]).filter(key => !key.startsWith('$$')); };
Now you can remove the ng-if entirely from your <th> since $$hashKey is never included in the keys array:
<th ng-repeat="l in getKeys(d)"> {{l}} </th>
Option 2: Use angular.toJson to strip internal properties
Angular's angular.toJson method automatically removes properties starting with $$. Convert the object to JSON and parse it back to get a clean version:
$scope.getKeys = function(obj) { if (!$scope.data.hasOwnProperty(obj) || $scope.data[obj].length === 0) { return []; } // Strip internal properties and get keys const cleanObj = angular.fromJson(angular.toJson($scope.data[obj][0])); return Object.keys(cleanObj); };
Option 3: Preprocess data upfront
If you don't need $$hashKey at all, preprocess your data to remove these properties when initializing:
// In your controller Object.keys($scope.data).forEach(key => { if (Array.isArray($scope.data[key])) { // Clean each item in the array $scope.data[key] = $scope.data[key].map(item => angular.fromJson(angular.toJson(item))); } });
Your original getKeys function will now work without modification, since $$hashKey is already removed from all items.
Bonus: Make table rows fully dynamic
Right now you're hardcoding <td>{{k.name}}</td> and <td>{{k.title}}</td>. To make this fully dynamic (so it works even if your item structure changes), replace those with another ng-repeat using the keys you retrieved:
<tr ng-repeat="k in data[d]"> <td ng-repeat="key in getKeys(d)">{{k[key]}}</td> </tr>
内容的提问来源于stack exchange,提问作者Saeed

