Tobbe
Tobbe

Reputation: 3884

AngularJS does not remove form from object

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?

Upvotes: 2

Views: 237

Answers (2)

Tobbe
Tobbe

Reputation: 3884

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

Upvotes: 0

Nils
Nils

Reputation: 987

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...

Upvotes: 1

Related Questions