【问题标题】:AngularJS service injection incorrect/different when called from a $timeout or AJAX call从 $timeout 或 AJAX 调用调用 AngularJS 服务注入不正确/不同
【发布时间】:2013-12-27 00:00:37
【问题描述】:

我有一个注入提供程序的指令(带有私有变量) - 下面和http://jsfiddle.net/jycchoong/BmaQD/3/ 中的示例代码。当 (a) 在指令的链接函数中内联调用它的方法,或 (b) 通过在指令的链接函数中调用的 $broadcast 时,注入的提供程序是预期的。但是,当 (c) 通过 $timeout 调用它时(或者在我的代码的情况下,在 AJAX 调用弄脏被监视对象之后的 $watch),注入的提供程序与指令的最后实例化相关联。

您可以看到 (c) 出现在输出中(第一行,第三句)。而在 (a) 或 (b) 中(输出中的前两个句子),从提供者返回“实例 1”,对于 (c),返回“实例 2”。 $scope 本身是正确的(请参阅输出中的 $scope.$id,因此我们处于正确的指令实例中),但提供程序实例用于最后一个指令。

对于我做错了什么或者我应该以不同的方式构建代码有什么建议吗?有关我所追求的模式的更广泛解释(您不必阅读),请查看下面代码片段之后的背景说明,如果有关于实现总体目标的不同方法的建议。

感谢您的帮助!!!

附言。这不是关闭问题。所有场景 (a)、(b) 和 (c) 在日志函数中具有相同的本地/闭包可见性。

HTML:

<div my-directive id="Instance 1"></div>
<div my-directive id="Instance 2"></div>

JS:

var app = angular.module('app', ['myModule']);
angular.module('myModule',[])
.directive('myDirective', function (myProvider, $timeout) {
    return {
        restrict: 'A',
        scope: true,
        link: function ($scope, element) {
            element.text('');
            var log = function ($event, eventData) {
                element.text(element.text()+'For source "'+($event ? eventData.source : 'Inline')
                    + '", scope id = ' + $scope.$id + ' with provider "' + myProvider.externalFn()
                    + '". ');
            };
            myProvider.init(element.attr('id'));
            // Inline
            log();
            $scope.$on('myEvent', log);
            // Invoke broadcast inline
            $scope.$broadcast('myEvent', {source: 'Broadcast Inline'});
            $timeout(function() {
                // Invoke broadcast in $timeout or from $watch
                $scope.$broadcast('myEvent', {source: 'Broadcast Delayed'});
            }, 1000, false);
        }
    };
})
.provider('myProvider', function () {
    var internalVar;
    return {
        $get: function () {
            return {
                init: function (value) {
                    internalVar = value;
                },
                externalFn: function () {
                    return internalVar;
                }
            };
        }
    };
});

输出:

For source "Inline", scope id = 003 with provider "Instance 1". For source "Broadcast Inline", scope id = 003 with provider "Instance 1". For source "Broadcast Delayed", scope id = 003 with provider "Instance 2".
For source "Inline", scope id = 004 with provider "Instance 2". For source "Broadcast Inline", scope id = 004 with provider "Instance 2". For source "Broadcast Delayed", scope id = 004 with provider "Instance 2".

背景

我希望做的事情并不是那么不寻常。我将指令代码和提供程序代码分开。我选择提供者是因为服务需要能够存储自己的私有变量,并且提供者/指令组合的每个实例在私有变量中都有不同的值。这允许不同的开发人员处理服务与指令(或允许注入特定服务的不同变体)。一切都很好,直到我不得不从 AJAX 调用中更新我的数据,突然之间,注入的提供程序不再是我所期望的。

一个明显的解决方法是将 $scope 传递给提供程序 - 正如您在上面的代码中所看到的,正确的 $scope 是可用的。这有点丑陋,破坏了模式的好处。我当然不希望提供程序开发人员摆弄整个 $scope。另一种解决方案是创建一个 $scope.myProvider 对象,然后只将它传递给提供程序以使用(并将所有内容存储在其中),以便 $scope 的其余部分不可见,但这似乎有点像破解。

欢迎评论...

【问题讨论】:

    标签: angularjs angularjs-service


    【解决方案1】:

    好吧,我想我明白了。菜鸟 AngularJS 的错误。服务不是传统的课程。您不能将它们实例化为每个注入它们的指令具有不同的私有变量。只有一个“实例化”。如果每个指令需要有不同的变量值,则必须将这些变量粘贴到 $scope 中(每个指令将具有不同的 $scope)。考虑到与传统的 OO 课程相比,它的思维方式发生了重大变化,因此需要一点时间来适应。

    解决方案是将 $scope 推入提供程序,如果希望限制提供程序的“范围”以避免混淆范围的其余部分,请执行以下操作 (http://jsfiddle.net/jycchoong/BmaQD/5/)。它是自我监管(在提供者中)。我很想知道是否有更好的方法...

    .provider('myProvider', function () {
        var myProviderScope;
        var setMyProviderScope = function($scope) {
            myProviderScope = $scope.myProvider;
        };
        return {
            $get: function () {
                return {
                    init: function ($scope, value) {
                        if (!$scope.myProvider) $scope.myProvider = {};
                        setMyProviderScope($scope);
                        myProviderScope.val = value;
                    },
                    externalFn: function ($scope) {
                        setMyProviderScope($scope);
                        return myProviderScope.val;
                    }
                };
            }
        };
    }); 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-03
      • 1970-01-01
      • 2014-12-31
      • 1970-01-01
      • 2014-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多