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

Shortcut for multiple object properties #43

Open
molerat619 opened this issue Sep 17, 2018 · 14 comments
Open

Shortcut for multiple object properties #43

molerat619 opened this issue Sep 17, 2018 · 14 comments

Comments

@molerat619
Copy link

molerat619 commented Sep 17, 2018

Hey Markus,

would it make sense to allow to do the following?

computed: {
    ...mapFields(["myObject.*"]) // or simply "myObject"
}

Then in the form one can easily use v-model="myObject.title" etc. Right now, I find it a bit cumbersome/not scalable to have to add each field to that array in mapFields.

@maoberlehner
Copy link
Owner

I'll consider it, but I can't promise anything. Thank you for suggesting it.

@xlanex6
Copy link

xlanex6 commented Oct 15, 2018

@molerat619

  • 1 on this feature, it could be very very cool.

@anikolaev
Copy link

@maoberlehner please consider this modification which implements the feature: anikolaev@fd0c1ad

Usage is almost the same as for multi-row (array) fields.

In *.vue:

<input v-model="selectedSeries.name"/>
<input v-model="selectedSeriesYAxis.name"/>

...

const mapSelectedSeriesFields = createHelpers({
  getterType: 'forms/getSelectedSeriesField',
  mutationType: 'forms/updateSelectedSeriesField'
}).mapObjectFields

...

export default {
  computed: {
    ...mapSelectedSeriesFields({
      selectedSeries: '*',
      selectedSeriesYAxis: 'y_axis.*',
    }),
  }

As you can see I used it to access data for selected series using specific getter and setter for that and storing selected series index in store too. That is one of the solutions for dynamic properties but it is another issue.

@maoberlehner
Copy link
Owner

@anikolaev thank you for providing a code example. I'll take a closer look at the weekend 👍

@stijnjanmaat
Copy link

stijnjanmaat commented Dec 6, 2018

Nice @anikolaev, using your fork for now :). Maybe useful for somebody: you need a getter like this

getNestedField: state => path => {
  if (path === '')
    return state.foo;

  return state.foo[path];
},

returning the whole foo object when path is empty. And a mutation like this:

updateNestedField(state, {path, value}) {
  state.foo[path] = value;
},

@anikolaev
Copy link

anikolaev commented Dec 6, 2018

@stijnjanmaat It should work with library's getField() too:

    import { getField, updateField } from 'vuex-map-fields'

    getNestedField(state) {
      return getField(state.foo);
    },
...
    updateNestedField(state, field) {
      updateField(state.foo, field);
    },

@maoberlehner
Copy link
Owner

maoberlehner commented Dec 7, 2018

Hey all! Sorry for letting you wait – I just want to let you know that I've not forgotten about this. But I shifted my priorities to different projects for the last couple of weeks. I'll work on this as soon as I can free up some time.

Thank you for your patience!

@anikolaev
Copy link

@maoberlehner I understand you. I've also shifted project and the new one unfortunately doesn't use Vue. But I hope you will find time to improve this lib as I found it very useful for complex forms.

@zainulabidin302
Copy link

zainulabidin302 commented Feb 23, 2019

This is how I am using vuex-map-fields in my project. The object.* is working but in a slightly different way (without syntactic sugar).

import store from '../store/index.js';

const getObjectByDotNotation = (a, b) =>
  b.split('.')
    .reduce((prev, cur) => prev[cur], a);

const flatArray = a => [].concat.apply([], a);

const keysMapForVuexFieldMap = (a, prefix, join = '.') => {
  const keys = Object.keys(a);
  const objects = keys.filter(k => (
    typeof (a[k]) === 'object') && !(a[k] instanceof Array) && !(a[k] == null));
  const ctxPrefix = z => (prefix ? `${prefix}${join}${z}` : z);
  const fields = keys.filter(k => typeof (a[k]) !== 'object' || (a[k] instanceof Array) || (a[k] == null))
    .map(k => ctxPrefix(k));

  if (objects.length > 0) {
    const y = objects.map(b => keysMapForVuexFieldMap(a[b], ctxPrefix(b)));
    return flatArray(y)
      .concat(fields.map(a => a));
  }
  return fields;
};

function getMapFieldsList(x, prefix) {
  const a = getObjectByDotNotation(store(), x);
  return keysMapForVuexFieldMap(a, prefix || null);
}

export default getMapFieldsList;

getMapFieldsList will return a list of fields in the state object which can be passed to mapFields

...mapFields([...VuexMapFieldService('state.UserProfile.form', 'form'), 'form', 'loading', 'error']),
Every property in UserProfile.form (UserProfile is a namespaced module) object will be returned as an array (even nested properties)
e.g
[ 'form.first_name', 'form.address.address_line_1', 'form.passport.passport_no']

keysMapForVuexFieldMap is general enough to be applied on any object.
getMapFieldsList is a wrapper which will use store as well.

@ts-23
Copy link

ts-23 commented Jun 19, 2019

Would it not be better just to do this to get the entire object?
...mapFields(["myObject"])

Adding an asterisk * introduces a new thing that is not needed.

@ratondeau
Copy link

Yes that is exactly what I am looking for. I have a formData object where all the field data gets in. Then I want to bind it via v-model to this data. It is a plain Object with no nested elements as i break array structured down to and index identifier.
The form can get quite complex as it uses tabs and inline elements (composed from other relations) so a more generic approach would be appreciated.

@shanehoban
Copy link

shanehoban commented Nov 29, 2020

Has this been implemented, I can find anything about it, trying to have an object passed through like so (on strict mode it doesn't like it):

/* App.store.js */

import { getField, updateField } from 'vuex-map-fields';

const getDefaultAppState = () => {
  return {
    config: {
      debug: process.env.VUE_APP_DEBUG_MODE || 'false',
    },
    settings: {
      theme: 'dark-theme',
      loadTimeout: 9857,
      loadLimit: 69,
      stickyScroll: true,
      showBotComments: true,
      showUsernames: true,
      hideReplyIcons: false,
      hidePostLabels: false,
      disableConsoleLogs: false
    }
  }
}

// State object
const state = getDefaultAppState()

// Getter functions
const getters = {
  getField,
}

// Actions
const actions = {}

// Mutations
const mutations = {
  updateField,

  RESET_APP (state) {
    Object.assign(state, getDefaultAppState())
  }
}

export default {
  namespaced: true,
  state,
  getters,
  actions,
  mutations
}

And in my component, I'd love to be able to do something like this:

  computed: {
    ...mapFields('App', ['settings', 'config']),
  },

Which would allow me to use v-model="settings.stickyScroll" for example. Is there a way to do this (without throwing errors in strict mode that is)?

@geoidesic
Copy link
Collaborator

geoidesic commented Nov 29, 2020

@shanehoban no it has not been implemented.
The idea with map fields is that it maps symbols on the vm root to paths in vuex.
What would be your expected outcome in terms of mapped symbols for ...mapFields('App', ['settings', 'config']),?

Are you expecting that each item in the object is mapped to the vm root?
E.g. vm.debug being mapped to config.debug?

@shanehoban
Copy link

Thanks @geoidesic.

To answer your question, I don't really understand how the internals work, but my expectation is that I will always be accessing object properties via dot notation eg.:

v-model="settings.stickyScroll"

so settings as a whole becomes available, and not the properties of it without dot notation, e.g. if I reference stickyScroll, this is never going to reference settings.stickyScroll, if that makes sense

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

No branches or pull requests

10 participants