我有一个用于查询OData服务的角度提供程序。
现在我正在尝试在该提供程序上构建$ filter函数,因此我可以在整个应用程序中使用它。
我遇到的问题,到目前为止无法解决的问题是,网址的查询部分需要以' $ filter ='当有一个过滤器时我可以处理好,但是添加了多个过滤器作为'和{查询到这里}'。
示例查询将是:
http://www.example.com/odata/Restaurants/?$filter=id eq 2 and city eq 'Los Angeles' and substringof("Lagasse", chef)&$top=20
我将数组中的所有过滤器发送给提供商。理想情况下,我会使用" $ filter =#{firstFilter}"对于阵列中的第一个滤波器,对于剩余的滤波器,使用"和#{remainingFilter}"但我不确定如何构建这段代码。
我当前的代码使用多个if语句来检查过滤器是否存在,但是由于构建url的性质,它始终强制使用其中一个过滤器。我想避免这种情况。
例如:
var filter = "$filter=id eq 2";
if (city) {
filter += " and city eq #{cityName}";
}
if (chef) {
filter += " and substringof(#{chefName}, chef)";
}
现在,每当用户输入查询时,他们都必须指定一个id。
我们不使用BreezeJS,JayData或任何其他库。严格的AngularJS,特别是$ http,NOT $ resource。
答案 0 :(得分:4)
您可以使用odata-filter-builder为$filter part构建OData URL query options。
然后只需使用$http
和config params。
简短的例子:
var filter = ODataFilterBuilder()
.eq('id', 2)
.eq('city', 'Los Angeles')
.and('substringof("Lagasse", chef)')
.toString();
$http
.get(resourceUrl, {params: {$filter: filter, $top: 20}})
.then(function(response) {
// Handle response
})
完整示例:
angular
.module('OData', [])
.constant('ODataFilterBuilder', ODataFilterBuilder)
.factory('ODataService', function($http) {
return {
load: function(resourceUrl, queryParams) {
return $http.get(resourceUrl, {params: queryParams})
.then(function(response) {
return response.data.value;
});
}
}
});
angular
.module('app', ['OData'])
.controller('appController', function($http, ODataService, ODataFilterBuilder, $httpParamSerializer) {
// 1. inject ODataFilterBuilder
// use short name for filter builder
var f = ODataFilterBuilder;
// 2. build filter
var filter = f()
.eq('id', 2)
.eq('city', 'Los Angeles')
.and('substringof("Lagasse", chef)')
// 3. creater odata query params
var queryParams = {
$filter: filter.toString(),
$top: 20
// TODO: add other params
};
// 4. prepare odata resourse URL
var odataServiceUrl = 'http://path/to/odata/service/';
var odataResourseUrl = odataServiceUrl + 'entity';
// 5. Do http request with odataResourseUrl and queryParams
// use ODataService or angular $http service
// ODataService
// .load(odataResourseUrl, queryParams)
// .then(function(value) {
// // handle value
// });
// OR
// $http.get(odataResourseUrl, {params: queryParams})
// .then(function(respons) {
// // handle respons.data.value
// });
// Result examles:
// NOTE: $httpParamSerializer - default $http params serializer that converts objects to strings
var queryParamsSerialised = $httpParamSerializer(queryParams);
// put values to 'this' to use it in html
this.queryParams = queryParams;
this.queryParamsSerialised = queryParamsSerialised;
this.queryUrl = odataResourseUrl + '?' + queryParamsSerialised;
});
<div ng-app="app" ng-controller="appController as vm">
<pre>queryParams: {{vm.queryParams|json}}</pre>
<pre>queryParamsSerialised: {{vm.queryParamsSerialised}}</pre>
<pre>queryUrl: {{vm.queryUrl}}</pre>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<script src="https://npmcdn.com/odata-filter-builder@^0.1/dist/odata-filter-builder.js"></script>
答案 1 :(得分:2)
我知道你说你没有使用任何其他库,但万一其他人偶然发现了这个...我建议使用joData。它非常具有表现力,不需要其他依赖项:https://github.com/mccow002/joData
以下是joData中的示例:
var query = new jo('http://www.example.com/odata/Restaurants');
query.filter(new jo.FilterClause('id').eq(2))
.andFilter(new jo.FilterClause('city').eq('Los Angeles'))
.andFilter(new jo.FilterClause('chef').substringof('Lagasse').eq(true))
.top(2);
然后,
query.toString()
...产生
"http://www.example.com/odata/Restaurants?$top=2&$filter=id eq 2 and city eq 'Los Angeles' and substringof('Lagasse',chef) eq true"
无论如何,在这里为Angular设置这就是我所做的......
在你的angular.js引用之前引用你的html中的joData js。
将其包装在Angular服务中
angular.module(&#39; app.shared.oData&#39;,[]) .service(&#39; oDataBuilderService&#39;,function(){ this.jo = jo; };
现在其他服务可以使用此odata服务来构建odata查询:
angular.module(&#39; app.shared.video&#39;,[]) .service(&#39; videoService&#39;,function($ http,oDataBuilderService){
this.getByVideoCatalogId = function (videoCatalogId) {
var query = new oDataBuilderService.jo('http://www.example.com/VideoCatalog/OData');
var videoCatalogIdEquals = new oDataBuilderService.jo.FilterClause("VideoCatalogId").eq(videoCatalogId);
query.andFilter(videoCatalogIdEquals);
var queryAsString = query.toString();
var promise = $http.get(queryAsString);
return promise;
}
});
答案 2 :(得分:1)
我已经完成了类似的工作,我认为这是一个优雅的解决方案,不依赖于其他库。我使用Array.join并将过滤器与&#34;和#34;连接起来。他们之间:
var filter = [];
if (city) filter.push("City eq '" + city + "'");
if (chef) filter.push("Chef eq '" + chef + "'");
var filterQuery = filter.join(" and ");
这假设你总是想要&#34;和&#34;他们之间,(不是或),但在我的应用程序和您的示例中就是这种情况。我也这样做来建立网址:
var parts = [baseurl];
parts.push("$top=10");
parts.push("$skip=" + skip);
parts.push(filterQuery);
var url = parts.join("&");
答案 3 :(得分:0)
您最后可以添加$filter=
,但是&#34;和&#34;
更容易创建一个简单的函数
addFilter(currentFilter, filter) {
if (currentFilter.length == 0) {
currentFilter = "$filter=" + filter;
} else {
currentFilter += "and " + filter;
}
return currentFilter;
}
然后只需致电currentFilter = addFilter(currentFilter, "what to filter")
var currentFilter = "";
if (city) {
currentFilter = addFilter(currentFilter, "city eq #{cityName}");
}
if (chef) {
currentFilter = addFilter(currentFilter, "substringof(#{chefName}, chef)");
}