Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Having problems with sync() and object syntax #103

Open
giuseppe-esposito-87 opened this issue May 20, 2020 · 15 comments
Open

Having problems with sync() and object syntax #103

giuseppe-esposito-87 opened this issue May 20, 2020 · 15 comments

Comments

@giuseppe-esposito-87
Copy link

giuseppe-esposito-87 commented May 20, 2020

Hi,

I cannot make sync work with a nested object.

In my store, inside order.js I have:

import { make } from "vuex-pathify";

const state = {
  order: {},
};

const mutations = make.mutations(state);
const defaultActions = make.actions(state);
const actions = {
  ...defaultActions,
  setOrderItemQuantity: async (foo, payload) => {
    //todo
    console.log(foo);
    console.log(payload);
  },
};
const getters = make.getters(state);

export default {
  state,
  mutations,
  actions,
  getters,
};

inside the index.js

import Vue from "vue";
import Vuex from "vuex";
import order from "./Modules/order";
import pathify from "@/plugins/pathify";
import * as restActions from "./Modules/restActions";

const store = {
  state: {},
  mutations: {},
  actions: { ...restActions },
  modules: {
    order: {
      namespaced: true,
      modules: {
        order,
      },
    },
  },
};

Vue.use(Vuex);
export default new Vuex.Store({
  plugins: [pathify.plugin],
  ...store,
});

The order object loaded inside the state (via a rest action) is like this:

order = {
  uuid: 1,
  id: 1,
 warranty: true,
  orderItems: [
    {
      id: 1,
      title: 'myTitle',
      quantity: 10,
      totalPrice: 100,
      unitPrice: 10,
    },
    {
      // other orderItem
    },
    {
      // another one
    }
  ]
};

Then in my component I'm trying to set a computed property for the v-model as seen in the doc\examples:

[...]
export default {
[...]
  data() {
    return {
      index: 0 //this will be dynamic
    };
  },
  computed: {
    quantitySelected: sync("order/order@orderItems[:index].quantity|setOrderItemQuantity")
  }
}

But that is not working.

What I've discovered so far:

  1. quantitySelected: get("order/order@orderItems[0].quantity does work (I can print 10)
  2. quantitySelected: get("order/order@orderItems[:index].quantity|setOrderItemQuantity") does not work

Any idea what I'm doing wrong?
Thank you

@giuseppe-esposito-87
Copy link
Author

giuseppe-esposito-87 commented May 26, 2020

I've another unrelated problem with sync():
I've added another custom action to my order.js store, so now it is like:

import { make } from "vuex-pathify";

const state = {
  order: {},
};

const mutations = make.mutations(state);
const defaultActions = make.actions(state);
const actions = {
  ...defaultActions,
  setOrderShippingWarranty: async () => {
   //custom action
  },
  setOrderItemQuantity: async (foo, payload) => {
  //custom action
  },
};
const getters = make.getters(state);

export default {
  state,
  mutations,
  actions,
  getters,
};

Now I would like to use sync() in a component to set up the 2 way data binding calling the custom action but I can't understand how should do it.
I thought it would be:

  computed: {
    shippingWarranty: sync(
      "order/order@shippingWarranty|order/setOrderShippingWarranty"
    )
  }

But that gives the error :

vuex-pathify.esm.js?7ffd:417 [Vuex Pathify] Unable to create sub-property for path 'order/order@order/setOrderShippingWarranty!':
- Set option 'deep' to 2 to allow it

(after I set up the option I've seen that doesn't lead to the correct result anyway)

  computed: {
    shippingWarranty: sync(
      "order/order@shippingWarranty|setOrderShippingWarranty"
    )
  }

Just add setOrderShippingWarranty = true\false to the order object.

Therefore...What is the correct syntax to make sync() works in this case? THank you

@davestewart
Copy link
Owner

Hey,

Sorry I missed this!

In the first example, you seem to have two layers of modules:

modules: {
    order: {
      namespaced: true,
      modules: {
        order,
      },
    },
  },

This should just be:

const order = {
  namespaced: true,
  ... // other properties
}

modules: {
    order
  },

Additionally, you seem to have order inside state:

const state = {
  order: {},
};

So I would get your module nesting correct using Vuex, before even looking at Pathify.

I'll leave this open in case you need an extra pair of eyes, but this doesn't look like a Pathify issue... yet.

@davestewart
Copy link
Owner

Also:

quantitySelected: get("order/order@orderItems[:index].quantity|setOrderItemQuantity")

You have to think through in your head what the syntax resolves to:

order/order@orderItems[:index].quantity

This is going to be getting an array item from within a sub-property of the order state of the order module.

I'm not sure why setOrderItemQuantity is here. The pipe character is designed to give you an alternate method when using sync, but you are using get:

https://davestewart.github.io/vuex-pathify/#/api/component?id=sync

If you need to sync, use sync. If this is a mistake, fix the syntax.

Pathify is designed mainly to simplify the wiring for 1:1 relationships with the. I'd suggest if you have something a little more complex either:

  • stick to just plain Vuex
  • simplify your architecture

By the way, I appreciate (in hindsight) the docs are not the easiest to navigate, there's a lot of reading, and it's not easy to just look things up via the API. This may change at some point in the future!

@giuseppe-esposito-87
Copy link
Author

giuseppe-esposito-87 commented May 27, 2020

Thank you for you answer,

In the first example, you seem to have two layers of modules:

modules: {
    order: {
      namespaced: true,
      modules: {
        order,
      },
    },
  },

This should just be:

const order = {
  namespaced: true,
  ... // other properties
}

modules: {
    order
  },

Yeah, you're totally right, that was a mistake, I've corrected that.


Additionally, you seem to have order inside state:

const state = {
  order: {},
};

Perhaps you've been confused by the nomenclature of my variables?
I've named the "object" inside the state "order" as the module, but just for coherence.

I mean, I could just as well call it:

 const state = {
   myCustomObject: {},
 };

I'm not sure why setOrderItemQuantity is here. The pipe character is designed to give you an alternate method when using sync, but you are using get:

A typo: I tried

quantitySelected: get("order/order@orderItems[:index])

insted of using sync(getter/setAction) as a test to check if a getter with a variable :index worked, and it did not work for me (because I was combining with sync and had not idea what was working and what not with that combination).

However, it does work now that I've corrected the wrongly nested module, as you pointed out, thank you.


What I can't still get to work it is calling a sync(get|setAction), I'm writing in a separate following comment for clarity's sake.

@giuseppe-esposito-87
Copy link
Author

giuseppe-esposito-87 commented May 27, 2020

Current situation:

I've updated my vuex index.js to fix the nested module mistake:

import Vue from "vue";
import Vuex from "vuex";
import order from "./Modules/order";
import pathify from "@/plugins/pathify";
import * as restActions from "./Modules/restActions";

const store = {
  state: {},
  mutations: {},
  actions: { ...restActions },
  modules: {
    order: {
      namespaced: true,
      ...order
    }
  }
};

Vue.use(Vuex);
export default new Vuex.Store({
  plugins: [pathify.plugin],
  ...store
});

My order.js is still:

import { make } from "vuex-pathify";

const state = {
  order: null
};

const mutations = make.mutations(state);
const defaultActions = make.actions(state);
const actions = {
  ...defaultActions,
  setOrderShippingWarranty: async ({ dispatch }, payload) => {
    //custom action
  },
  setOrderItemQuantity: async ({ dispatch }, payload) => {
    //custom action
  }
};
const getters = make.getters(state);

export default {
  state,
  mutations,
  actions,
  getters
};

(the order object in the state is set up via a custom action when the App is mounted).

In a component, I'm trying to set up a 2 way data binding with

computed: {
    shippingWarranty: sync(
      "order/order@shippingWarranty|order/setOrderShippingWarranty"
    )
  }

The "get" works as I get the correct value, while the action doesn't, as I get the error describe in previous comment:

vuex-pathify.esm.js?7ffd:417 [Vuex Pathify] Unable to create sub-property for path 'order/order@order/setOrderShippingWarranty!':
- Set option 'deep' to 2 to allow it

Could you see what I am doing wrongly? Thank you.

@davestewart
Copy link
Owner

davestewart commented May 27, 2020

A couple of code comments before I get started:

  • when you type the three backticks in your posts, add js right after; this will colorize the code and make it easier for folks to read
  • where you have a namespaced: true, ...order just export everything from the one file, and skip the spread so it's modules: { order }

So I'm not 100% sure that pathify supports sync with actions (it was designed for commits), even though Pathify has "accessor priority".

If you can set up a simple Code Sandbox (creating a new issues should provide the links) I will be happy to take a look.

If it does, I suspect the code will be:

module  
  |  property                   
  |     |     sub-property  
  |     |           |                 action
  |     |           |                   |
  v     v           v                   v
order/order@shippingWarranty|setOrderShippingWarranty"

Sorry I don't sound so certain - this lib just runs itself these days and I rarely look at the code!

EDIT: actually, I've just seen what might be the problem. The error message actually tells you.

Did you configure the library before using it?

See: https://davestewart.github.io/vuex-pathify/#/setup/config

Set deep to 2 and it should work (also, it looks like the docs are inconsistent; the default for deep is 1 not true. I will raise a ticket).

@davestewart
Copy link
Owner

Any luck @Peppe87 ?

@giuseppe-esposito-87
Copy link
Author

Hi,

Sorry for the delay but In the last working days I had to focus on another project unrelated on Vue. Next week I'll check again the deep config to be sure (but previously I tried it and it did not work) and eventually set up a code sandbox to example my situation.

I'll notify you as soon I'll do that, thank you again for the support

@giuseppe-esposito-87
Copy link
Author

giuseppe-esposito-87 commented Jun 1, 2020

@davestewart

I've tried the set deep options = 2 but it does not solve my problem.
As far as I can understand, is how you said: the sync doesn't "recognize" the custom action I've created.

Anyway I've created a mockup of what I'm trying to do in my project:
https://codesandbox.io/s/pathify-sync-action-test-tw4h9

I'd be grateful if you could check it when possible, thank you.

@giuseppe-esposito-87
Copy link
Author

@davestewart any chances you checked this issue?

@davestewart
Copy link
Owner

Hey, sorry for the long wait! I've had quite a busy couple of weeks myself.

I'll look into this tomorrow

@giuseppe-esposito-87
Copy link
Author

@davestewart any chances you looked to this issue? Thanks

@davestewart
Copy link
Owner

Still no time... really sorry!

I'm launching a big project I've spent the last year working on and all OSS is on hold until then.

I REALLY want to take some time to attend to the various issues though, so out of sight but not out of mind.

Fingers crossed next couple of weeks...

@juangalbea
Copy link

juangalbea commented Nov 26, 2021

You said this is not working:

export default {
[...]
  data() {
    return {
      index: 0 //this will be dynamic
    };
  },
  computed: {
    quantitySelected: sync("order/order@orderItems[:index].quantity|setOrderItemQuantity")
  }
}

do this instead:

export default {
[...]
  data() {
    return {
      index: 0, //this will be dynamic
      name: 'order'
    };
  },
  computed: {
    quantitySelected: sync("order/:name@orderItems[:index].quantity|setOrderItemQuantity")
  }
}

@adamcrown
Copy link

@juangalbea That works! Why does it work!?

This was broken for me:

data() { return { } },
computed: sync('users/users@:id', [...])

and this worked:

data() { return { storeRootAttr: 'users } },
computed: sync('users/:storeRootAttr@:id', [...])

What a weird bug. Thanks for helping me find this workaround. I hope a permanent fix can come soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants