0

I am trying to set value in html page from angularjs controller.
I am getting value from web api in service but I have issue that I am always getting error:

TypeError: Cannot set property 'messageFromServer' of undefined

But I can't figure what am I doing wrong here. What am I missing? On the html part I have:

<div ng-app="myApp" ng-controller="AngularController">
     <p>{{messageFromServer}}</p>
</div>

In the controller I have:

var app = angular.module('myApp', []);
app.controller('AngularController', ['$scope', 'messageService', function ($scope, messageService) {
    $scope.messageFromServer = "When I set it here it works!"
    messageService.getMessage();
}]);

app.service('messageService', ['$http', function ($http) {
    this.getMessage = function ($scope) {
        return $http({
            method: "GET",
            url: "api/GetMessage",
            headers: { 'Content-Type': 'application/json' }
        }).success(function (data) {            
            $scope.messageFromServer = data;            
            console.log(data);
        }).error(function (data) {
            console.log(data);
        })
    };
}]);

2 Answers 2

1

Basically the problem is, you missed to $scope object to the service getMessage method. But this is not a good approach to go with. As service is singleton object, it shouldn't manipulate scope directly by passing $scope to it. Rather than make it as generic as possible and do return data from there.

Instead return promise/data from a service and then assign data to the scope from the controller .then function.

app.service('messageService', ['$http', function ($http) {
    this.getMessage = function () {
        return $http({
            method: "GET",
            url: "api/GetMessage",
            headers: { 'Content-Type': 'application/json' }
        }).then(function (response) {
            //you could have do some data validation here
            //on the basis of that data could be returned to the consumer method
            //consumer method will have access only to the data of the request
            //other information about request is hidden to consumer method like headers, status, etc.
            console.log(response.data);
            return response.data;            
        }, function (error) {
            return error;
        })
    };
}]);

Controller

app.controller('AngularController', ['$scope', 'messageService', 
  function ($scope, messageService) {
    $scope.messageFromServer = "When I set it here it works!"
    messageService.getMessage().then(function(data){
        $scope.messageFromServer = data;
    });
  }
]);
Sign up to request clarification or add additional context in comments.

7 Comments

Your service code won't work because you're trying to return data from inside of the promise. You just need to return the $http() call, which returns the promise. Then the controller code will work :)
@DavidEast are you kidding? returning data from promise will always work..that is what called as chain promise mechanism. Go and read about how chain promise mechanism works
Ah I didn't realize you were continuing the chain, but there's still little benefit because $http() returns a promise as well. What benefit do you find from wrapping the promise in a promise? Just curious!
@DavidEast could you check my updated answer...in which I've added why I'm returning object from the promise.. The thing which you are saying is correct..in some cases you can't have that block of code(like validating data & return data only, other response information to be hidden)..For other case I could just loved to return a promise..
@DavidEast Thanks for appreciation man.. Glad to chat with you.. Thanks :)
|
1

Don't use $scope in your service, just return the promise from $http.

var app = angular.module('myApp', []);

app.service('messageService', ['$http', function ($http) {
    this.getMessage = function () {
        return $http({
            method: "GET",
            url: "api/GetMessage",
            headers: { 'Content-Type': 'application/json' }
        });
    };
}]);

app.controller('AngularController', ['$scope', 'messageService', function ($scope, messageService) {
    messageService.getMessage().then(function(data) {
      $scope.messageFromServer = data;
    });
}]);

In this example you can unwrap the promise in your controller, or even better you can use the router to resolve the promise and have it injected into your controller.

app.config(function($routeProvider) {
  $routeProvider.when('/',{
    controller: 'AngularController',
    templateUrl: 'views/view.html',
    resolve: {
      message: function(messageService) {
        return messageService.getMessage();
      }
    }
  });
});

Then in your AngularController, you'll have an unwrapped promise:

app.controller('AngularController', ['$scope', 'message', function ($scope, message) {
    $scope.messageFromServer = message;
}]);

2 Comments

the original problem with OP is, he missed to pass $scope service getMessage method.. He haven't included $scope into the messageService
Yes, but I'd prefer to keep $scope out of the service. That's just my preference.

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.