尝试将$ scope注入服务时出现注入器错误

时间:2014-03-12 02:20:27

标签: angularjs firebase

我试图通过扩展示例应用来使用firebase来学习角度。我想修改用于调用firebase而不是我的webserver的服务对象。我试图将$scope注入我的服务对象,现在收到错误。我做错了什么?

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

app.config(function($routeProvider) {
  $routeProvider.when('/', {
    templateUrl: "templates/home.html",
    controller: "HomeController"
  })
  .when('/settings', {
    templateUrl: 'templates/settings.html',
    controller: 'SettingsController'
  })
  .otherwise({ redirectTo: '/' });
});

//services must return objects
app.service('mailService', ['$scope', '$http', '$firebase', function($scope, $http, $firebase) {
  var mailRef = new Firebase("https://ng-book-email-client.firebaseio.com/mail");

  //var getMail = function() {
  //  return $http({
  //          method: 'GET',
  //          url: '/api/mail'
  //        });
  //};
  $scope.email = $firebase(mailRef);

  var sendEmail = function(mail) {
    //var d = $q.defer();
    //$http({
    //  method: 'POST',
    //  data: 'mail',
    //  url: '/api/send'
    //}).success(function(data, status, headers) {
    //  d.resolve(data);
    //}).error(function(data, status, headers) {
    //  d.reject(data);
    //});
    //return d.promise;
    return $scope.email.$add(mail);
  };

  return {
    //getMail: getMail,
    sendEmail: sendEmail
  };
}]);

app.controller('HomeController', function($scope) {
  $scope.selectedMail;

  $scope.setSelectedMail = function(mail) {
    $scope.selectedMail = mail;
  };

  $scope.isSelected = function(mail) {
    if($scope.selectedMail) {
      return $scope.selectedMail === mail;
    }
  };
});

// directive that builds the email listing
app.directive('emailListing', function() {
  var url = "http://www.gravatar.com/avatar/";
  return {
    restrict: 'EA', // E- element A- attribute C- class M- comment
    replace: false, // whether angular should replace the element or append
    scope: { // may be true/false or hash. if a hash we create an 'isolate' scope
      email: '=', // accept an object as parameter
      action: '&', // accept a function as a parameter
      isSelected: '&',
      shouldUseGravatar: '@', // accept a string as a parameter
      gravatarSize: '@'
    },
    transclude: false,
    templateUrl: '/templates/emailListing.html',
    controller: ['$scope', '$element', '$attrs', '$transclude',
      function($scope, $element, $attrs, $transclude) {
        $scope.handleClick = function() {
          $scope.action({selectedMail: $scope.email});
        };
      }
    ],
    // if you had a compile section here, link: wont run
    link: function(scope, iElement, iAttrs, controller) {
      var size = iAttrs.gravatarSize || 80;

      scope.$watch('gravatarImage', function() {
        var hash = md5(scope.email.from[0]);
        scope.gravatarImage = url + hash + '?s=' + size;
      });

      iElement.bind('click', function() {
        iElement.parent().children().removeClass('selected');
        iElement.addClass('selected');
      });
    }
  };
});

app.controller('MailListingController', ['$scope', 'mailService', function($scope, mailService) {
  $scope.email = [];
  $scope.nYearsAgo = 10;

  //mailService.getMail()
  //.success(function(data, status, headers) {
  //  $scope.email = data.all;
  //})
  //.error(function(data, status, headers) {
  //});

  $scope.searchPastNYears = function(email) {
    var emailSentAtDate = new Date(email.sent_at),
        nYearsAgoDate = new Date();

    nYearsAgoDate.setFullYear(nYearsAgoDate.getFullYear() - $scope.nYearsAgo);
    return emailSentAtDate > nYearsAgoDate;
  };
}]);

app.controller('ContentController', ['$scope', 'mailService', '$rootScope', function($scope, mailService, $rootScope) {
  $scope.showingReply = false;
  $scope.reply = {};

  $scope.toggleReplyForm = function() {
    $scope.reply = {}; //reset variable
    $scope.showingReply = !$scope.showingReply;
    console.log($scope.selectedMail.from);
    $scope.reply.to = $scope.selectedMail.from.join(", ");
    $scope.reply.body = "\n\n -----------------\n\n" + $scope.selectedMail.body;
  };

  $scope.sendReply = function() {
    $scope.showingReply = false;
    $rootScope.loading = true;
    mailService.sendEmail($scope.reply)
    .then(function(status) {
      $rootScope.loading = false;
    }, function(err) {
      $rootScope.loading = false;
    });
  }

  $scope.$watch('selectedMail', function(evt) {
    $scope.showingReply = false;
    $scope.reply = {};
  });
}]);

app.controller('SettingsController', function($scope) {
  $scope.settings = {
    name: 'harry',
    email: "me@me.com"
  };

  $scope.updateSettings = function() {
    console.log("updateSettings clicked")
  };
});

错误

Error: [$injector:unpr] http://errors.angularjs.org/1.2.14/$injector/unpr?p0=<div ng-view="" class="ng-scope">copeProvider%20%3C-%20%24scope%20%3C-%20mailService
at Error (native)
at https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js:6:450
at https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js:32:125
at Object.c [as get] (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js:30:200)
at https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js:32:193
at c (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js:30:200)
at d (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js:30:417)
at Object.instantiate (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js:31:80)
at Object.<anonymous> (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js:31:343)
at Object.d [as invoke] (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js:30:452) angular.js:9509

2 个答案:

答案 0 :(得分:3)

答案是$ scope不应该注入服务或工厂。它们应该是可重复使用和可共享的。因此,实现所需效果的正确方法是在服务中创建一个$firebase对象,并返回一个函数,该函数可以将任何变量和范围以及$bind它们添加到firebase对象。

灵感来自http://plnkr.co/edit/Uf2fB0?p=info

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

//services must return objects
app.service('mailService', ['$http', '$firebase', function($http, $firebase) {
  var emailRef = new Firebase("https://ng-book-email-client.firebaseio.com/all");
  var emails = $firebase(emailRef);

  // uses firebase to bind $scope.email to the firebase mail object
  var setEmails = function(scope, localScopeVarName) {
    return emails.$bind(scope, localScopeVarName);
  };

  var sendEmail = function(mail) {
    return $scope.email.$add(mail);
  };

  return {
    setEmails: setEmails,
    sendEmail: sendEmail
  };
}]);

app.controller('MailListingController', ['$scope', 'mailService', function($scope, mailService) {
  mailService.setEmails($scope, 'emails');
  $scope.nYearsAgo = 10;

  $scope.searchPastNYears = function(email) {
    var emailSentAtDate = new Date(email.sent_at),
        nYearsAgoDate = new Date();

    nYearsAgoDate.setFullYear(nYearsAgoDate.getFullYear() - $scope.nYearsAgo);
    return emailSentAtDate > nYearsAgoDate;
  };
}]);

答案 1 :(得分:0)

我认为你不应该向服务注入$scope,服务可以是实现/支持多个控制器的常用服务,服务不应该知道$scope(控制器)。但控制器用户服务通过将参数传递给服务方法来完成工作。     mailService.sendEmail($ scope.reply)

不确定为什么你在服务中需要$ scope,

$scope.email = $firebase(mailRef);

你期待这样的事吗,

this.email = $firebase(mailRef);