3

我有一个用于查询 OData 服务的角度提供程序。

现在我正在尝试在该提供程序上构建一个 $filter 函数,以便我可以在整个应用程序中使用它。

我遇到的问题,到目前为止还没有解决,是 URL 的查询部分需要以 '$filter=' 开头,当有一个过滤器但有多个过滤器时我可以处理得很好被添加为 ' 和 {query go here}'。

示例查询将是:

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,而不是 $resource。

4

4 回答 4

6

您可以使用odata-filter-builderOData URL 查询选项构建$filter 部分

然后只需使用$http配置参数。

简短的例子:

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>

于 2016-03-21T10:17:09.220 回答
3

我知道你说你没有使用任何其他库,但万一其他人偶然发现这个......我建议使用 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 设置它就是我所做的......

  1. 在 angular.js 引用之前在 html 中引用 joData js。

  2. 将其包装在 Angular 服务中

    angular.module('app.shared.oData', []) .service('oDataBuilderService', function () { this.jo = jo; };

  3. 现在其他服务可以使用这个 odata 服务来构造 odata 查询:

    angular.module('app.shared.video', []) .service('videoService', 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;
        }
    

    });

于 2015-06-11T01:12:15.123 回答
1

您可以$filter=在最后添加,但是您会遇到与“和”相同的问题

更容易的是创建一个简单的函数

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)");
}
于 2014-11-20T20:30:06.840 回答
1

我做过类似的事情,我认为这是一个优雅的解决方案,不依赖于其他库。我使用 Array.join 并将过滤器与它们之间的“和”连接起来:

var filter = [];
if (city) filter.push("City eq '" + city + "'");
if (chef) filter.push("Chef eq '" + chef + "'");
var filterQuery = filter.join(" and ");

这假设您总是想要它们之间的“和”,(不是或),但在我的应用程序和您的示例中就是这种情况。我也这样做来建立网址:

var parts = [baseurl];
parts.push("$top=10");
parts.push("$skip=" + skip);
parts.push(filterQuery);
var url = parts.join("&");
于 2016-04-22T04:38:43.040 回答