如何正确绑定到 AngularJS 中的服务 属性?

How to bind properly to a service property in AngularJS?

我有一个工厂,那里有几个预定义的合作伙伴(也可以是其他任何东西,我认为这是一个易于理解的示例)。在 运行 时间,我们 select 当前合作伙伴(基于我在此省略的一些逻辑)。

angular.module('myApp').factory('PartnersService', function ($location, $log) {

  var partners = {
    firstPartner: {
      name: 'Default Partner',
      id: 1 // just an extra property as example 
    },
    secondPartner: {
      name: 'Other Partner',
      id: 2
    }
  };

  // set default value
  var partner = partners.firstPartner;

  var initPartner = function () {
    // based on some logic (omitted), select partner
    partner = partners.secondPartner;
    $log.log("initPartner should have changed partner to " +  partner.name);
  };

  return {
    initPartner: initPartner,
    partners: partners,
    partner: partner,
  };
});

然后,我想以 PartnersService.partner 的身份访问合作伙伴并查看它的变化,例如来自控制器:

angular.module('myApp').controller('myController',
  function ($scope, $log, PartnersService) {
    // PartnersService.partner is the default partner (firstPartner)
    PartnersService.initPartner();
    // After initPartner, PartnersService.partner is still
    // the default, but I expected it to change
});

我找到了一些解决方法(在我看来...它们是解决方法吗?),但对我来说感觉不自然,所以我想请问有没有更好的办法

JS Bin 上查看我完整的工作示例。如果您觉得这个例子有点冗长,我深表歉意,但我想确保 Stack Overflow 用户理解我的担忧,如果我的想法有问题,可以指出。

解决方法 1(getter?):

angular.module('myApp').controller('myController', function ($scope, $log, PartnersService) {
  PartnersService.initPartner();
  var partner = PartnersService.getPartner();
  $log.log('I could use a getter: ' + partner.name);
});

angular.module('myApp').factory('PartnersService', function ($location, $log) {

  var getPartner = function () {
    return partner;
  };

  return {
    getPartner: getPartner,
    // ...
  };
});

解决方法 2(嵌套在对象文字中):

angular.module('myApp').controller('myController', function ($scope, $log, PartnersService) {
  PartnersService.initPartner();
  $log.log('or nest the partner in an extra object literal: '
     + PartnersService.extraObjectLiteral.partner.name);
});

angular.module('myApp').factory('PartnersService', function ($location, $log) {
  var partners = { /*...*/ }
  var extraObjectLiteral = {
    partner: partners.firstPartner
  };

  var initPartner = function () {
    // based on some logic (omitted), select partner
    extraObjectLiteral.partner = partners.secondPartner;
  };

  return {
    extraObjectLiteral: extraObjectLiteral,
    //...
  };
});

我认为您没有遗漏任何明显的东西。您的两种解决方法对我来说似乎都可以,除了在后一种情况下我可能会使用以下结构:

var partners = { ... };

var initPartner = function () {
    retObj.partner = partners.secondPartner;
};

var retObj = {
    initPartner: initPartner,
    partners: partners,
    partner: partners.firstPartner
};   

return retObj;

更改为:

this.partner = partners.secondPartner;

在您的 initPartner 方法中。这样就解决了。

当你做的时候你真正在做什么

  var partners = { ... }
  var partner = partners.firstPartner;

是,您在 class 中创建本地对象,但它们不是 class 的公开成员。并与

  return {
    initPartner: initPartner,
    partners: partners,
    partner: partner
  };

您创建 class 的成员,并将局部变量的值复制到 class 的成员。在您的 initPartner 方法中,您更改了本地对象,但 class' 对象保持不变。

我会采用使用 getter 和 setter 的方法,因为这遵循 Revealing Module Pattern 这对于维护更清晰、更易读和更易理解的代码确实是首选。

出厂代码如下

(function () {
    angular.module('myApp').
        factory('PartnersService', PartnersService);

    function PartnersService($location, $log) {
        var partners = {
            firstPartner: {
                name: 'Default Partner',
                id: 1 // just an extra property as example 
            },
            secondPartner: {
                name: 'Other Partner',
                id: 2
            }
        };
        var partner;

        //Set default value
        setDefaultPartner();

        var service = {
            getPartner: getPartner,
            setPartner: setPartner
        };
        return service;

        /*** Function Declarations ***/

        /* Accessible Functions */

        function getPartner() {
            return partner;
        }

        function setPartner() {
            var selectedPartner = initPartner();

            return selectedPartner;
        }

        /* Private Functions */

        function initPartner() {
            /*
             * Some (omitted) logic to select partner
             */

             partner = partners.secondPartner;
             $log.log("initPartner should have changed partner to " +  partner.name);

             return partner;
        }

        function setDefaultPartner() {
            partner = partners.firstPartner;
        }
    }
})();

请注意,剩下的唯一 public/accessible 个成员是 getPartnersetPartner(调用 initPartner)函数。

控制器如下。

(function () {
    angular.module('myApp').
        controller('myController', myController);

    function myController($scope, $log, PartnersService) {
        $scope.partner = PartnersService.getPartner();
        $log.log("should be default partner: " + $scope.partner.name);

        $scope.partner = PartnersService.setPartner();
        $log.log("After setPartner which calls initPartner, the current partner is now the " + $scope.partner.name);
    }
})();

修改您的JS Bin,以下是生成的控制台日志。

"should be default partner: Default Partner"
"initPartner should have changed partner to Other Partner"
"After setPartner which calls initPartner, the current partner is now the Other Partner"