As @c0bra pointed out in the comments the form.$error
object is populated, it just doesn’t like being dumped out as JSON.
Looping through form.$errors
and it’s nested objects will get the desired result however.
<ul>
<li ng-repeat="(key, errors) in form.$error track by $index"> <strong>{{ key }}</strong> errors
<ul>
<li ng-repeat="e in errors">{{ e.$name }} has an error: <strong>{{ key }}</strong>.</li>
</ul>
</li>
</ul>
All the credit goes to c0bra on this.
Another option is to use one of the solutions from this question to assign unique names to the dynamically created inputs.