1

The requirement is to display a success message after click of a button.Since this has to be used across many controllers i decided to use a service to do the same. But i am not able to access the scope

index.html

<div ng-controller="uploadController">     
    <div class="col-md-6" ng-click="uploadFile()" >
        <div class="form-group has-success" id="divsubmitbtn">
            <button type="submit" id="submit" class="btn btn-custom"
            ng-click="submitData()" ng-disabled="isDisableSubmit">
           <span class="glyphicon glyphicon-upload"></span> Upload</button>
       </div>
   </div>
   <div class=" col-md-12">
       <div ng-show="showError" ng-class="{fade:doFade}" class="alert alert-              success">
    <strong>Success:</strong> {{successMessage}}
     </div>
  </div>
</div>

controller.js

app.controller('uploadController', ['$scope','$timeout','$rootScope','displayMsgService',function($scope,$timeout,$rootScope,displayMsgService) {

$scope.uploadFile = function($scope,displayMsgService){     
        $scope.displayMsgService.show();
        };

$rootScope.submitData = function() {
            $scope.uploadFile();
       };
}]);

service.js

app.factory('displayMsgService',function() {
  return {
      show : function($scope){
                $scope.showError = false;
                $scope.doFade = false;           
                $scope.showError = true;
                $scope.successMessage = "success";

                $timeout(function(){
                    $scope.doFade = true;
                }, 2500);
            }
        } 
});

I am getting the below error Cannot read property 'displayMsgService' of undefined

What is that i am missing out

Nisha shetty
  • 121
  • 3
  • 7

2 Answers2

3

TYPOS

$rootScope.submitData = function() {
            $scope.uploadFile();
       };

I think you mean: $scope.submitData, as submitData is a $scope method in your controller;

and $scope.displayMsgService.show(); should really be displayMsgService.show();, as displayMsgService is the injected service, not related to $scope (not a controller scope method)


In your controller, try:

$scope.uploadFile = function($scope,displayMsgService){     
    displayMsgService.show($scope);
    };

The way your factory function was written, it must be passed the controller scope; if you modify the scope from the factory, you will also want to call $scope.$apply();

EXPLANATION

show : function($scope) does not mean that the scope is injected into your factory method. Rather, it means the show function must be passed an argument; you could replace show : function($scope) by show : function(arg) and get the same results.

This is why you must pass your scope from your controller like so: displayMsgService.show($scope)


However, passing your controller $scope to the factory/service is not good practice: see these posts: Passing current scope to an AngularJS Service and injecting scope into a service

To avoid having to pass your scope to the service, here are two solutions:


1. Broadcast

In your situation, the easiest is to broadcast an event from your service, to let your controller know the file is uploaded, like so:

 $rootScope.$broadcast('uploadDone');

NOTE: again, $rootScope needs to be injected in service/factory

and in your controller:

$scope.$on('uploadDone',function(){
 //modify $scope here
}

2. PROMISES

For asynchronous events like upload, you could also consider using promises. Even though they are not as straightforward as broadcast, they are standard practice in this case.

In your controller:

uploadMsgService.upload()
  .then(function{
  //do something to $scope
  });

and in your service:

app.factory('uploadMsgService',function($q) {
  var deferred = $q.defer();
  doTheUpload(inputData,function(err,data){
  if(err){deferred.reject("there was an error:"+err);}
  deferred.resolve(data);   
  })
  return deferred.promise;
});

For more information about the use of promises with angularjs:

Official documentation on using $q with angularjs

thinkster tuition

Community
  • 1
  • 1
Manube
  • 5,110
  • 3
  • 35
  • 59
1

You could try using a base controller for this instead of a Service.

Base Controller

app.controller('DisplayMsgController', ['$scope', function ($scope) {
  $scope.show = function () {
    // Set all your required variables and messages here
  };
}]);

And then you simply have to include the base controller in any controller where you want the desired functionality.

Upload Controller

app.controller('UploadController', ['$scope', '$controller', function ($scope, $controller) {
  // Pass the scope to the controller
  $controller('DisplayMsgController', { $scope: $scope });

  // Do your processing of data and then call the DisplayMsgController's function
  // As you would any other function in the current controller
  $scope.uploadFile = function(){     
    // Do processing here
    ...
    // Display message
    $scope.show();
  };
}]);
Sylvan D Ash
  • 1,047
  • 13
  • 24
  • Which is the best way to implement a function which can be used across multiple controllers – Nisha shetty Jun 05 '15 at 09:05
  • It all depends on what exactly you want to achieve, but you could try passing in variables to the function (and then checking that the variables have values) to reduce on global variables. However, you can just think of the base controller as an extension of the current controller, and so functions in the base controller are functions that would normally be in the current controller, the only difference being that several controllers have the same functions, hence why you've put them in a base controller. Hope that helps – Sylvan D Ash Jun 05 '15 at 10:43