在角度工厂中访问范围

时间:2015-06-05 07:05:42

标签: javascript angularjs

要求是在点击按钮后显示成功消息。由于必须在许多控制器上使用,我决定使用服务来执行相同操作。 但我无法访问范围

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

我收到以下错误 无法读取属性&#39; displayMsgService&#39;未定义的

我错过了什么

2 个答案:

答案 0 :(得分:3)

错字

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

我认为你的意思是:$scope.submitData,因为submitData是控制器中的$ scope方法;

$scope.displayMsgService.show();应该是displayMsgService.show();,因为displayMsgService是注入的服务,与$ scope无关(不是控制器范围方法)

在您的控制器中,尝试:

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

编写工厂函数的方式,必须通过控制器范围;如果您从工厂修改范围,您还需要致电$scope.$apply();

说明

show : function($scope)并不意味着范围被注入您的工厂方法。相反,它意味着show函数必须传递一个参数;您可以将show : function($scope)替换为show : function(arg)并获得相同的结果。

这就是您必须从控制器传递范围的原因:displayMsgService.show($scope)

  

但是,将您的控制器$范围传递给工厂/服务并非良好做法:请参阅以下帖子:Passing current scope to an AngularJS Serviceinjecting scope into a service

为了避免将范围传递给服务,这里有两个解决方案:

1。广播

在您的情况下,最简单的方法是从您的服务广播一个事件,让您的控制器知道该文件已上传,如下所示:

 $rootScope.$broadcast('uploadDone');

注意:同样,$rootScope需要在服务/工厂中注入

并在您的控制器中:

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

2。 PROMISES

对于像上传这样的异步事件,您还可以考虑使用promises。虽然它们不像广播那么简单,但在这种情况下它们是标准做法。

在您的控制器中:

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

并在您的服务中:

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

有关使用angularjs的承诺的更多信息:

Official documentation on using $q with angularjs

thinkster tuition

答案 1 :(得分:1)

您可以尝试使用基本控制器代替服务。

基本控制器

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

然后您只需将基本控制器包含在您想要所需功能的任何控制器中。

上传控制器

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