Giter Site home page Giter Site logo

odataangularresources's Introduction

Build Status Coverage Status CDNJS

ODataAngularResources

ODataAngularResources is a fork of Angular's $resource that allows to make OData queries in a fluent way. It does everything Angular Resources does but add some features:

  • Fluent API
  • Generate proper OData queries without worrying about escaping the right characters
  • Allows filtering, skipping, ordering, expanding, and selecting only N elements (with top)
  • Able to generate complex queries with OR, AND and method calls

Simple JSFiddle Demo

Table of Contents

How to install

  1. Download the repository or install the bower package :
bower install angular-odata-resources --save

or

npm install angular-odata-resources --save
  1. Include the file build/odataresources.js into your project
  2. Be sure to register the module "ODataResources" in your module definition :
var myModule = angular.module('myModule',['ODataResources']);
  1. Then replace your dependency to "$resource" by "$odataresource"
myModule.controller('MyController', ['$scope','$odataresource',function($scope,$odataresource){}]);

How to use

Simple query

  • Call the odata() method on your resource.
var User = $odataresource('/user/:userId', {userId:'@id'});
var myUsers =   User.odata()
                    .filter("Name","John")
                    .query(); 
//Queries /user?$filter=Name eq 'John'
  • The first parameter of the filter method is assumed to be the property and the second to be the value. But that behavior can be overriden by passing special parameters. See advanced queries for more informations.

  • Returned objects from the query() method are regular Resource object which can be used for saving, updating etc...

myUsers[0].$save();
  • Like regular Resource requests you can pass callback that will be called on success and on error
var myUsers =   User.odata()
                    .query(function(){
                        console.log("Everything went ok!")
                    },function(){
                        console.log("Oops, something wrong happened!")
                    }); 

Retrieving a single element

  • Simply call the get method with the entity key
var userId = 10;
var myUsers =   User.odata().get(userId);
//Queries /user(10)
  • You can also provide callbacks
var userId = 10;
var myUsers =   User.odata().get(userId,
                          function(){
                            console.log("Everything went ok!")
                        },function(){
                            console.log("Oops, something wrong happened!")
                        });

If you want to retrieve a single element after a query you can use the single() method which will take the first elements of the response. This method will throw if the reponse returns an empty array.

var User = $odataresource('/user/:userId', {userId:'@id'});
var myUser =   User.odata()
                    .filter("Name","John")
                    .single(); 
//Queries /user?$filter=Name eq 'John' and put the first element into myUser

Query with top, orderBy and skip

var User = $odataresource('/user/:userId', {userId:'@id'});
var myUsers =   User.odata()
    				.filter("Name", "John")
    				.filter("Age",">",20)
    				.skip(10)
    				.take(20)
    				.orderBy("Name","desc")
    				.query();
                    
//Queries /user?$filter=(Name eq 'John') and (Age gt 20)&$orderby=Name desc&$top=20&$skip=10
  • Multiple chained filters are executed with and between.
  • orderBy assumes the order to be asc if the second parameter is not specified.

Count and InlineCount

  • It's possible to query the number of elements
                var data = User.odata().filter('name','bob').count();
                    
//Queries /user/$count/?$filter=name eq 'bob'
// data.result == 25
  • You can also ask for an inline count to have the count aside with the data
                var users = User.odata().withInlineCount().query();
                
//Queries /user?$inlinecount=allpages
// users is an array but also contains the count property
// The server may reply by
// {
//     "@odata.context": "http://host/service/$metadata#Collection(Edm.String)",
//     "value": [{
//         name: 'Test',
//         id: 1,
//     }, {
//         name: 'Foo',
//         id: 2,
//     }],
//     'count': 10
// }
// And then, the count will be defined as followed
// users.count == 10

Including related models (Expanding)

  • You can easily include related models by calling the expand method
var User = $odataresource('/user/:userId', {userId:'@id'});
var myUsers =   User.odata()
                    .expand("City")
                    .query();
                    
//Queries /user?$expand=City
  • You can also expand nested related models like the Country of the City of the User
var User = $odataresource('/user/:userId', {userId:'@id'});
var myUsers =   User.odata()
                    .expand("City","Country")
                    .query();
                    
//Queries /user?$expand=City/Country
  • You can also include multiple related models into your query
var myUsers =   User.odata()
                    .expand("City")
                    .expand("Orders")
                    .query();
                    
//Queries /user?$expand=City,Orders

Pick a subset of the properties (Selecting)

  • You can use the select method to retrieve only some properties of the entities.
var User = $odataresource('/user/:userId', {
        userId: '@id'
    });
    
    var users = User.odata().select(['name','userId']).query();
    //OR
    var users = User.odata().select('name','userId').query();                    

//Queries /user?$select=userId,name

Specifying a custom url and method

  • Want a custom url for your odata queries? easy! It works just like angular resources:
User = $odataresource('/user/:userId',
                     { userId: '@id'},
                	 {
                		odata: {
                			method: 'POST',
                			url: '/myCustomUrl'
                		}
                	 }
	);

Specifying the response format

var myUsers =   User.odata()
					.format("json")
                    .expand("City")
                    .expand("Orders")
                    .query();
                    
//Queries /user?$format=json&$expand=City,Orders

Advanced queries

Predicates

  • If you need to write or statements in your queries, you need to use the Predicate class. First, be sure to reference the $odata dependency.
myModule.controller('MyController', ['$scope','$odataresource','$odata',function($scope,$odataresource,$odata){}]);
  • Now you can use the $odata.Predicate class wich allow advanced filtering.
var predicate1 = new $odata.Predicate("FirstName", "John");
var predicate2 = new $odata.Predicate("LastName", '!=', "Doe");
//
combination = $odata.Predicate.or([predicate1,predicate2]);
User.odata().filter(combination).query();
//Queries /user?$filter=(FirstName eq 'John') or (LastName ne 'Doe');
  • You can even combine predicates with predicates
var predicate1 = new $odata.Predicate("FirstName", "John");
var predicate2 = new $odata.Predicate("LastName", '!=', "Doe");
var predicate3 = new $odata.Predicate("Age", '>', 10);
//
combination1 = $odata.Predicate.or([predicate1,predicate2]);
combination2 = $odata.Predicate.and([combination1,predicate2]);
User.odata().filter(combination).query();
//Queries /user?$filter=((FirstName eq 'John') or (LastName ne 'Doe')) and Age gt 10
  • You can also achieve the same results with the fluent api
var predicate = new $odata.Predicate("FirstName", "John")
                            .or(new $odata.Predicate("LastName", '!=', "Doe"))
                            .and(new $odata.Predicate("Age", '>', 10));
//
User.odata().filter(predicate).query();
//Queries /user?$filter=((FirstName eq 'John') or (LastName ne 'Doe')) and Age gt 10

Overriding default Predicate or Filter behavior

It is sometime necessary to compare two properties or two values in a query. To do so, you can use the $odata.Value or $odata.Property classes

var predicate = new $odata.Predicate(
                            new $odata.Value('Foo'),
                            new $odata.Value('Bar')
                            );
//
User.odata().filter(predicate).query();
//Queries /user?$filter='Foo' eq 'Bar'

Or with two properties :

User.odata().filter(
                    new $odata.Property('Name'),
                    new $odata.Property('Surname')
                    ).query();
//Queries /user?$filter=Name eq Surname

Specifying the type of the data

This library is clever enough to figure out the types from the data passed and format them accordingly. But sometimes you may need to have a specific output type. In this case you can pass a second argument to the $odata.Value() constructor :

User.odata().filter(
                    'Latitude',
                    new $odata.Value(40.765150,"Decimal")
                    ).query();
//Queries /user?$filter=Latitude eq 40.765150M

User.odata().filter(
                    'Latitude',
                    new $odata.Value("75.42","Int32")
                    ).query();
//Queries /user?$filter=Latitude eq 75


User.odata().filter(
                    'Latitude',
                    new $odata.Value("true","Boolean")
                    ).query();
//Queries /user?$filter=Latitude eq true


User.odata().filter(
                    'Latitude',
                    new $odata.Value(10,"Boolean")
                    ).query();
//Queries /user?$filter=Latitude eq true

Here is the complete list of supported types :

Type Name Output example
Boolean true
Byte FE
DateTime datetime'2000-12-12T12:00'
Decimal 2.345M
Double 2.0d
Single 2.0f
Guid guid'12345678-aaaa-bbbb-cccc-ddddeeeeffff'
Int32 51358
String 'Hello OData'

Function calls

  • You can call functions like endswith or length on an OData query. To do so, use the $odata.Func class.
var users = User.odata()
              .filter(new $odata.Func("endswith","FullName","Doe"), true)
              .query();
//Queries /user?$filter=endswith(FullName, 'Doe') eq true

Definition

new $odata.Func(MethodName, PropertyName, Value1, Value2,...)

The parameters are assumed to be first, a property and then a value. This behavior can be overriden by specifying explicit values or properties :

new $odata.Func('substringof',
                  new $odata.Value('Alfreds'),
                  new $odata.Property('CompanyName'));

List of available functions

Function Example Example value
String Functions
bool substringof(string po, string p1) new $odata.Func('substringof',new $odata.Value('Alfreds'), new $odata.Property(CompanyName)) true
bool endswith(string p0, string p1) new $odata.Func('endswith','CompanyName', 'Futterkiste') true
bool startswith(string p0, string p1) new $odata.Func('startswith','CompanyName', 'Alfr') true
int length(string p0) new $odata.Func('length','CompanyName') 19
int indexof(string p0, string p1) new $odata.Func('indexof','CompanyName', 'lfreds') 1
string replace(string p0, string find, string replace) new $odata.Func('replace','CompanyName', ' ', '') AlfredsFutterkiste
string substring(string p0, int pos) new $odata.Func('substring','CompanyName', 1) lfreds Futterkiste
string substring(string p0, int pos, int length) new $odata.Func('substring','CompanyName', 1, 2) lf
string tolower(string p0) new $odata.Func('tolower','CompanyName') alfreds futterkiste
string toupper(string p0) new $odata.Func('toupper','CompanyName') ALFREDS FUTTERKISTE
string trim(string p0) new $odata.Func('trim','CompanyName') Alfreds Futterkiste
string concat(string p0, string p1) new $odata.Func('concat','City', new $odata.Property('Country')) Berlin Germany
Date Functions
int day(DateTime p0) new $odata.Func('day','BirthDate') 8
int hour(DateTime p0) new $odata.Func('hour','BirthDate') 0
int minute(DateTime p0) new $odata.Func('minute','BirthDate') 0
int month(DateTime p0) new $odata.Func('month','BirthDate') 12
int second(DateTime p0) new $odata.Func('second','BirthDate') 0
int year(DateTime p0) new $odata.Func('year','BirthDate') 1948
Math Functions
double round(double p0) new $odata.Func('round','Freight') 32d
decimal round(decimal p0) new $odata.Func('round','Freight') 32
double floor(double p0) new $odata.Func('round','Freight') 32d
decimal floor(decimal p0) new $odata.Func('floor','Freight') 32
double ceiling(double p0) new $odata.Func('ceiling','Freight') 33d
decimal ceiling(decimal p0) new $odata.Func('floor','Freight') 33
Type Functions
bool IsOf(expression p0, type p1) new $odata.Func('isof','ShipCountry', 'Edm.String') true

Lambda Operators

The $odata.Func class also supports the lambda operators any and all

new $odata.Func(LambdaOperator, PropertyName, LambdaVariable, Expression)

The parameters are assumed to be first, a lambda operator, a property name, a lambda variable, and a boolean expression. The boolean expression must use the lambda variable to refer to properties of the related entities identified by the navigation path.

var predicate1 = new $odata.Predicate("c/FirstName", "Bobby");
var predicate2 = new $odata.Predicate("c/LastName", "McGee");
//
var combination = $odata.Predicate.and([predicate1,predicate2]);
//
var func = new $odata.Func('any', 'clients', 'c', combination);
//
Jobs.odata().filter(func).query();
//Queries /Jobs?$filter=clients/any(c:((c/FirstName eq 'Bobby') and (c/LastName eq 'McGee')))

OData V4 support

This project supports basic odata v4 queries and responses. If the server responds with an array wrapped inside an object :

{
  "@odata.context":"http://local.testsite.com/odata/$metadata#TestData",
   "value":[
    {
      "TestId":1,"name":"test 1"
    },{
      "TestId":2,"name":"test 2"
    }
  ],
"totalCount":10
}

The api will still return the array provided in the value property and everything else will be set as properties of the array.

var User = $odataresource('/user/:userId', {userId:'@id'});
var myUsers =   User.odata()
                    .filter("Name","John")
                    .query(); 

//... later

console.log(myUsers[0].name);
console.log(myUsers.totalCount);

Updating entries with OData v4

You can use the $update method on an object. But for that you need to specify what is the property that contains the key.

There is two way of doing so :

  • Provide the key property as a second argument.
User = $odataresource('/user', 'id');
var myUsers = User.odata.query();

//... later
myUsers[0].$update();
//Will issue a PUT /user(1)
  • Or provide it as a property of the 4th argument.
User = $odataresource('/user', {},{},{odatakey : 'id'});
var myUser = new User();

myUser.$save();
//Will issue a POST /user

myUser.$update();
//Will issue a PUT /user(1)

myUser.$delete();
//Will issue a DELETE /user(1)
  • You can provide a comma seperated list of id's for complex key tables.
User = $odataresoure('/userroles', {},{},{odatakey: 'id,roleid'});
var myUser = new User();

myUser.$update();
//will issue a POST /user(id=1,roleid=2)

Expand and Odata v4

With odatav4 expanding nested entities is done with a different query

/user?$expand=Order/Items

becomes

/user?$expand=Order($expand=Items)

To enable this behavior set the isodatav4 property to true when invoking the $odataresource method:

User = $odataresource('/user', {}, {}, {
    odatakey: 'id',
    isodatav4: true
});

var result = User.odata().expand("roles", "role").query();
//  /user?$expand=roles($expand=role)

You can use the expand predicate for complex expand scenarios (such as parsing your metadata and applying a default schema to a query):

var result = User.odata().expandPredicate("roles").select("name").finish().query();
// /user?$expand=roles($select=name)

ExpandPredicate returns the Expand context and finish returns the base OdataProvider context, so make sure to finish the expandPredicate.

You can nest expands as well:

// grab odata context
var query = User.odata();
// add expand roles table and select roles.name
query.expandPredicate("roles").select("name").finish();
// add and save the context for the provider table and select provider.name, also expand provider -> settings (automatically calls finish())
var providertype = query.expandPredicate("provider").select("name").expand("settings");
// add provider type table and finish out both the provider type and provider expandPredicate contexts
providertype.expandPredicate("providertype").finish().finish();
// run the query
query.query();

// or inline

var query = User.odata().expandPredicate("roles").select("name").finish().expandPredicate("provider").select("name").expand("settings")
  .expandPredicate("providertype").finish().finish().query();

// /user?$expand=roles($select=name),provider($select=name;expand=settings,providertype)

InlineCount with OData v4

  • With OData v4 inlinecount issues a $count=true parameter
                var users = User.odata().withInlineCount().query();
                
//Queries /user?$count=true
// users is an array but also contains the count property
// The server may reply by
// {
//     "@odata.context": "http://host/service/$metadata#Collection(Edm.String)",
//     "@odata.count":10,
//     "value": [{
//         name: 'Test',
//         id: 1,
//     }, {
//         name: 'Foo',
//         id: 2,
//     }]
// }
// And then, the count will be defined as followed
// users.count == 10

Transform the final query url

  • It is possible to transform the query that will be made to the server by calling the method transformUrl
User.odata()
    .filter("Name", "Raphael")
    .transformUrl(function(url){
        return url+'&foo=bar';
    })
    .query();

// queries /user?$filter=Name eq 'Raphael'&foo=bar                    

The Promise Chain

When you retrieve a resource from the API, you are returned a Resource object or Array of Resources with the $http call being appended to the $promise property. This promise has already been chained through two phases. A intereptor phase for $http request success or errors. These are not to be confused with $http request and response interceptors, but follow the same ceonepts with argumets and return values. After the interceptor phase is the callback phase for per request success or error handling.

Interceptors

Interceptor handlers can be defined for each action you define for the actions object argument to $odataresource. Both succes and error interceptor handlers get called withe the $http response object passed as their single argument. There is a default handler defined for the success interceptor phase on each action defined with $odataresource that returns argument.resource. To maintain continuous support from $odataresource prototype methods (save, update, delete, etc), you should return this object from you success interceptor if you override the default one.

User = $odataresource('/user', {}, {
    odata: {
      interceptor: {
        response: function(response) {
          // response is the returned $http result with the parsed Resource object on response.resource.
          apiLog.logSuccess(response);
          return response.resource;
        },
        responseError: function(response) {
          // response is the returned $http result
          apiLog.logError(response, response.headers());
        },
      },
    },
  }, {});

Callbacks

Callbacks can be provided to each API call by passing a method reference in the parameters to the $odataresource api call. The success callback is provided if you want a convient way to inject into the promise chain when calling the api query. Both the final Resource object and the $http response headers are provided as parameters an available success callback handler. The error callback handler will provide you with any error message that might get thrown during parsing the $http response and building the Resource object.

var User = $odataresource("/user", {}, {}, {});
var user = User.odata().select("FirstName","LastName").query(function(resource, headers) {
    resource.Name = resource.FirstName + ' ' + resource.LasstName;
  }, function(error) {
    apiLog.logError(error);
  });

Error Correction

The error interceptor and callback handling has been enhanced to provide an opportunity for error handling and correction measures to be applied to the original $odataresource settings. The response from both the error interceptor and the error callback can provide corrected data back to the promise chain to merge into the final Resource object. The correction can be in the form of a new Resource object, a new Resource object promise, an $http promise, or an object with a property named $correction containing new arguments for the $oataresource object (url, defaultParams, actions, options). If the new promise, or correction results in another error, the error correction attempt will stop and reject, preventing an infinate loop.

User = $odataresource('/user', {}, {
    odata: {
      interceptor: {
        response: function(response) {
          // response is the returned $http result with the parsed Resource object on response.resource.
          apiLog.logSuccess(response);
          return response.resource;
        },
        responseError: function(response) {
          // response is the returned $http result
          apiLog.logError(response, response.headers());
          return { $correction: { url: 'https://fixedUrl.com/' } };
        },
      },
    },
  }, {});

Refreshing Responses & Odata Query Persistence

Support has been added to keep track of queries used to retrieve entities. You can call the $refresh method on a returned array of resources, or an individual resource object itself to get an updated entity from the API. The odata query applied to the refresh GET will depend on how the object you're calling the $refresh method on was retrieved. There are two types of persisted queries, full and limited. Full will store the entire list of odata arguments you supplied to reproduce the same result set. Limited will limit the query to selects, expands, and format. Limited assumes you're getting a single entity from a larger query, and want to keep the response equal to the initial object, ie same selects, expands, but dont need the filter/take/skip/etc odata arguments.

Persistence

To apply persisted query arguments to the provider manually call the 're' method.

var newUser = userResource.$odata().re().query();

Or you can enable this behavior by default.

var User = $odataresource("/user", {}, {}, { isodatav4: true, odatakey: "id", persistence: true } );
var user = User.odata().select("name").query();
var newUser = user.$odata().query();

$refresh

Persistence is applied automatically with or without the persistence options flag when using $refresh.

Use the following table to determine the query that will be appllied to the refresh:

Initial OdataProvider Call Target Persistence
var array = resource.odata().query(); var array = array.$refresh(); full
var array = resource.odata().query(); var entity = array[0].$refresh(); limited
var entity = resource.odata().get(1); var entity = entity.$refresh(); limited
var entity = resource.odata().single(); var entity = entity.$refresh(); full
var count = resource.odata().count(); var count = count.$refresh(); full

Build from the source

  1. You need Grunt installed globally:
> npm install -g grunt
  1. Then run
> npm install
> grunt build

Run the tests

  • Simply run
> grunt test

Contribute

Want to contribute? Great! Be sure to write tests before submitting your pull request.

odataangularresources's People

Contributors

bamand avatar bodia-uz avatar dclaze avatar depend86 avatar devnixs avatar grensjo avatar hbdbim avatar k-soze avatar kennynaoh avatar knight-bubble avatar kyse avatar maurosala avatar nicojuicy avatar shvydky avatar subpx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

odataangularresources's Issues

Parsing OData WebAPI Response.

This is working with basic OData endpoints, but when you use the OData v4 endpoints, it's failing to recognize the response as a valid one. It's expecting the response to be a simple array, but the ODataController sends back a more complex response type:

{
  "@odata.context":"http://local.testsite.com/odata/$metadata#TestData","value":[
    {
      "TestId":1,"Name":"test 1"
    },{
      "TestId":2,"Name":"test 2"
    },{
      "TestId":3,"Name":"test 3"
    },{
      "TestId":4,"Name":"test 4"
    },{
      "TestId":5,"Name":"test 5"
    }
  ]
}

Notice that this is an object, not an array. We need to unwrap the OData context wrapper, in order to get the "value" property which is what we want.

This is a relatively easy fix. On line 316 of the ODataResources.js file, we just need to add a simple if statement to detect the wrapper:

if (angular.isString(data['@odata.context'])) {
     data = data.value;
}

OData 2.0 result set

Data returned from OData 2.0 is structured like:
{ d : { results : [{ ... }, { ... }] } }

As the ODataAngularResources expects an array, the following error message is thrown:
Expected response to contain an array but got an object

Changing code below is solving this issue for me:

var promise = $http(httpConfig).then(function(response) {
                var data = response.data,
                  promise = value.$promise;

To

var promise = $http(httpConfig).then(function(response) {
                var data = response.data.d.results,
                  promise = value.$promise;

Can i use with RestAngular

Hi and thanks for this useful library.
I'm trying to integrate Odata to my AngularJS project and i initialiy use the Restangular, your library use instead $resource to make it's own Resource. Is it then possible to use this library without the use of the $odataService ??

Error: $injector:modulerr Module Error

After I added the service to the module the app crashed giving "Error: $injector:modulerr Module Error"

here is my app.js

(function(){
    var app = angular.module("access-control",["ODataResources", "ngRoute"]);
    app.config(function($routeProvider) {
        $routeProvider
            .when("/main",{
                templateUrl: "views/main.html",
                controller: "MainController"
            })
            .otherwise({redirectTo: "/error"});
    })
}())

and that's my js ref in index.html

<script src="bower_components/angular/angular.min.js"></script>
<script src="bower_components/angular-route/angular-route.min.js"></script>
<script src="bower_components/angular-odata-resources/buid/odataresources.min.js"></script>
<script src="js/app.js"></script>
<script src="js/controllers/MainController.js"></script>

what did I miss ?

Angular material integration

I am trying to integrate this to run with angular material select.

http://codepen.io/pen/?editors=1010

That link shows how to implement the async to show. I am told to use a promise and that will run it but I cant get it to run. Currently I am using the code below.

fObject.get = function (queryObject)
            {
                $rootScope.loading = true;
                rsrcObject.query(queryObject,
                        function (data)
                        {
                            $rootScope.loading = false;
                            fObject.list = data;
                        },
                        function (data)
                        {
                            $rootScope.loading = false;
                            baseSrvc.returnError(data);
                        });
            };

Problem using Guid datatype in OData v4 query

I have this query:

Companies
    .filter("Id", new $odata.Value('3240569b-79f5-41b6-9a51-02fcc2aef24f', "Guid"))
    .query();

It results in this URL:
[...]/odata/Sites?$filter=Id eq guid'3240569b-79f5-41b6-9a51-02fcc2aef24f'

Which gives this error message:

{
  "error":{
    "code":"","message":"The query specified in the URI is not valid. Unrecognized 'Edm.String' literal 'guid'3240569b-79f5-41b6-9a51-02fcc2aef24f'' at '6' in 'Id eq guid'3240569b-79f5-41b6-9a51-02fcc2aef24f''."
  }
}

If I remove the "guid" prefix and the quotes around the GUID, everything works fine. This is in accordance with the OData v4 spec: https://www.oasis-open.org/committees/download.php/50849/odata-v4.0-wd04-part2-url-conventions-2013-09-27.docx (see section 5.1.1.6.1). I have specified isodatav4: true to $odataresource.

Issue in MethodCall -> any lambda function

Hi,

We are trying to use the following code to generate the URL filter which looks like the below:

$filter=orgAssociations/any(o:o/orgJobs/any(oj:oj/departmentCode eq 'f1'))
When we call the filter, the generated URL is

$filter=orgAssociations/any(o:o/rgJobs/any(o:o/(departmentCode eq 'f1'))

Please see the above URL where the letter o from orgJobs is omitted. Also, the bracket in the end is missing in the generated URL.

Code snippet below:

presourceClass.odata().filter(new $odata.Func('any','orgAssociations',
                            new $odata.Func('any',
                                new $odata.Property('orgJobs'),
                                new $odata.Predicate('departmentCode',
                                'f1')
                                )
                            ));

          //$filter=orgAssociations/any(o:o/rgJobs/any(o:o/(departmentCode eq 'f1'))
          console.log(provider.execute() + ' -> url');

I traced the issue to the following line:

https://github.com/devnixs/ODataAngularResources/blob/master/src/odatamethodcall.js#L43

i.e. change
invocation += expression.substring(1, expression.length-1);
to
invocation += expression;
If we comment out the above line, then everything is getting generated as expected.

Another issue is with the line below:

https://github.com/devnixs/ODataAngularResources/blob/master/src/odatamethodcall.js#L39

Since both orgAssociations and orgJobs has the same first character 'o', the variable name is the same which results in an error. Hence the strategy of using the first character for variable name is not working.

Please advise.

Inheritance problem..

Hello , I have a problem to save my object in my OData API with angular restangular in my app.
I have the following classes on my server :

abstract Accessoire
    - AccessoiresType1 : Accessoire 
    - AccessoiresType2 : Accessoire 
abstract Vehicule
  Vehicule has a list of Accessoires 
    - Moto : Vehicule 

When i try this :

var urlBase = 'http://localhost:63891/odata/';
var Accessoire = $odataresource(urlBase + 'Accessoires', {}, actions, {odatakey: 'Id', isodatav4: true});
var Accessoire1 = $odataresource(urlBase + 'AccessoiresType1', {}, actions, {odatakey: 'Id', isodatav4: true});
var Moto = $odataresource(urlBase + 'Motos', {}, actions, {odatakey: 'Id', isodatav4: true});

var accessoire1 = new Accessoire1();
accessoire1.Libelle = "test ac1";

var moto = new Moto();
moto.SpecifiqueMoto = "spec moto1";
moto.Accessoires = []
moto.Accessoires.push(accessoire1);
moto.$save();`

I get the following error :

{
  "error":{
    "code":"","message":"The request is invalid .","innererror":{
      "message":"moto : Can not create an abstract class.","type":"","stacktrace":""

    }
  }
}

Do you have a solution ?

Thank you.
Maiwenn

Problem with fetching form odata v3

When i try to use this:

$odataresource("http://services.odata.org/Northwind/Northwind.svc/Orders").odata().withInlineCount().query()

I get this error:

Error: [$resource:badcfg] Error in resource configuration for action `odata`. Expected response to contain an array but got an object (Request: GET http://services.odata.org/Northwind/Northwind.svc/Orders?$inlinecount=allpages)
http://errors.angularjs.org/1.4.5/$resource/badcfg?p0=odata&p1=array&p2=obj…odata.org%2FNorthwind%2FNorthwind.svc%2FOrders%3F%24inlinecount%3Dallpages
    at REGEX_STRING_REGEXP (http://localhost:5001/vendor/angular/angular.js:68:12)
    at angular.module.provider.$get.Resource.(anonymous function).$http.then.value.$resolved (http://localhost:5001/vendor/angular-odata-resources/build/odataresources.js:942:27)

Looks like the problem is simple, it expects an array, but the endpoint returns an object, containing the 'value' attribute that contains the array.

Calling custom methods that are bound on OData Collections

I'm trying to use ODataAngular Resources on our ASP.Net OData v4 API project, and it was good going until I got to the point that I had to call our custom method to verify a token and email on my Accounts collection. The Verify method is bound to the Accounts collection with the namespace Service in my API.

It looks like I've got the URL right and gotten it called using the query() method on ODataAngularResources. The called URL looks like this:

GET XHR https://localhost/api/Accounts/Service.Verify(Email='[email protected]',Token='605705') [HTTP/1.1 200 OK 9ms]

The problem is that it looks like the response (A boolean) is not being parsed properly by the query() method, where it looks like it is expecting an array instead. Here's the error that is being thrown:

12:23:01.155 "Error: [$resource:badcfg] Error in resource configuration for action `odata`. Expected response to contain an array but got an object (Request: GET //localhost/api/Accounts/Service.Verify(Email='[email protected]',Token='605705'))
http://errors.angularjs.org/1.3.15/$resource/badcfg?p0=odata&p1=array&p2=object&p3=GET&p4=%2F%2Flocalhost%2Fapi%2FAccounts%2FService.Verify(Email%3D'asdf%asdf.com'%2CToken%3D'605705')
minErr/<@https://localhost/bower_components/angular/angular.js:63:12
resourceFactory/</Resource[name]/promise<@https://localhost/bower_components/angular-odata-resources/build/odataresources.js:942:1
processQueue@https://localhost/bower_components/angular/angular.js:13248:27
scheduleProcessQueue/<@https://localhost/bower_components/angular/angular.js:13264:27
$RootScopeProvider/this.$get</Scope.prototype.$eval@https://localhost/bower_components/angular/angular.js:14466:16
$RootScopeProvider/this.$get</Scope.prototype.$digest@https://localhost/bower_components/angular/angular.js:14282:15
$RootScopeProvider/this.$get</Scope.prototype.$apply@https://localhost/bower_components/angular/angular.js:14571:13
done@https://localhost/bower_components/angular/angular.js:9698:36
completeRequest@https://localhost/bower_components/angular/angular.js:9888:7
requestLoaded@https://localhost/bower_components/angular/angular.js:9829:1
"1 angular.js:11655:18
consoleLog/<() angular.js:11655
$ExceptionHandlerProvider/this.$get</<() angular.js:8596
processQueue() angular.js:13256
scheduleProcessQueue/<() angular.js:13264
$RootScopeProvider/this.$get</Scope.prototype.$eval() angular.js:14466
$RootScopeProvider/this.$get</Scope.prototype.$digest() angular.js:14282
$RootScopeProvider/this.$get</Scope.prototype.$apply() angular.js:14571
done() angular.js:9698
completeRequest() angular.js:9888
requestLoaded() angular.js:9829

Any ideas or suggestions would be much appreciated, I'm stuck on this.

Patch/Merge

I haven't seen support for patch/merge.

Do you have plans to support this? I'll probably help you write it ( but in a later phase of my current project).

It's enabled by default in odata web api scaffolder.

I use this in a current project of mine and the author helped the team of odata / webapi: https://github.com/Starcounter-Jack/JSON-Patch

DbGeography

I would add DbGeography to your library ( odata v4), any thoughts before i begin? I don't see something similar to it in odataValue:

Example below:

{
    "@odata.context":"http://subdomain.mydomain.me/odata/$metadata#Pois","value":[
      {
          "Id":"d57e6603-5530-4457-b041-6398b7182173","Name":"Demo Home","Address":"Zuidstraat 8 8630 Veurne","Location":{
              "Geography":{
                  "CoordinateSystemId":4326,"WellKnownText":"POINT (51.515574 2.025285)","WellKnownBinary":null
              }
          },"TagId":"ec32e8f3-c0b8-4bcc-af6c-7059b1ef1a65","RouteId":null
      }
    ]
}

Danger is, i need to fork the library to use the "odata" .Net version, based on : http://www.odata.org/blog/geospatial-data-support-in-odata/ . There seem to be some differences with my example code above.

Or should i add the standard and add a wrapper arround the .Net DbGeography type and release a nuget package, so it becomes the standard as described on the odata website?

"GeographyPoint": {"type": "Point","coordinates":[142.1,64.1]}

405 Method Not Allowed

I am trying to do a get but it keeps going through as options how do I fix this?

Request Method:OPTIONS
Status Code:405 Method Not Allowed

getUrl?

Love this library, I'm using it to help make a dynamic query builder.

I'm wondering if there's a way to simply get the built-out URL? Something like this, but less verbose. I did not see a typeScript definition that would do this. It would be handy to display to the user the query they are generating with the UI. If not, I could maybe make PR based on the transformUrl function.

Here's how I'm wrapping it currently

   getUrl(filter):string => {
    var theUrl ='';
    this.buildOdataResource([filter]).transformUrl(function(url){
      console.log('this.buildOdataResource >> ', url );
      theUrl = url;
      return url;
    });
   return theUrl;
}

this is what I see as available functions:


class Provider<T> {
    private callback;
    private filters;
    private sortOrders;
    private takeAmount;
    private skipAmount;
    private expandables;
    constructor(callback: ProviderCallback<T>);
    filter(operand1: any, operand2?: any, operand3?: any): Provider<T>;
    orderBy(arg1: string, arg2?: string): Provider<T>;
    transformUrl(transformMethod : (url:string)=>string): Provider<T>;
    take(amount: number): Provider<T>;
    skip(amount: number): Provider<T>;
    private execute();
    query(success?: ((p:T[])=>void), error?: (()=>void)): T[];
    single(success?: ((p:T)=>void), error?: (()=>void)): T;
    get(key: any, success?: ((p:T)=>void), error?: (()=>void)): T;
    expand(...params: string[]): Provider<T>;
    expand(params: string[]): Provider<T>;
    select(...params: string[]): Provider<T>;
    select(params: string[]): Provider<T>;
    count(success?: (result: ICountResult) => any, error?: () => any):ICountResult;
    withInlineCount(): Provider<T>;
  }

Tokens

How do you add a token to the gets for authentication? I am used to doing it with the $http but not with odata and this extension.

odatakey as Guid

is there a way to define odatakey type ?
I needed to do this to make a get request:

var form = AccessControlService.Forms.odata()
                .expand("Actions")
                .expand("Zones")
                .get("guid'" + $routeParams.id + "'");

but I couldn't do update:

var newForm = new AccessControlService.Forms();
            newForm.Title = form.Title;
            newForm.Subtitle = form.Subtitle;
            if (form.Id) {
                newForm.Id = form.Id;
                newForm.$update();
            } else{
                newForm.$save();
            }
PUT http://localhost:4744/odata/Forms(5ac87c3d-07a6-4f90-8849-2e04ceecc61b) 400 Bad Request

here is my AccessControlService.js:

(function () {
    var accessControlService = function ($odataresource) {
        var service_url = "http://localhost:4744/odata/";
        var config = {
            odatakey: "Id",
            isodatav4: true
        };
        var forms = $odataresource(service_url + "Forms", {}, {}, config);
        return {
            Forms: forms
        };
    }
    var app = angular.module("access-control");
    app.factory("AccessControlService", ["$odataresource", accessControlService]);
} ());

Complex expressions in lambda operation not working

Tried to use the latest update on my own project and realised that it doest work for what I actually needed it for. Current solution only supports single simple expressions.

I have made an update that seems to work much better. I will do some more testing and then update tests and documentation.

Saving expand & selects in the returned resource object

Was thinking about when I need to run an update on a resource from the array of resources. I know I can grab the resource and do entity.$odata().get(), but would be nice not to have to reapply my selects and expands. So end result would be a new version of my resource object with the same expanded table and fields as the original call that made the request. Just throwing this out there for thoughts before I went down the rabbit hole. Does this logic not belong stored in the resource and should remain the end users responsibility to reapply to the odataprovider before calling get()? If not transformed, the @Odata.context property of the response contains the Metadata for recreating the necessesary select/expand calls.

Non-nested or statements

I have a long list of or statements because odata does not support a "field in (list)" syntax. Code looks something like:

$odata.Predicate.or([predicate0...predicateN]);

Expected: (ID eq 0) or (ID eq 1) or (ID eq 2) or (ID eq 3)
Actual: (((ID eq 0) or (ID eq 1)) or (ID eq 2)) or (ID eq 3)

I have so many fields that the server errors because the or statements are nested too deep.

Odata V4 and parameters

I am trying to get the library to take a parameter but it looks like it only works for older odata not for V4.

what I was trying is like this:
$odataresource("OData/users(:id)", { id: '@id' } , {}, { odatakey: 'id', isodatav4: true }).odata().query();

if I use some versions with /:id I can get the id value but for V4 it needs the "( )" format.
I am new with this so if I am making a mistake please explain it.

I can get a url that has /users/2 or one that has /users() but not /users(2) unless i do it without the parameter and just make the string.

is the a bug in the library or that the Odata 4 support is not finished yet?
if it's a thing that I can fix where should I look in the source to fix it?

thanks!

How to write a PATCH request?

I'm in the need of writing a HTTP PATCH request to my OData API. I've got an array of Order items, and I need to be able to add, edit, remove Items in the Order, without submitting the whole order back to the API, only what's changed.

Please suggest / document how to accomplish this. I've tried to use both $update and $save, but am facing problems, either the server ends up trying to / creating a duplicate Order or nothing gets saved.

Selecting in expanded queries

I was happy to see that you have support for this OData v4 syntax:

var result = User.odata().expand("roles", "role").query();
// /user?$expand=roles($expand=role)

But what I want to make use of (and what I can't seem to figure out how to do with this library) is the following v4 syntax:

/user?$expand=roles($select=id)

Which would expand the user object with its roles, but only include the roles' id property.

So far I've tried these without any success:

[...].select(['roles.id'])
[...].select(['roles/id'])
[...].select([['roles', 'id']])
[...].select([{ 'roles': ['id'] }])

This works, but it feels kind of "wrong", especially from a fluent API perspective:

[...].expand("roles($select=id)")

At that point I'm gaining very little from the API, as I'm basically building the query myself.

Suggestion for implementing access_token header?

I'm using ODataAngularResources against an OAuth2 protected service. For this, I need to pass an Authorization Bearer header with the access token set in it.

I am able to do this for GET based requests like query, etc. by sending it into odata.headers of the 3rd parameter of the $odataresource() constructor, but this doesn't seem to work for sending $save() based POST requests.

Thoughts, suggestions, ideas on the best strategy to implement this would be much appreciated!

Custom function changes $count=true to $inlinecount=allpages

So the entire library is in odata v4

I have this resource

app.factory('Product', ['$resource', '$odataresource', function ($resource, $odataresource) {
    return $odataresource('/odata/Products',
        {productId:'@Id' }
        { 'GenerateFromProduct': { method: 'GET', url: '/odata/ProductVariants(:productId)/GenerateFromProduct()' } }, {}, {
        odatakey: 'Id',
        isodatav4: true
    });
}]);

The endpoint is : http://localhost:26696/odata/Products(b2a35842-7b68-e511-beda-6c71d92133bc)/GenerateFromProduct

The Id is my entities property: 'Id'

The query for indexing the products changes with the custom function to : http://localhost:26696/odata/Products?$top=10&$inlinecount=allpages instead of http://localhost:26696/odata/Products?$top=10&$count=true

The previous declaration of the resource was working :

app.factory('Product', ['$resource', '$odataresource', function ($resource, $odataresource) {
    //  return $resource('/api/entries/:id'); // Note the full endpoint address
    return $odataresource('/odata/Products', {}, {}, {
    odatakey: 'Id',
    isodatav4: true
    });
}]);

Should isodatav4 be set somewhere else or is this a bug?

Extend API with 'format' attribute

I need to send query like this: www.foo.com/service?$format=json
but it's imposible to do using ODataAngularResources
Please, can you implement such a feature?

DateTime formatting

I'm not sure how to format ISO dates. If I put a raw date in the filter value, it appends single quote (%27) to the string, and odata says it is invalid. additionally, if I specify datetime'Tue Mar 15 2016 14:41:17 GMT-0700 (PDT)' It adds string literal around that, too. Putting in an actual js Date object also causes it to parse the value as a string.

I would expect to just provide a date object and have it serialize it into odata query param. Is there another way?

If so, maybe just add that example in the readme

Complex route key replacements does not work

In the simple case where you have a simple route like:
$odataresource('/user/:userId', {userId:'@id'});
the expected result is "/user(5)" and that is OK, but for more complex routes where the Id is NOT at the end of the route, it does not work.

For example:
$odataresource('/user/:userId/details', {userId:'@id'});
The expected result is: "/user(5)/details" however the actual result is "user/details(5)"

deeplevel orderBy

Is there a way to order by a child property?

Eg. ( possible syntax)

.orderBy("Trajects.Priority").query()

Or isn't this supported in Odata? I can't seem to find it in the docs. They suggest navigating to the child and then ordering: http://notify-arrival.sapico.me/odata/Routes(9cbaab82-1245-4015-a106-66c440a751fa)/Trajects?$orderby=Order%20asc

Is it possible to order it on a higher level? If you haven't came accross this yet or have no idea.. Just close this issue and i'll check the method described above :)

(If it's possible i would add it in ODataAngularResources if it doesn't exist yet, that's why i'm asking)

ODataAngularResources not parse OData 4 response

I try call OData v4 service from typescript.

For test purpose I use Northwind Products OData Service

Here is code wich call service:

var results = this.$odataresource("http://services.odata.org/V4/Northwind/Northwind.svc/Products")
.odata()
.filter("UnitPrice", ">", 10)
.filter("Discontinued", true)
.take(2)
.query();

Request URL :http://services.odata.org/V4/Northwind/Northwind.svc/Products?$filter=(UnitPrice%20gt%2010)%20and%20(Discontinued%20eq%20true)&$top=2

Response :

{ "@odata.context":"http://services.odata.org/V4/Northwind/Northwind.svc/$metadata#Products",
"value":[
{
"ProductID":5,
"ProductName":"Chef Anton's Gumbo Mix",
"SupplierID":2,
"CategoryID":2,
"QuantityPerUnit":"36 boxes",
"UnitPrice":21.3500,
"UnitsInStock":0,
"UnitsOnOrder":0,
"ReorderLevel":0,
"Discontinued":true
},
{
"ProductID":9,
"ProductName":"Mishi Kobe Niku",
"SupplierID":4,
"CategoryID":6,
"QuantityPerUnit":"18 - 500 g pkgs.",
"UnitPrice":97.0000,
"UnitsInStock":29,
"UnitsOnOrder":0,
"ReorderLevel":0,
"Discontinued":true
}
]
}

Deserialized response:

[$promise: Promise, $resolved: false]
0: Resource
1: Resource
$promise: Promise
$resolved: true
@odata.context: "http://services.odata.org/V4/Northwind/Northwind.svc/$metadata#Products"
length: 2
proto: Array[0]

I would like have deserialized response as array of Product object.

I really dont’t know where can be problem.

In app I use ODataResources but also ngResource

Problem when OData returns V3 "odata.metadata" property rather than V4 "@odata.context"

Hi, i have an local OData V3 API that returns a result like it.

{
odata.metadata: "http://localhost/odata/v1/$metadata#Customers",
value: [ ]
}

When i try to use a comnand like "odata().query()" the lib throws an error like it.

Error in resource configuration for action 'odata'. Expected response to contain an array but got an object. ...

Looking the code, i found a validation in line 926 that no consider another property, just "@odata.context".

You have any reason for that?
The lib just support OData V4?

OData 2.0 $type parameter

In OData 2.0 it is possible to retrieve data in either JSON or XML format by specifying the $format parameter. It would be nice to have this parameter available via the module as well.

Right now as a workaround I use:

.transformUrl(function(url){
        return url+'&$format=json';
      })

library does not parse correctly a result set.

i have the following json from a query that returns a list:

{
"odata.metadata": "http://localhost:63447/odata/$metadata#CompanyViewModels",
"value":[
{
"Id": 1,
"CompanyName": "Company1"
},
{
"Id": 2,
"CompanyName": "Company2"
}
]
}

it is not an array, because it has the 'odata.metadata' json payload.

and it throws an error here.

if (angular.isArray(data) !== (!isSingleElement && !!action.isArray) && !forceSingleElement) {
throw $resourceMinErr('badcfg',
'Error in resource configuration for action {0}. Expected response to ' +
'contain an {1} but got an {2} (Request: {3} {4})', name, (!isSingleElement && action.isArray) ? 'array' : 'object',
angular.isArray(data) ? 'array' : 'object', httpConfig.method, httpConfig.url);
}

why? because the object is not an array ( [] ).

i had to add the following.

if (data.value)
{
data = data.value;
}

asp.net web api for backend.

should have if property named odata.metadata exists then something.

怎样发起这样的查询 /User('925ea858-33ed-413d-8353-f9f43a8de744')/Roles ?

three tables

IdentityUser
IdentityUserRole
IdentityRole

UserController.css

    public class UserController : ODataController
    {
        DbContext content;
        public UserController(DbContext content)
        {
            this.content = content;
        }
        //[ODataRoute]
        [EnableQuery(PageSize = 20, AllowedQueryOptions = System.Web.OData.Query.AllowedQueryOptions.All)]
        public IQueryable<User> Get()
        {
            return this.content.Set<User>().OrderBy(o => o.Name);
        }

        [EnableQuery]
        public SingleResult<User> Get([FromODataUri] string key)
        {
            var result = this.content.Set<User>().Where(o => o.Id == key);
            return SingleResult.Create(result);
        }

        // get User(id)/Roles
        [EnableQuery]
        public IQueryable<Role> GetRoles([FromODataUri] string key)
        {
            var result = this.content.Set<User>().Where(o => o.Id == key)
                .SelectMany(o => o.Roles.Select(p => p.Role));
            return result;

        }
    }

i can get the user roles by User('925ea858-33ed-413d-8353-f9f43a8de744')/Roles ,the result like this:

{
"@odata.context": "http://localhost:38333/odata/$metadata#UserRole/rg.Data.Models.Role",
"value": [
{
"@odata.type": ......,
"Id": "1f9d0459-b090-42d4-b7f8-7e58e839a338",
"Name": "33"
},
{
"@odata.type": ...
"Id": "42034263-a8fe-4130-952c-029e2dbb7b3e",
"Name": "11"
}
]
}

and, how query these data by $odataresource ?

still confused please help

we have a query that works but is not really good on the server.
the server queries al whole table and then picks a record right now due to how this is written. I want to have it work better but I can't seem to get the right way to do it.

what goes to fiddler now is like this: /aspnetusers/aspnetusers?$filter=Id%20eq%201157&$expand=AspNetRoles
what I want to have it do is like this: /aspnetusers/aspnetusers(1157)?$expand=AspNetRoles

the client side right now is using this
return $odataresource(url + "/atrakapi/aspnetusers/aspnetusers").odata()
.filter("Id", id)
.expand("AspNetRoles")
.query();

so how do I change that from filter to a get by id
trying different things so far gets me errors but not the right data.
sorry I am so dense on this, I am more of a C# developer not a JS developer

ODataAngularResources not parse OData 4 response

I try call OData v4 service from typescript.

For test purpose I use Northwind Products OData Service

Here is code wich call service:

var results = this.$odataresource("http://services.odata.org/V4/Northwind/Northwind.svc/Products")
.odata()
.filter("UnitPrice", ">", 10)
.filter("Discontinued", true)
.take(2)
.query();

Request URL :http://services.odata.org/V4/Northwind/Northwind.svc/Products?$filter=(UnitPrice%20gt%2010)%20and%20(Discontinued%20eq%20true)&$top=2

Response :

{ "@odata.context":"http://services.odata.org/V4/Northwind/Northwind.svc/$metadata#Products",
"value":[
{
"ProductID":5,
"ProductName":"Chef Anton's Gumbo Mix",
"SupplierID":2,
"CategoryID":2,
"QuantityPerUnit":"36 boxes",
"UnitPrice":21.3500,
"UnitsInStock":0,
"UnitsOnOrder":0,
"ReorderLevel":0,
"Discontinued":true
},
{
"ProductID":9,
"ProductName":"Mishi Kobe Niku",
"SupplierID":4,
"CategoryID":6,
"QuantityPerUnit":"18 - 500 g pkgs.",
"UnitPrice":97.0000,
"UnitsInStock":29,
"UnitsOnOrder":0,
"ReorderLevel":0,
"Discontinued":true
}
]
}

Deserialized response:

[$promise: Promise, $resolved: false]
0: Resource
1: Resource
$promise: Promise
$resolved: true
@odata.context: "http://services.odata.org/V4/Northwind/Northwind.svc/$metadata#Products"
length: 2
proto: Array[0]

I would like have deserialized response as array of Product object.

I really dont’t know where can be problem.

In app I use ODataResources but also ngResource

Processing response wrapped in object possible?

Is it possible to preprocess the response? I want to consume an API that gives responses wrapped in an object:

{
  "d" : {
    "results": [
      {
        "__metadata": {
          "uri": "http://data.udir.no/kl06/ODATA/Fagkode('REA3031')",
          "type": "Udir.Lkt.Dokumenter.OData2.FagkodeInformasjon"
        },
        "Tittel": "Matematikk Vg2P, muntlig",
        "Kode": "REA3031",
        "Psi": "uuid:c1a421a7-6218-4921-afa9-acf19d1387f8",
        "UrlData": "http://data.udir.no/kl06/REA3031",
        "UrlPsi": "http://psi.udir.no/kl06/REA3031",
        "SistEndret": "\/Date(1372944663000)\/",
        "Status": "http://psi.udir.no/ontologi/status/utgaatt"
      } , { ...more objects }
    ]
  }
}

Error message: Error in resource configuration for actionodata. Expected response to contain an array but got an object
Data uri: http://data.udir.no/kl06/odata/Fagkode

Support more advanced filters

In OData, this is a valid $filter query: /odata/Foo?$filter=Bars/all(b: b/Baz ne 0) -- it will give you the Foo entities where all the Bars' Baz property is not equal to 0. I'm in need of making this type of query, and I'm struggling to get ODataAngularResources to produce one.

Closest I got was this: .filter("Bars/all(b: b/Baz", "!=", "0)"), but it (obviously) thinks that "0)" is a string, and produces this output: Bars/all(b: b/Baz ne '0)'.

Any help on how to get this to work would be appreciated.

Sub-Filter

There are any way to make the query like

/odata/employer(5)/client?$filter(...)

if not, would be nice!

Ty

$save $delete is not a function issues

Hi, I am just using this js, and I found that it is quite useful and powerful to get data. But when I try to use $save and $delete, js return me save is not a function and also delete is not a function. I wondering which part I missing ?

odata v4 query

I've been playing with the library all day but things weren't smooth with me ...
I keep getting an error that 'odata' or 'query' was expecting an array while they got an object instead ...
here's my app.js

(function(){
    var app = angular.module("access-control", ["ngRoute", "ODataResources"]);
    app.config(function($routeProvider) {
        $routeProvider
            .when("/main", {
                templateUrl: "views/main.html",
                controller: "MainController"
            })
            .when("/error", {
                templateUrl: "views/error.html"
            })
            .when("/admin", {
                templateUrl: "views/admin.html",
                controller: "AdminController"
            })
            .when("/admin/forms", {
                templateUrl: "views/admin/forms.html",
                controller: "FormsController"
            })
            .otherwise({ redirectTo: "/error" });
    });
}())

and here is my controller

(function () {
    var formsController = function ($scope, $log, $odataresource) {
        var onError = function (reason) {
            $log.error("fail ...");
        }
        var onFormsComplete = function (response) {
            $log.log("completed ...");
        }
        var forms = $odataresource("http://localhost:4744/odata/Forms");
        var myforms = forms.odata().query(onFormsComplete,onError);
        $scope.forms = myforms;
    };
    var app = angular.module("access-control");
    app.controller("FormsController", ["$scope", "$log", "$odataresource", formsController]);
}())

and here is my response

{
  "odata.metadata":"http://localhost:4744/odata/$metadata#Forms",
  "value":[
    {
      "Title":"Form 1",
      "Subtitle":null,
      "Id":"5ac87c3d-07a6-4f90-8849-2e04ceecc61b",
      "CreatedOn":"2016-05-05T00:00:00",
      "LastModifiedOn":"2016-05-05T00:00:00"
    }
  ]
}

it never gets in onFormsComplete nor onError ...

I'm still new to the front-end and angular thing so please bear with me ...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.