防止第三方工厂使用相同名称干扰我的应用程序工厂

时间:2015-10-14 15:24:40

标签: javascript angularjs factory color-picker

我在我的应用中使用angular-bootstrap-colorpicker并且遇到了一个奇怪的问题。 colorpicker模块有一个名为Slider的工厂。这导致颜色选择器无法工作,因为我的应用程序还有一个名为Slider的工厂。不可能在应用程序中重构每一次这样的事情,无论如何它似乎是一个草率的解决方法。抛出的错误是

  

未捕获的TypeError:Slider.setSaturation不是函数

我得出的结论是因为我的应用工厂没有方法setSaturation而Angular被“混淆”了。我对工厂以及Angular如何组织它们并不是很了解,但似乎很奇怪它们可以在这样的模块之间使用。例如

angular.module('thomasApp', [])
...
.factory('Slider', ...

影响
angular.module('colorpicker.module', [])
...
.factory('Slider', ...

反之亦然。

有没有我可以划分这个颜色选择器,以免它干扰我的Slider工厂?

编辑:

我同意链接的答案,即使用前缀作为命名空间是一个明智的想法。然而,这将需要不切实际的重构量。我很欣赏下面的答案,但它并没有足够的充实让我能够付诸行动。

1)这真的是最好的解决方案(除了项目开头的前缀)吗? - 如果我做这样的改变,下次我做凉亭更新时会删除它,还是有人拉下我的项目并安装了凉亭?

2)有更好的方法吗? - 如果没有,是否可以扩展当前的答案并解释发生了什么?

4 个答案:

答案 0 :(得分:7)

您遇到的问题是Angular中一般已知的问题。 @fracz是对的,它与Modules and namespace / name collision in AngularJS有关。问题是Angular每个模块实例化只有一个$ injector实例,所有定义的可注入对象都进入它。通过可注入的对象,我指的是常量,值,服务,控制器,指令。在这种情况下这很糟糕,因为即使我们通过在最后定义多个模块和它们之间的依赖关系来模块化我们的应用程序,所有定义的可注入对象最终都会相同的上下文/命名空间/注入器。

Angular通过在这种情况下不使用fail-fast技术使情况变得更糟,并且因为应用程序继续工作,您最终可能会注意到问题,这通常会导致昂贵的重构。而且我们仍然有一个问题,我们如何能够改善这一点,IMO失败 - 至少会在开始时帮助避免这个问题。

然而,在您的情况下,您很幸运,图书馆非常小,您需要的只是颜色选择器指令。我通过在模块中定义颜色选择器指令,同时从实例化的库模块$ injector中获取它的定义,制作了一个解决方法示例here。像这样,你可以自由改变它的名字:)。

代码示例:

// NOTE: redefine the directive
app.directive('colorpicker', function () {
  var injector = angular.injector(['ng', 'colorpicker.module']);
  return injector.get('colorpickerDirective')[0];
});

为了便于说明,还有一个示例显示了在定义具有相同名称的两个服务时Angular的行为方式。应用程序成功继续使用上一个服务定义。

我希望这个答案能让事情变得清晰并成功解决你的问题。如果您有更多问题,请随时提出。干杯!

答案 1 :(得分:5)

也许是这样的事情 - 创建一个假模块并用新名称包装现有的提供者。这将隔离依赖。



var colorpicker = angular.module('my-colorpicker', ['colorpicker.module']);
colorpicker.factory('ColorPickerSlider', function() {
  var injector = angular.injector(['colorpicker.module']);
  var Slider = injector.get('Slider');
  return Slider;
});




我知道这并没有解决名称空间的基本问题,但它提供了一种隐藏沙箱中现有依赖项的方法。

答案 2 :(得分:0)

是的,您可以处理多个具有相同名称的工厂。

以下是示例

var app = angular.module('firstApp', []);
app.factory('SameFact', [function () {
    return { Name: "First" };
}]);

var app2 = angular.module('secondApp', ['firstApp']);

app2.factory('SameFact', [function () {
    return { Name: "Second" };
}]);

app2.controller("testController", ["SameFact", "$scope", "$injector", function (SameFact, $scope, $injector) {
    $scope.myName = {};
    $scope.myName.Name1 = SameFact.Name; // This will be "Second", Last factory
    var inj = angular.injector(['firstApp']);
    $scope.my_inject = inj.get('SameFact').Name; // This will be "First", the first factory
}]);

注意

当您将工厂作为依赖项传递给控制器​​时,它将注册最后注册的工厂。

也就是说,在这个例子中,我已经注册了两个同名SameFact但在不同模块中的工厂。

当我从控制器中引用工厂SameFact时,它总是指向最后注册的工厂,即工厂secondApp

但是,您可以手动引用模块firstApp中的工厂。

您可以使用angular.injector(['module_name'])选择所需模块的进样器,然后在其中使用get()功能来获取工厂或服务。

<强>结论

因此,您需要声明一个范围变量,该变量指向Slide模块的colorpicker工厂。并使用此范围变量来获取colorpicker模块中的所有必需操作。找到您调用colorpicker函数的位置,并将其替换为此新变量。

希望这能帮助你度过目前的状况。

随意对此有任何疑问!!!

答案 3 :(得分:0)

在模块初始化时,将colorpicker.module置于包含Slider factory的模块之前:

angular.module('thomasApp', ['colorpicker.module','anotherModule'])

以下是js fiddle

的示例