Absolute Beginer
Absolute Beginer

Reputation: 83

Cannot read property 'toLowerCase' of undefined (Angularjs/JavaScript/Json)

I'm building Angular/Express app, I load data with controller and try to work with data in a function but I get error in console

Cannot read property 'toLowerCase' of undefined

When I manually write JSON data it works just fine. Anyone had this error and why is it happening?

Edit: Also I want function to work on click, when I want it not when it's loaded, also I use data from listData in view so I know it's loaded

Controller

var self = this; 
self.listData = [];

var self = this; 
self.listData = [];

$http.get('/myList')
.success(function (data) {
    self.listData = data;
    console.log(data);
})
.error(function (data) {
    console.log('Error: ' + data);
});

self.myFunc = function(){
    var map = self.listData.reduce(function (p, c) {
        p.set(c.name.toLowerCase(), c.surname);
        return p;
    }, new Map());

    console.log(...map);
}

Upvotes: 7

Views: 2047

Answers (4)

Andriy Ivaneyko
Andriy Ivaneyko

Reputation: 22071

c.name is undefined for some item in your listData. Checkout JSON which you receive from server, not faked one.

NOTE: $http.get is asynchronous. Putting self.myFunc = ... into success handler of $http.get suppose to give correct behaviour. You can take a look on Understanding Asynchronous Code in Layman's terms to see how async works.

Good Luck ! :)

Upvotes: 0

Bahadir Tasdemir
Bahadir Tasdemir

Reputation: 10803

Here is your updated code works on click of an element:

jQuery("#a-div-to-click").on("click", function() {
    var self = this; 
    self.listData = [];
    $http.get('/myList').success(function (data) {
            self.listData = data;
            console.log(data);
            self.myFunc();
       }).error(function (data) {
            console.log('Error: ' + data);
       });
    }
    self.myFunc = function(){
        var map = self.listData.reduce(function (p, c) {
                p.set(c.name.toLowerCase(), c.surname);
                return p;
        }, new Map());

        console.log(map);
    }

});

V2) The data is loaded at "onload" phase and the process done at "onclick" phase:

app.controller('yourController', function ($scope, $http) {

    $scope.fetchData = funcion(onSuccess) {
        $http.get('/myList').success(function (data) {
                $scope.aDivlistData = data;
                console.log(data);
                if (onSuccess != null) {
                    onSuccess();
                }
           }).error(function (data) {
                console.log('Error: ' + data);
           });
        }
    }();

    $scope.onADivClicked = function() {
        if ($scope.aDivlistData == null) {
            $scope.fetchData($scope.populateMap);
        } else {
            $scope.populateMap();
        }

    };

    $scope.populateMap = function() {
        var map = $scope.aDivlistData.reduce(function (p, c) {
                p.set(c.name.toLowerCase(), c.surname);
                return p;
        }, new Map());

        console.log(map);
    }
}
//html part:
//<div id="a-div-to-click" ng-click="onADivClicked()">A Div</a>

Upvotes: 1

Dylan Meeus
Dylan Meeus

Reputation: 5812

HTTP.GET is an asynchronous function

You could call your function which turns the data to lowercase in the .success of your http.get. That way you know that the data has arrived. Now you might be executing this function a bit too early which means that you do not yet have the data in your list.

If you try to run the toLowerCase() on your data, before you actually retrieved the data you will get this error. That is one of the things you learn to deal with when working with web requests.

For example writing your code like this would work.

   $http.get('/myList')
           .success(function (data) {
                self.listData = data;
                myFunc(listData);
                console.log(data);
           })
           .error(function (data) {
                console.log('Error: ' + data);
           });

 }

 function myFunc(){

    var map = self.listData.reduce(function (p, c) {
                p.set(c.name.toLowerCase(), c.surname);
                return p;
           }, new Map());

           console.log(...map);

 }

Upvotes: 1

Gavy
Gavy

Reputation: 405

Just by looking at your code. It looks like "c.name" is undefined. May be you can print that variable out and see what's in it

Upvotes: 0

Related Questions