You can use the (key, value) in object syntax.
In your case :
<div ng-repeat="(key1, value1) in fields">
<li ng-repeat="(key2, value2) in value1">{{key2}} : {{value2}}</li>
</div>.
But :
You need to be aware that the JavaScript specification does not define
the order of keys returned for an object. (To mitigate this in Angular
1.3 the ngRepeat directive used to sort the keys alphabetically.)
Version 1.4 removed the alphabetic sorting. We now rely on the order
returned by the browser when running for key in myObj. It seems that
browsers generally follow the strategy of providing keys in the order
in which they were defined, although there are exceptions when keys
are deleted and reinstated. See
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_issues
If this is not desired, the recommended workaround is to convert your
object into an array that is sorted into the order that you prefer
before providing it to ngRepeat. You could do this with a filter such
as toArrayFilter or implement a $watch on the object yourself.
More details : https://docs.angularjs.org/api/ng/directive/ngRepeat
Edit : What if you want to change the object now ?
You can't do :
<div ng-repeat="(key1, value1) in fields">
<h3>{{key1}}</h2>
<li ng-repeat="(key2, value2) in value1">
<input ng-model="value2" /><br />
{{key2}} : {{value2}}
</li>
</div>
Why ? Because ng-model will change value2 in the current scope, and not in your object fields as you don't use dot notation.
For each item/iteration, ng-repeat creates a new scope, which
prototypically inherits from the parent scope, but it also assigns the
item's value to a new property on the new child scope.
More details : https://github.com/angular/angular.js/wiki/Understanding-Scopes
But you can do :
<div ng-repeat="(key1, value1) in fields">
<h3>{{key1}}</h2>
<li ng-repeat="(key2, value2) in value1">
<input ng-model="fields[key1][key2]" /><br />
{{key2}} : {{value2}}
</li>
</div>
Take a look !!!