1

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. "test@gmail.com", 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!

robert
  • 1,402
  • 1
  • 15
  • 21
Octtavius
  • 563
  • 8
  • 29
  • i don't see any errors in your plunkr messages.. what is the problem exactly ? – MayK May 19 '16 at 20:19
  • `$scope` might not be inheriting `$rootScope`. I would try to rewrite your `handleError` function as a service or something. That would clean up your code a bit. – robert May 19 '16 at 20:19
  • In `$scope.storeEmailErr`, you initialize `res` as an object, but then `res` is reassigned to the return value of `$rootScope.handleError`, which is an array. That is a little weird :). – robert May 19 '16 at 20:25

2 Answers2

1

The issue you are having is with this block of code here:

$.each(errorArray, function(i){
    if(errorArray[i].selector === key) {
        errorArray.splice(i, 1);
        elemIn = false;
     }
});

When you call splice, you are modifying the length of the array. $.each is looping over the length of the array, and is not aware of the length change. (I don't know the internal workings of $.each, but I'm guessing it caches the length of the array before starting, for performance reasons.) So, after you splice out the first error, the loop is still running a second time. At this point, errorArray[1] no longer exists, which is causing your undefined error.

See this question for reference: Remove items from array with splice in for loop

Community
  • 1
  • 1
Brian Glaz
  • 15,468
  • 4
  • 37
  • 55
1

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.

Andonaeus
  • 872
  • 1
  • 5
  • 21
  • Thanks a lot Andonaeus for your help. It works fine now. But I don't understand why I have to create the staticErrors when I have the errorsDescription. I don't modify the errorDescription at all but when it removes an error element from the errorArray, it also removes from the errorsDescription. If have time, please explain what would be the problem. I really rely on your help. – Octtavius May 19 '16 at 22:11
  • 1
    @Octtavius they are the same array, you just refer to it with the different name – Andonaeus May 19 '16 at 22:16