mrichar1 / jsonapi-vuex

Use a JSONAPI api with a Vuex store, with data restructuring/normalization.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

HasMany relationships

SomewhatCloudy opened this issue · comments

I couldn't get a hasMany relation to work, and carefully reading the docs I saw 'Note - getRelated only works on specific items, not collections.'

Am I right in assuming that it's not possible to use a hasMany relation at all with this library?

hasMany relationships should work fine in the general case with jsonapi-vuex.

The getRelated action only working on specific items means that you can't pass it a collection and expect it to 'walk' every relationship of every item in the collection. However getRelated is only needed if you don't have relationship following enabled, or you don't use includes params on your requests.

In the general sense, a hasMany relationship is represented in JSONAPI as a list of relationship links. Assuming we had a blog with many comments, you might get:

"relationships": {
  "comments": {
    "data": [
       { "type": "comments", "id": "1" },
       { "type": "comments", "id": "2" }
    ]
  }
}

The default behaviour (config option followRelationshipsData is true) is to translate relationships as:

{
  "comments": {
    "1": » get('comment/1')  // getter call to get('comment/1')
    "2": » get('comment/1')  // getter call to get('comment/2')
  }
}

So you can access these as e.g.: blog.comments.2 (or iterate over Object.entries(blog.comments) )

Note you also still have the original relationships data, as well as the isRel and rels helper methods, if you want to do more low-level operations with them.

I hope that helps explain things!

That makes a bit more sense.

I've managed to get it working with included relations but I still cannot get getRelated to return anything, take the following:

		let surf1 = await this.$store.dispatch('jv/get', 'surfaces/' + surfaceId + '?include=images'),
			rel1get = this.$store.getters['jv/getRelated']('surfaces/'+surfaceId)['images'],
			rel2get = this.$store.getters['jv/getRelated']('surfaces/'+surfaceId)['item'],
			related1 = await this.$store.dispatch('jv/getRelated', 'surfaces/' + surfaceId + '/item'),
			related2 = await this.$store.dispatch('jv/getRelated', 'surfaces/' + surfaceId + '/images'),
			rel2getb = this.$store.getters['jv/getRelated']('surfaces/'+surfaceId)['item'];

surf1 and rel1get return as expected. rel2get doesn't return anything (as expected). related1 and related2 both make a valid http call to the API that returns correctly but both of them just return empty objects from the dispatch method. rel2getb also doesn't contain anything despite related1 calling the endpoint that should have populated it.

I am using 5.1.1 with VueX 3.6.2 and Vue 2.6.14.

Maybe I am doing something stupid (It happens!) but if not I can possibly track the issue down if you have an idea of where I should look?

Hi,

Your code looks correct, and I can't see any immediate mistakes there, so I probably need to know what the jsonapi looks like. From the calls you're making I would expect something like:

{
  "type": "surfaces",
  "id": "1",
  "attributes": { ... },
  "relationships": {
    "images": [
      "data": { "type": "image", "id": "5" },
       "data": { "type": "image", "id": "6" }
    ],
    "items": {
      "data": { "type": "item", "id": "10" }
    },
  }
}

Can you also supply the store contents after each dispatch call? (console.log(this.$store.state))

I've also just spotted you're using Vue2 - there is a chance that this is an issue with v5 being built against Vue3 - can yuo also try explicitly setting jsonapi-vuex: 4.5.3 in package.json ?

Nope that doesn't appear to help.

I've not had much of a chance to dig in to it myself but initially the line from actions.js:128 seems suspect.
let record = await context.dispatch('get', args)
It looks like it should be something like:
let record = await context.dispatch('get', type+'/'+id)
(If you are trying to sniff an existing record for a relation key.)

That doesn't fix it though!

That line is just there to get the 'original' item from the store, if the args to getRelated isn't already an object containing the item and its relationships.

It just calls the get action with the getRelated args - and since these contain a type and id get will unpack these itself and make the call.

You can confirm this easily - if you make the following call:

this.$store.dispatch('jv/getRelated', 'surfaces/' + surfaceId + '/item')

You should see an initial GET against /surfaces/surfaceId before then GETs for any related items.

Ahh ok, it just contained some random models when I tried it. I might see if I can make up a testcase for the issue(s) I am having at some point soon too. Will let you know!

commented

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.