Search code examples
javascriptangularjsangularjs-directiveangularjs-scope

Cannot read 'xyxyx' property of undefined even if element exist


I have two HTML inputs (type="email", type="number") and my Angular app watches them using $formatters and $parsers. The errors are stored in an array and when user insert an email which contains "@gmail" the error is removed from the array.

app.controller('form1Controller', function($scope, UserService) {
    $scope.formCompleted = false;
    $scope.errors = UserService.errors;

     //handle the user email input.
    $scope.storeEmailErr = function(data) {

        var correctKey = "@gmail";
        var key = "#userEmail"; 

        var res = {}; 

        if (data != null) {
            res = $scope.handleError(data, emailIn, correctKey, key, $scope.errors);
            $scope.errors = res[0];
            UserService.errors = res[0];
            emailIn = res[1];
        }
    };

    //handle the user email input.
    $scope.storeIdErr = function(data) {

        var correctKey = "0000";
        var key = "#userId";

        var res = {};

        if (data != null) {
            res = $scope.handleError(data, idIn, correctKey, key, $scope.errors);
            $scope.errors = res[0];
            idIn = res[1];
        }

     };
}

This is the code that adds and removes errors from array. And here i suppose is the problem

function theIndexOf(val) {
  console.log("find index in array of length:  " + errorsDescription.length)
  for (var i = 0; i < errorsDescription.length; i++) {
    if (errorsDescription[i].selector === val) {
        return i;
    }
  }
}

app.run(function($rootScope){
$rootScope.handleError = function(data, elemIn, correctKey, key, errorArray){
    var idx = theIndexOf(key);
    console.log("get index >>>>> " + idx);
    var obj = errorsDescription[idx];

    //if user didn't put correct word i.e. @gmail or 0000
    if (data.indexOf(correctKey) < 0) {
        if (!elemIn) {
            errorArray.push(obj);
            elemIn = true;
        }
    } else {
        if (elemIn) {
            $.each(errorArray, function(i){
                if(errorArray[i].selector === key) {
                    errorArray.splice(i, 1);
                    elemIn = false;
                }
            });
        }
    }
    return [errorArray, elemIn];
}
});

The problem is that when I insert i.e. "[email protected]", the error is deleted from the array and when I insert correct data again it tells me that cannot read 'yyy' property of undefined.

Here is my plunker. https://plnkr.co/edit/l0ct4gAh6v10i47XxcmT?p=preview

In the plunker, type in the fields 'test@gmail' and test0000 for the Number, then remove data then insert again the same data to see the problem

Any help would be much appreciated!


Solution

  • EDIT: Working plunkr here: https://plnkr.co/edit/8DY0Cd5Pvt6TPVYHbFA4

    The issue is here:

    var obj = errorsDescription[idx];
    
    //if user didn't put correct word i.e. @gmail or 0000
    if(data.indexOf(correctKey) < 0){
        // console.log("You must put correct word");
        if(!elemIn){
            errorArray.push(obj);
            elemIn = true;
        }
    }
    

    When your Personal Number error is removed, the logic above pushes undefined to your errorArray (because elemIn is false). Your storeIdErr methond:

    $scope.storeIdErr = function(data){
    
        var correctKey = "0000";
        var key = "#userId";
    
        var res = {};
    
        if(data != null){
            res = $scope.handleError(data, idIn, correctKey, key, $scope.errors);
            $scope.errors = res[0];
            idIn = res[1];
        }
    
    };
    

    reads this value (res[0]) and stores it in $scope.errors which ultimately is iterated over on the next input event by:

    function theIndexOf(val){
        console.log("find index in array of length:  " + errorsDescription.length)
        for(var i = 0; i < errorsDescription.length; i++){
            if(errorsDescription[i].selector === val){
                return i;
            }
        }
    }
    

    due to your factory returning that object when asked for errors. To fix this, you should keep a static list that you never remove from which provides the error definitions. This is what you should refer to when you push to errorArray in your first code block.