7

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);
}
4
  • http.get is asynchronous Commented Aug 5, 2016 at 9:29
  • inside the reduce function do console.log(c) and see if the data is correct. Commented Aug 5, 2016 at 9:41
  • Just fyi .success and .error are deprecated. Use .then and .catch instead. Commented Aug 5, 2016 at 9:53
  • use console.log to check the data. The chrome dev tools also have a 'network' tab which can show you the stream of data coming in Commented Aug 5, 2016 at 9:56

4 Answers 4

1

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);

 }
Sign up to request clarification or add additional context in comments.

4 Comments

This function is executed on click, so the view has loaded the data is loaded into view. vm.word works fine when i console it. But just wont works with function. Function should get access to it becuse when i manually write vm.json and work with him it converts no problems.
You kept the typo in there so it will work even less.
@gyc I fixed it. I saw your answer on this post, and the OP replied that this was due to a typo in his post, so I stopped my edit and forgot that I had copy pasted that part. ;-)
It has nothing to do http.get being asynchronous. The callback for .reduce won't be called on empty array.
1

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>

3 Comments

Ye but i need to load data again from the server, and the point is to work with once loaded data.
Checkout my V2 and tell me if not the one you want again so I can get the sample that works with you.
Updated the V2 and now it is guaranteed that you will get your data and it will only be populated for once.
0

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

Comments

0

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 ! :)

3 Comments

But i don't want to do the function when it loads i wanna do it on click.
ok, in that case simply ensure that ListData is written corectly everywhere.
Same thing, it was typo, but ye works everywhere. I even load data from it in view.

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.