3

I'm getting a Cannot read property of undefined error when calling a function, however the data is being displayed correctly.

According to what I've read so far, that's because of asynchronous load of data made by AngularJS and that I should use promises to avoid that.

I've searched online and Angular's documentation but I didn't understand how to use it.

I'd appreciate if someone could help me.

Currently, I have the following code:

.factory('Test', ['$resource', function ($resource) {
  return $resource('data.json');
}])

.controller('MyCtrl', ['$scope', 'Test', function($scope, Test) {

Test.get(function (data) {
  $scope.myData = data;
});

$scope.myFunction = function() {
  var min = $scope.myData.min;
  var max = $scope.myData.max;
  var diff = max - min;
  return diff;
}

}])

Here's a Plunker: http://plnkr.co/edit/3AK70uVbNSdhAIIfdkHb?p=preview

3 Answers 3

3

You should not use $scope.myData.min until $scope.myData is populated, which as you correctly said is asynchronous so can take a moment. The simplest solution is in this case just wrap your code into if-block:

$scope.myFunction = function() {
  if ($scope.myData) {
    var min = $scope.myData.min;
    var max = $scope.myData.max;
    var diff = max - min;
    return diff;
  }
}

myFunction is going to be checked in every digest cycle so once $scope.myData is available it the function will evaluate and return diff properly.

However, much better approach would be to work with a promise object returned by resource. In this case you could do something like this:

function myFunction(myData) {
  var min = myData.min;
  var max = myData.max;
  var diff = max - min;
  return diff;
}

Test.get().$promise.then(myFunction).then(function(data) {
  $scope.myData = data;
});

and in HTML use myData without a function:

<div ng-controller="MyCtrl">
  {{myData}}
</div>

Demo: http://plnkr.co/edit/2SSk2lChkbvm5ffbHF2n?p=preview

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

5 Comments

I was just thinking: what if I'd want to pass a value to the function (e.g. {{myData(2)}} where 2 would be min. Then, I wouldn't be able to use your second approach, right?
Then you wouldn't be able to use it, yes. However, I wouldn't recommend using functions like this, the function is going to be called many times, with possible performance issues. It's better to set scope property and use it inside of myFunction.
I see. But let's say I'd like something like this: plnkr.co/edit/9qv6cXs1RaOOaxhJ3U1X?p=preview - then, is there a better way than using a function like this?
Actually, I made some changes to the code above (plnkr.co/edit/Bi17ENfKoAelqgihEeQs?p=preview) but I wonder if it's a good practice to put calculations right into the HTML instead of writing a function for it.
Yes, in this case with simple calculation it's fine.
0

Just define $scope.myData = {}

e.g. for your code:

angular.module('myApp', ['ngResource'])

.factory('Test', ['$resource', function ($resource) {
  return $resource('data.json');
}])

.controller('MyCtrl', ['$scope', 'Test', function($scope, Test) {
  $scope.myData = {}  // <--- That's what I have defined
  Test.get(function (data) {
      $scope.myData = data;
  });

  $scope.myFunction = function() {
      var min = $scope.myData.min;
    var max = $scope.myData.max;
    var diff = max - min;
    return diff;
  }

}])

Comments

-1

Your code is fine, maybe a little modification to avoid

Cannot read property of undefined error

$scope.myData = Test.get();

Then u can have

$scope.myFunction = function() {
    var min = $scope.myData.min;
    var max = $scope.myData.max;
    var diff = max - min;
    return diff || 0;
}

https://docs.angularjs.org/api/ngResource/service/$resource

Comments

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.