2

I generate forms by ng-repeat-ing over an array. Every generated form is added to an vm.forms object. When removing an item from the array I'm iterating over the corresponding form is removed, but the vm.forms object still has a key for the original form, causing me undefined errors.

angular
    .module('myApp', [])
    .controller('FormLooper', FormLooper);

function FormLooper() {
    var vm = this;
    
    vm.children = [{
        name: 'Sarah',
        age: 9,
    }, {
        name: 'John',
        age: 13,
    }];
    vm.removeChild = removeChild;
    vm.forms = {};
    vm.showSummary = false;
    vm.triggerError = triggerError;

    function triggerError() {
        console.log('Available forms:', vm.forms);
        console.log('property names:', Object.getOwnPropertyNames(vm.forms));

        Object.getOwnPropertyNames(vm.forms).map(function(key) {
            console.log('key', key, vm.forms[key]);
            return vm.forms[key].$valid; // This will result in an `undefined` error
        });
    }

    function removeChild(index) {
        vm.children.splice(index, 1);
    }
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.6/angular.min.js"></script>
<body ng-app="myApp">
    <div ng-controller="FormLooper as vm">
        <div ng-repeat="child in vm.children">
            <form name="vm.forms.formId{{ $index }}">
                <label>
                    Name: <input ng-model="child.name">
                </label>
                <br>
                <label>
                    Age: <input type="number" ng-model="child.age">
                </label>
            </form>
            <button ng-click="vm.removeChild($index)">RemoveChild</button>
        </div>
        <button ng-click="vm.triggerError()">Trigger Error (check your console output)</button>
    </div>
</body>

Or, the same code as a JSFiddle: http://jsfiddle.net/Tobbe/8eohL2nq/2/

Shouldn't angular delete the entire object property?

I could solve this by manually delete-ing the object property in the removeChild function, but in my actual code I don't want to mix these concerns like that. Another simple solution is to just check for undefined or similar in the function that map calls. But it doesn't feel like I should have to resort to that...

So, am I missing something here?

EDIT:

Please pay attention to the console output and notice that the vm.forms object is properly populated when the forms are created. Angular does this all on its own :) So it adds to the object when the forms are created, but it doesn't delete from the object when the forms are removed. Is this a bug?

2
  • You seem to never really init vm.forms (not in js at least) Commented Apr 21, 2016 at 14:12
  • I do vm.forms = {};. Isn't that enough? Commented Apr 22, 2016 at 8:00

2 Answers 2

1

You are working with apples and peaches...

You try to use vm.forms.formid{{$index}} which will search for an vm.forms object. Which you never initialize.

You have two options: 1. Work with the children array:

<div ng-repeat="child in vm.children">
            <form name="vm_forms_formId{{ $index }}">
                <label>
                    Name: <input ng-model="child.name">
                </label>
                <br>
                <label>
                    Age: <input type="number" ng-model="child.age">
                </label>
            </form>
</div>

which will give you valid form names (you could also use IDs of the children).

  1. Use both forms array and children array. But you should init the forms object first...
Sign up to request clarification or add additional context in comments.

7 Comments

I'm not seeing what you changed in option 1, except for dots to underscores in the form name. But after that change, what would the loop in triggerError look like?
For option 2. Isn't that exactly what I'm doing?
In my understanding, angular does save a value inside of vm.forms.formId0 which represents the form itself (but from an angular perspective not the dom itself). So vm.forms.formId0 = {some complex object, with ie. validation values etc.). And when you remove an item from the children array, angular watches this and manipulates the dom. The complex object you referenced in vm.forms.formId0 becomes null or empty. (vm.forms.formId0 = {}) but vm.forms[formId0] still exists
I just don't understand why you need the form object? If you really do, splice the vm.forms object as well.
Yes, vm.forms[formId0] still exists, but its value is undefined. (Not {}.) I need the form object to check $valid on all the forms.
|
0

The behavior I want should be handled by the AngularJS parser, but it is not supported right now. Easiest workaround right now is to just check for undefined on access.

See more here: https://github.com/angular/angular.js/issues/14510

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.