您如何设计一个用户在依赖它时必须将配置数据传递给的模块?
How do you design a module that a user has to pass config data to when they depend on it?
我有一个 angular 模块,它基本上是一个客户端 Web 服务层(正在进行中)。我有一个模块声明和一个名为 "baseRequest" 的工厂。 baseRequest 依赖于模块中的其他工厂。 BaseRequest 需要知道它将调用的 WebApi2 控制器的基础Url。
该脚本托管在站点 A:但将在站点 B、C、D、E 等上使用。因此,如果没有某些内容,它无法可靠地知道它是自己的 url配置数据。
基于此,我希望使用 api 的用户在添加脚本标签时必须对其进行配置。我设想他们必须在我的模块上调用配置,但我不确定如何在这个模块上实现它,并且被有关该主题的文档弄糊涂了:
(function () {
angular.module('xyzApi', []).run(['$http', function ($http) {
//Configure defaults on $http here if need be
}]).factory('xyzApiEvents', ['$rootScope', function ($rootScope) {
var evtNotFoundErr = 'xyzAPI Does not have an event called: ';
var events = {
"loggingIn": "xyzApi.loggedIn",
"loggedOut": "xyzApi.loggingIn",
"loggingIn": "xyzApi.loggingOut",
"loggedOut": " xyzApi.loggedOut"
}
var factory = {
raiseEvent: function (eventName, eventValue) {
if (!events.hasOwnProperty(eventName))
throw evtNotFoundErr + eventName;
$rootScope.$broadcast(events[eventName], eventValue);
},
on: function (eventName, callBack) {
if (!isFunction(callBack))
throw 'xyzApi: xyzApiEvents.on(eventName, callBack)... callBack must be a function!';
if (!events.hasOwnProperty(eventName))
throw evtNotFoundErr + eventName;
$rootScope.$on(events[eventName], function (evt, args) {
callBack(evt, args);
});
}
};
return factory;
}]);
function isFunction(functionToCheck) {
var getType = {};
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
}
})();
基本请求:
(function () {
angular.module('xyzApi').factory('baseRequest', ['$q', '$http', '$log', 'xyzApiEvents', function ($q, $http, $log, xyzApiEvents) {
var userOAuthToken = null;
var httpConfig = { headers: {} };
xyzApiEvents.on('loggingIn', function (event, oAuthToken) {
userOAuthToken = oAuthToken;
//set Authorization header for authorized web requests
httpConfig.headers['Authorization'] = userOAuthToken;
});
var baseUrl = '{{baseUrl}}'; //this is the url I need configured
return {
serviceUrl: function () {
return baseUrl;
},
get: function (sQuery) {
var deferred = $q.defer();
var url = baseUrl + sQuery;
$http.get(url, httpConfig).then(function(response) {
deferred.resolve(response);
}, function (errorResponse) {
$log.error(errorReponse);
deferred.reject(errorResponse);
}); //TODO Add Update Promise
return deferred.promise
},
post: function (sQuery, postData) {
var deferred = $q.defer();
var url = baseUrl + sQuery;
$http({
method: 'POST',
url: url,
headers: httpConfig.headers,
data: postData
}).then(function (response) {
deferred.resolve(response);
}, function (errorResponse) {
$log.error(errorResponse);
deferred.reject(errorResponse);
}); //TODO Add Update Promise
return deferred.promise;
}
}
}]);
})();
解决方案(感谢@Anzeo)
我有许多单独的服务,我将它们打包成一个服务作为 API 中的最后一个脚本:所以我将其设为提供者而不是将 baseRequest 设为提供者。此外,我必须将我的模块的名称更改为 xyzDataWebServices,因为我希望 xyzApi 成为 controller/directives 中使用的代码,并且提供者不能与其模块同名(这导致了问题).
(function () {
angular.module('xyzDataWebServices').provider('xyzApi', function () {
var baseUrl;
this.setBaseUrl = function (value) {
baseUrl = value;
};
this.$get = ['$log', 'baseRequest', 'xyzApiContext', 'xyzApiAuthentication', 'xyzApiLibrary', function xyzApiFactory($log, baseRequest, xyzApiContext, xyzApiAuthenication, xyzApiLibrary) {
baseRequest.setServiceUrl(baseUrl);
var factory = {
context: xyzApiContext,
authentication: xyzApiAuthenication,
library: xyzApiLibrary
}
return factory;
}];
});
})();
然后依赖它并配置服务Url:
<script type="text/javascript">
angular.module('app', ['ngAnimate', 'ngAria', 'ngMessages', 'ngTouch', 'ui.bootstrap', 'ui.router', 'xyzDataWebServices']).config(['$stateProvider', '$urlRouterProvider', 'xyzApiProvider', function ($stateProvider, $urlRouterProvider, xyzApiProvider) {
xyzApiProvider.setBaseUrl('@Utility.DataWebServiceUrl');
$urlRouterProvider.otherwise('/');
$stateProvider.state('login', {
url: '/',
templateUrl: 'assets/templates/login.html'
});
}]).factory('loginModel', [function () {
return {
userName: null,
password: null,
stayLoggedIn: false
};
}]);
</script>
我应该注意这是 MVC 5、Web Api 2 和 Angular。所以上面是在 Razor 模板 "Cshtml" 中,@Utility 是在 Utility class 上调用该方法的 Razor 语法。因此,当视图转换时,它会将 Web 服务 url 存储在 web.config 文件中。
我还使用 Web 配置转换来根据我部署到的服务器更改 Url。
简而言之,此 url 配置现在由部署驱动配置,我永远不必更改它。
注意* 我将所有内容都包含在函数中的原因是因为我的 API 被拆分成物理文件:例如
- xyzApi.js
- services[=61=]_debounce.js
- services_baseRequest.js
- services_context.js
- services_authentication.js
- services_etc.js
- xyzApiEnd.js
前面的数字只是为了方便按字母顺序排列,并且很容易更改以更改捆绑顺序。
xyzApi 是捆绑顺序中的第一个,然后服务按带通配符的字母顺序捆绑,然后 xyzApiEnd 最后捆绑。
您可以使用 Angular 的 Provider 机制实现可配置库。
基本上您要做的是围绕 service/factory/whatever 编写一个包装器。您可以将此包装器作为提供者注入 config 语句(即 `$httpProvider)。
angular.module('xyzApi').provider('baseRequest', function () {
});
然后您可以公开方法来为稍后(在 运行 阶段)使用的 service/factory 设置变量。
在您的情况下,您需要添加一个方法以允许用户设置 baseUrl,例如:
angular.module('xyzApi').provider('baseRequest', function () {
var baseUrl;
return {
setBaseUrl: function (providedBaseUrl) {
baseUrl = providedBaseUrl;
}
}
});
最后,添加特殊的$get
方法。 $injector 服务使用此方法来获取注入的实例 属性。
angular.module('xyzApi').provider('baseRequest', function () {
var baseUrl;
return {
setBaseUrl: function (providedBaseUrl) {
baseUrl = providedBaseUrl;
},
$get: function(/* here you can use other injected services */){
}
}
});
我总是将服务的实现包装在创建函数中。
将这些更改应用于您的代码会产生:
angular.module('xyzApi').provider('baseRequest', function () {
var baseUrl;
return {
setBaseUrl: function (providedBaseUrl) {
baseUrl = providedBaseUrl;
},
$get: function ($q, $http, $log, xyzApiEvents) {
return createBaseRequestFactory($q, $http, $log, xyzApiEvents, baseUrl);
}
};
function createBaseRequestFactory($q, $http, $log, xyzApiEvents, baseUrl){
var userOAuthToken = null;
var httpConfig = {headers: {}};
xyzApiEvents.on('loggingIn', function (event, oAuthToken) {
userOAuthToken = oAuthToken;
//set Authorization header for authorized web requests
httpConfig.headers['Authorization'] = userOAuthToken;
});
return {
serviceUrl: function () {
return baseUrl;
},
get: function (sQuery) {
var deferred = $q.defer();
var url = baseUrl + sQuery;
$http.get(url, httpConfig).then(function (response) {
deferred.resolve(response);
}, function (errorResponse) {
$log.error(errorReponse);
deferred.reject(errorResponse);
}); //TODO Add Update Promise
return deferred.promise
},
post: function (sQuery, postData) {
var deferred = $q.defer();
var url = baseUrl + sQuery;
$http({
method: 'POST',
url: url,
headers: httpConfig.headers,
data: postData
}).then(function (response) {
deferred.resolve(response);
}, function (errorResponse) {
$log.error(errorResponse);
deferred.reject(errorResponse);
}); //TODO Add Update Promise
return deferred.promise;
}
}
}
});
我有一个 angular 模块,它基本上是一个客户端 Web 服务层(正在进行中)。我有一个模块声明和一个名为 "baseRequest" 的工厂。 baseRequest 依赖于模块中的其他工厂。 BaseRequest 需要知道它将调用的 WebApi2 控制器的基础Url。
该脚本托管在站点 A:但将在站点 B、C、D、E 等上使用。因此,如果没有某些内容,它无法可靠地知道它是自己的 url配置数据。
基于此,我希望使用 api 的用户在添加脚本标签时必须对其进行配置。我设想他们必须在我的模块上调用配置,但我不确定如何在这个模块上实现它,并且被有关该主题的文档弄糊涂了:
(function () {
angular.module('xyzApi', []).run(['$http', function ($http) {
//Configure defaults on $http here if need be
}]).factory('xyzApiEvents', ['$rootScope', function ($rootScope) {
var evtNotFoundErr = 'xyzAPI Does not have an event called: ';
var events = {
"loggingIn": "xyzApi.loggedIn",
"loggedOut": "xyzApi.loggingIn",
"loggingIn": "xyzApi.loggingOut",
"loggedOut": " xyzApi.loggedOut"
}
var factory = {
raiseEvent: function (eventName, eventValue) {
if (!events.hasOwnProperty(eventName))
throw evtNotFoundErr + eventName;
$rootScope.$broadcast(events[eventName], eventValue);
},
on: function (eventName, callBack) {
if (!isFunction(callBack))
throw 'xyzApi: xyzApiEvents.on(eventName, callBack)... callBack must be a function!';
if (!events.hasOwnProperty(eventName))
throw evtNotFoundErr + eventName;
$rootScope.$on(events[eventName], function (evt, args) {
callBack(evt, args);
});
}
};
return factory;
}]);
function isFunction(functionToCheck) {
var getType = {};
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
}
})();
基本请求:
(function () {
angular.module('xyzApi').factory('baseRequest', ['$q', '$http', '$log', 'xyzApiEvents', function ($q, $http, $log, xyzApiEvents) {
var userOAuthToken = null;
var httpConfig = { headers: {} };
xyzApiEvents.on('loggingIn', function (event, oAuthToken) {
userOAuthToken = oAuthToken;
//set Authorization header for authorized web requests
httpConfig.headers['Authorization'] = userOAuthToken;
});
var baseUrl = '{{baseUrl}}'; //this is the url I need configured
return {
serviceUrl: function () {
return baseUrl;
},
get: function (sQuery) {
var deferred = $q.defer();
var url = baseUrl + sQuery;
$http.get(url, httpConfig).then(function(response) {
deferred.resolve(response);
}, function (errorResponse) {
$log.error(errorReponse);
deferred.reject(errorResponse);
}); //TODO Add Update Promise
return deferred.promise
},
post: function (sQuery, postData) {
var deferred = $q.defer();
var url = baseUrl + sQuery;
$http({
method: 'POST',
url: url,
headers: httpConfig.headers,
data: postData
}).then(function (response) {
deferred.resolve(response);
}, function (errorResponse) {
$log.error(errorResponse);
deferred.reject(errorResponse);
}); //TODO Add Update Promise
return deferred.promise;
}
}
}]);
})();
解决方案(感谢@Anzeo)
我有许多单独的服务,我将它们打包成一个服务作为 API 中的最后一个脚本:所以我将其设为提供者而不是将 baseRequest 设为提供者。此外,我必须将我的模块的名称更改为 xyzDataWebServices,因为我希望 xyzApi 成为 controller/directives 中使用的代码,并且提供者不能与其模块同名(这导致了问题).
(function () {
angular.module('xyzDataWebServices').provider('xyzApi', function () {
var baseUrl;
this.setBaseUrl = function (value) {
baseUrl = value;
};
this.$get = ['$log', 'baseRequest', 'xyzApiContext', 'xyzApiAuthentication', 'xyzApiLibrary', function xyzApiFactory($log, baseRequest, xyzApiContext, xyzApiAuthenication, xyzApiLibrary) {
baseRequest.setServiceUrl(baseUrl);
var factory = {
context: xyzApiContext,
authentication: xyzApiAuthenication,
library: xyzApiLibrary
}
return factory;
}];
});
})();
然后依赖它并配置服务Url:
<script type="text/javascript">
angular.module('app', ['ngAnimate', 'ngAria', 'ngMessages', 'ngTouch', 'ui.bootstrap', 'ui.router', 'xyzDataWebServices']).config(['$stateProvider', '$urlRouterProvider', 'xyzApiProvider', function ($stateProvider, $urlRouterProvider, xyzApiProvider) {
xyzApiProvider.setBaseUrl('@Utility.DataWebServiceUrl');
$urlRouterProvider.otherwise('/');
$stateProvider.state('login', {
url: '/',
templateUrl: 'assets/templates/login.html'
});
}]).factory('loginModel', [function () {
return {
userName: null,
password: null,
stayLoggedIn: false
};
}]);
</script>
我应该注意这是 MVC 5、Web Api 2 和 Angular。所以上面是在 Razor 模板 "Cshtml" 中,@Utility 是在 Utility class 上调用该方法的 Razor 语法。因此,当视图转换时,它会将 Web 服务 url 存储在 web.config 文件中。
我还使用 Web 配置转换来根据我部署到的服务器更改 Url。
简而言之,此 url 配置现在由部署驱动配置,我永远不必更改它。
注意* 我将所有内容都包含在函数中的原因是因为我的 API 被拆分成物理文件:例如
- xyzApi.js
- services[=61=]_debounce.js
- services_baseRequest.js
- services_context.js
- services_authentication.js
- services_etc.js
- xyzApiEnd.js
前面的数字只是为了方便按字母顺序排列,并且很容易更改以更改捆绑顺序。
xyzApi 是捆绑顺序中的第一个,然后服务按带通配符的字母顺序捆绑,然后 xyzApiEnd 最后捆绑。
您可以使用 Angular 的 Provider 机制实现可配置库。
基本上您要做的是围绕 service/factory/whatever 编写一个包装器。您可以将此包装器作为提供者注入 config 语句(即 `$httpProvider)。
angular.module('xyzApi').provider('baseRequest', function () {
});
然后您可以公开方法来为稍后(在 运行 阶段)使用的 service/factory 设置变量。
在您的情况下,您需要添加一个方法以允许用户设置 baseUrl,例如:
angular.module('xyzApi').provider('baseRequest', function () {
var baseUrl;
return {
setBaseUrl: function (providedBaseUrl) {
baseUrl = providedBaseUrl;
}
}
});
最后,添加特殊的$get
方法。 $injector 服务使用此方法来获取注入的实例 属性。
angular.module('xyzApi').provider('baseRequest', function () {
var baseUrl;
return {
setBaseUrl: function (providedBaseUrl) {
baseUrl = providedBaseUrl;
},
$get: function(/* here you can use other injected services */){
}
}
});
我总是将服务的实现包装在创建函数中。
将这些更改应用于您的代码会产生:
angular.module('xyzApi').provider('baseRequest', function () {
var baseUrl;
return {
setBaseUrl: function (providedBaseUrl) {
baseUrl = providedBaseUrl;
},
$get: function ($q, $http, $log, xyzApiEvents) {
return createBaseRequestFactory($q, $http, $log, xyzApiEvents, baseUrl);
}
};
function createBaseRequestFactory($q, $http, $log, xyzApiEvents, baseUrl){
var userOAuthToken = null;
var httpConfig = {headers: {}};
xyzApiEvents.on('loggingIn', function (event, oAuthToken) {
userOAuthToken = oAuthToken;
//set Authorization header for authorized web requests
httpConfig.headers['Authorization'] = userOAuthToken;
});
return {
serviceUrl: function () {
return baseUrl;
},
get: function (sQuery) {
var deferred = $q.defer();
var url = baseUrl + sQuery;
$http.get(url, httpConfig).then(function (response) {
deferred.resolve(response);
}, function (errorResponse) {
$log.error(errorReponse);
deferred.reject(errorResponse);
}); //TODO Add Update Promise
return deferred.promise
},
post: function (sQuery, postData) {
var deferred = $q.defer();
var url = baseUrl + sQuery;
$http({
method: 'POST',
url: url,
headers: httpConfig.headers,
data: postData
}).then(function (response) {
deferred.resolve(response);
}, function (errorResponse) {
$log.error(errorResponse);
deferred.reject(errorResponse);
}); //TODO Add Update Promise
return deferred.promise;
}
}
}
});