Using JS-Data 2.6 in Angular, I'm trying to load an array of data using a nice clean URL, e.g. /report/22. (This format makes sense, because it's following business logic - I'm loading a report data by category id, and getting several rows back.)
However,
- when I use
find
, then js-data dies with the dreaded[Error] "attrs" must be an object!
because it expects 1 row, and cannot be convinced otherwise - unless I'm missing something. - when I use
findAll
, then I need to search using uglier/report/?categoryId = 22
- and change the server - when I use actions, then it appends action name to the URI, which I don't need, e.g.
/report/22/myaction
Is there any way to use either find() or findAll() to
- have a clean URL
- load an array of data
- preferably, not changing the server implementation
Everything in this answer assumes you're using the HTTP adapter.
JSData's default expecations are the following:
GET /<resource>/:id
returns an object, e.g.{ id: 1 }
GET /<resource>
returns an array of objects, e.g.[{ id: 1 }, { id: 2 }]
POST /<resource> { some: 'field' }
creates a single item in your database and returns the updated item, e.g.{ id: 1, some: 'field' }
PUT /<resource>/:id { updated: 'field' }
updates a single item in your database and returns the updated item, e.g.{ id: 1, updated: 'field' }
PUT /<resource> { updated: 'field' }
updates a collection of items in your database and returns the updated items, e.g.[{ id: 1, updated: 'field' }, { id: 2, updated: 'field' }]
-DELETE /<resource>/:id
deletes a single item from your databaseDELETE /<resource>
deletes a collection of items from your databaseBy default,
DS#find
doesGET /<resource>/:id
, andDS#findAll
doesGET /<resource>
.Any response from the server needs to be in the right format by the time it gets to
DS#inject
.The lifecycle for these calls is the following:
find
orfindAll
method of adapterGET
method of adapterHTTP
method of adapterdeserialize
method on server responseafterFind
orafterFindAll
hookcacheResponse
true
, pass result ofafterFind
orafterFindAll
toDS#inject
false
, pass result ofafterFind
orafterFindAll
toDS#createInstance
The only way to avoid an injection error is to either:
A) Not inject the adapter response into the datastore
or
B) Massage the data into the correct format before it is passed into
DS#inject
DS#inject
requires either an object that has a field specified by the Resource'sidAttribute
option, or an array of the same.You have three opportunities to massage the data before it gets to
DS#inject
:deserialize
hookafterFind
orafterFindAll
hookIn any one of those methods you could fix the data to be what
DS#inject
expects.If you want to be able to do
Report.find(22)
then you might do:All of this assumes you really want to be able to use
DS#find
, butDS#find
andDS#findAll
are meant to be used with RESTful resources where a Resource corresponds to a table in a database and instances of the Resource correspond to rows in the table. Generating reports is typically one of those things where you're compiling data from disparate sources, doing aggregations, etc. It's not as predictable (and hence, this question).Here's another option:
Basically, there are many ways to accomplish any particular task, each with its own set of pros/cons. JSData can only generalize to so many use-cases with its default settings.
To unlock the power of JSData and maximize your productivity, you'll want to take note of the many options and hooks in JSData that allow you to mold JSData to your liking. If you find that any particular extension or customization you've written could be generalized and benefit a lot of others who have the same use-case, let us know!
Cheers!