Javascript 配置服务(通过其提供程序)以使用其他服务
我有一个服务,我想通过传入一个函数来配置它。只要此函数返回我的服务可以使用的内容,它就不关心如何获取数据,也不关心同步/异步。以下是我希望能够做到的一个示例,但由于明显的原因无法做到:Javascript 配置服务(通过其提供程序)以使用其他服务,javascript,angularjs,Javascript,Angularjs,我有一个服务,我想通过传入一个函数来配置它。只要此函数返回我的服务可以使用的内容,它就不关心如何获取数据,也不关心同步/异步。以下是我希望能够做到的一个示例,但由于明显的原因无法做到: .config(function(MyServiceProvider, OtherService) { MyServiceProvider.setSomeMethod( OtherService.someMethod ); }) 这太棒了,但是似乎没有一种方法可以从config函数中引用“OtherSe
.config(function(MyServiceProvider, OtherService) {
MyServiceProvider.setSomeMethod( OtherService.someMethod );
})
这太棒了,但是似乎没有一种方法可以从config函数中引用“OtherService”。我知道这是因为OtherService
可能尚未配置,因此它的实例不应该存在,但在这种情况下,一个人该怎么办
在运行块中建立这种关联(带焦虑)合适吗
.run(function(MyService, OtherService) {
MyService.setSomeMethod( OtherService.someMethod );
})
在引导解决之后,使用该服务解决依赖关系
例如:
angular.module('myApp').config(function(myProvider) {
myProvider.setMethod('myUberMethod');
});
// Somewhere in myProvider
var theUberMethod, theUberMethodName;
function setMethod(dependencyName) {
theUberMethodName = dependencyName;
}
function performTheMethod() {
theUberMethod = theUberMethod || $injector.get(theUberMethodName);
// Magic
theUberMethod();
}
您甚至可能想看看$injector的invoke方法,因为它允许您将参数注入到被注入的函数方法中
编辑
我得好好解释一下
您面临的问题与注入模块未在配置阶段初始化有关,因此无法将服务注入配置函数。只允许提供程序。您必须将任何依赖项解析推迟到配置阶段之后。这可以通过在提供者上使用$get函数来完成,或者通过注入$injector服务并使用它来完成解析
一个函数可以注册为依赖项注入,就像任何其他对象一样。因此,向提供者提供函数的名称就足以让它在以后解析并执行它
myApp.provider('myFunctionCallee', function() {
var self = this;
return {
hookMyFunction: function(value /* string: name of the function */ ) {
self.myFunction = value;
},
$get: function($injector) {
return {
executeMyFunction: function() {
return $injector.get(self.myFunction)();
}
};
}
};
});
现在我们需要一种方法来通知喷油器该功能
例一
这是最简单的。。。只需直接向注入器注册一个函数(对象)。我们将通过请求“myFunction”来解析函数
myApp.value('myFunction', function() {
return 'hello injected function!';
});
myApp.config(function(myFunctionCalleeProvider) {
myFunctionCalleeProvider.hookMyFunction('myFunction');
});
例二
此方法看起来与前一种方法非常相似。我们将直接注册一个函数,但也将它注入到我们的目标服务中
myApp.value('myFunction', function() {
return 'hello injected service function 1';
});
myApp.factory('myService', function(myFunction) {
return {
myServiceFunction: myFunction
};
});
myApp.config(function(myFunctionCalleeProvider) {
myFunctionCalleeProvider.hookMyFunction('myFunction');
});
例三
有时,前面的方法是不可能的。也许代码是由其他人编写的,而他/她没有你这样的远见卓识。但是,我们可以在任何可注入对象上公开任何函数:
myApp.factory('myService', function() {
return {
// We want to target this beast
myServiceFunction: function() {
return 'hello injected service function 2';
}
};
});
// Inject the target service here ...
myApp.factory('myFunction', function(myService) {
// ... and expose the beast.
return myService.myServiceFunction;
});
myApp.config(function(myFunctionCalleeProvider) {
myFunctionCalleeProvider.hookMyFunction('myFunction');
});
你可以在这里看到、感受和舔它。这两个答案都是@null答案的衍生物。为了完整性和清晰性,我把这个放在这里。我认为这个话题在其他地方没有得到很好的讨论,可能很难让人理解(就像我的情况一样) 在我下面不太喜欢的第二种方法中,我使用
$q.when()
包装此处的主题所配置的函数。我建议在这种情况下始终使用它,以便配置的函数可以安全地同步或异步。为了降低复杂性,我在第一个示例中不考虑这一点
创建一个服务并按名称(字符串)传递对该服务的引用。
使用引用其他服务的字符串名称配置提供程序-以何种方式或可能不是您实际尝试访问的服务:
.config(function(SomeServiceProvider) {
SomeServiceProvider.someServiceName = 'ThisService';
})
ThisService
将被SomeService
作为函数调用ThisService
可以将多个其他服务注入其中,对它们执行一些操作并返回结果
.factory('ThisService', function(FooService, BarService) {
var service = function() {
var x = FooService.whatever();
var y = BarService.blah();
return x+y;
};
return service;
})
在您配置的SomeService
中,使用$injector
获取此服务
.provider('SomeService', [
function() {
var config = this;
this.someServiceName = null;
this.$get = [
'$injector',
factory
];
function factory($injector) {
var service = function() {
//do stuff
//call the configured function
var fn = $injector.get(config.someServiceName);
var myData = fn();
//etc
};
return service;
}
}
])
我目前正在使用一个默认函数对此进行扩展,如果配置中没有给出服务名称,将调用该函数:
.provider('SomeService', [
function() {
var config = this;
this.defaultFn = function() {
//default stuff
};
this.someServiceName = null;
this.$get = [
'$injector',
factory
];
function factory($injector) {
var service = function() {
//do stuff
//use defaultFn if no service name was given
var fn = config.someServiceName
? $injector.get(config.someServiceName)
: config.defaultFn
;
var myData = fn();
//etc
};
return service;
}
}
])
这种方法有一个小小的缺点,就是它创建了另一个命名的角度组件(服务),但这其实不是问题,除非你非常不擅长命名或非常不走运。我只是在服务名称的开头添加了“Config”,对名称空间进行排序并对其进行标记
另一个选项:将$injector传递给在配置中创建的函数。
这是我以前的答案,我更喜欢上面的解决方案
(此处使用的$q
与问题无关。我之所以包含它,是因为它与功能非常相关-配置的服务可以使用同步或异步功能。)
您可以从另一个服务传递方法名并在配置中绑定它-将“someMethod”作为methodName传递,然后调用
OtherService[methodName]
-尽管我同意这很令人沮丧,而且肯定是您期望的一个带有dicto do的fw。@BenjaminGruenbaum好主意,但该服务甚至不知道其他服务。我可以尽快执行myService.setSomeMethod(函数(){return'whatever})代码>。碰巧我想在这里使用另一个服务的方法。这假设配置的服务期望涉及另一个服务。没有。它只需要一个函数,而不关心函数做什么。我进一步考虑了这个想法,将$injector
传递给我在config函数中声明的函数。这使得进行配置的人可以随心所欲。您误解了:函数是对象,因此是可注入的。我可能仍然误解:)您的方法似乎使用函数或作为函数的服务。。如果你想将方法设置为SomeService.somesmethod
,那你就不走运了,对吧?我的坏消息是,还不清楚--这里已经很晚了。请看一下编辑。
.config([
'MyServiceProvider',
function(MyServiceProvider) {
MyServiceProvider.setSomeMethod(function($injector) {
var OtherModule = $injector.get('OtherModule');
OtherModule.someMethod();
});
}
])
.provider('MyService', [
function() {
var config = this;
this.someMethod = function() { };
this.setSomeMethod = function(fn) {
this.someMethod = fn;
};
this.$get = [
'$q',
'$injector',
factory
];
function factory($q, $injector) {
var service = function() {
var loaded = config.someMethod($injector);
$q.when(loaded).then(function() {
});
};
return service;
}
}
])