1110
1110

Reputation: 6829

Cannot set property from angularjs service

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

Upvotes: 0

Views: 971

Answers (2)

Pankaj Parkar
Pankaj Parkar

Reputation: 136154

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

Upvotes: 1

David East
David East

Reputation: 32604

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

Upvotes: 1

Related Questions