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

Cannot access Vuex $store inside Modal component #55

Closed
rafaberaldo opened this issue May 10, 2017 · 22 comments
Closed

Cannot access Vuex $store inside Modal component #55

rafaberaldo opened this issue May 10, 2017 · 22 comments

Comments

@rafaberaldo
Copy link
Member

rafaberaldo commented May 10, 2017

Trying to access this.$store inside a Modal with component prop returns undefined, and I have no idea why that's happening.

@rafaberaldo
Copy link
Member Author

A workaround for this is importing the store file and set it as a property:

import store from '../../vuex/store'

export default {
    data() {
        return {
            store
        }
    }
}

@gustojs
Copy link

gustojs commented May 10, 2017

Can you share the exact code that didn't work for you?

@rafaberaldo
Copy link
Member Author

rafaberaldo commented May 10, 2017

this.$store is undefined inside the Settings component when calling a modal with component prop:

this.$modal.open({
    component: Settings
})

@gustojs
Copy link

gustojs commented May 10, 2017

From what I see, the whole Modal component gets attached to DOM as a direct child of <body> and as a sibling to the main Vue application. It's not visible for the main Vue instance and vue-devtools, so I believe it's treated as a separate Vue instance, to which we didn't pass the store and which we can't debug with vue-devtools.

Personally I make sure to create my modals under the control of main Vue instance, so I have no such issues and that's what I'd recommend for the components where you want to use custom user code.

@rafaberaldo
Copy link
Member Author

That makes sense, it doesn't appear in the vue-devtools as well as you said. But then there's no way to make a programmatic modal like that?

@gustojs
Copy link

gustojs commented May 10, 2017

There should be.

I just came back to coding after holidays so now have to catch up on work first, but I'll try to provide an alternative solution for modals later, as I'm invested in Buefy with current project.

@rodymolenaar
Copy link

rodymolenaar commented May 10, 2017

@rafaelpimpa Your Modal implementation does not show up in the vue-devtools component tree?

Also, but unrelated, do you want me to make a pull-request for prop binding to a Modal? I have a working implementation using v-bind you can pass it an object with key value pairs that will automatically be passed as props to the component.

@rafaberaldo
Copy link
Member Author

@rodymol123 No it doesn't.

I'm not sure what you mean by prop-binding, could you elaborate?

@rodymolenaar
Copy link

@rafaelpimpa How does one get data to a component in the modal now? Prop-binding is like doing :prop="value" on a component in the template, with v-bind this can be done programmatically.

My custom Modal component looks almost exactly the same as yours but allows values to be passed to the component e.g.

this.$modal.open(EditClientModal, {
    id: client.id,
    name: client.name,
    redirect: client.redirect
})
<component :is="component" v-bind="passedProps" @close="close"></component>

then the values can be used inside the component like this:

export default {
        props: ['id', 'name', 'redirect'],
        data() {
            return {
                editForm: {
                    errors: [],
                    name: this.name,
                    redirect: this.redirect
                }
            }
        },
        mounted() {
            this.$refs.focus.$refs.input.focus()
        },

the props attribute inside the component is required in order for this to work

I think that in your implementation a props attribute could be added besides the component attribute on open()

@rafaberaldo
Copy link
Member Author

Oh I see, I think it's easier to just send an object prop for the component though.

Does your modal implementation have access to $store? If so, how did you do?

@rodymolenaar
Copy link

@rafaelpimpa It's important to use v-bind on props in the Modals because else objects are passed through reference, meaning that in an edit form the data will transform in the UI underneath the Modal aswell, without input validation of sorts.

On to subject:

http://i.imgur.com/kdqL32h.png

My Modal component is visible in component tree after a refresh, but doesn't have access to this.$store either. As my screenshot shows it's probably because it is not a child of the root component when created dynamically. Using $mount() instead of el: doesn't seem to change that.

I think we could get some knowledge from: vuejs/Discussion#247, vuejs/Discussion#254

@rafaberaldo
Copy link
Member Author

rafaberaldo commented May 11, 2017

I found this forum thread with a response from a core team member of Vuejs.

But nothing like a programmatic way.

@rafaberaldo
Copy link
Member Author

I might be changing it to a normal template like Notifications instead of doing it programmatically, looks like it's the best way.

cmd-shift-s added a commit to cmd-shift-s/buefy that referenced this issue Jul 6, 2017
@cmd-shift-s
Copy link
Contributor

for example:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(vuex)
const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }
})

import Buefy from 'buefy'
Vue.use(Buefy, {store})

this.$store will not return undefined

@cmd-shift-s
Copy link
Contributor

i looked this
https://github.com/vuejs/vuex/blob/dev/src/mixin.js#L19

and made this sample

@rafaberaldo
Copy link
Member Author

That's interesting, but as I researched a lot about this I heard that is not a good practice to create things outside of the main vue instance.

So I've removed the component modal programmatically from the docs for the newcomers don't use, it's preferable to use the non-programmatic one.

@cmd-shift-s
Copy link
Contributor

cmd-shift-s commented Jul 6, 2017

I got it
thank you 😄

@LinusBorg
Copy link

LinusBorg commented Nov 13, 2017

@rafaelpimpa This is coming a bit late, but you can make a programatically created instance become a child of the app's component tree by defining the component's parent explicitly:

const modal = new ModalComponent({
  parent: this
})

That will ensure that it

  • appears in devtools
  • has access to this.$store
  • has access to this.$router

...etc

@rafaberaldo
Copy link
Member Author

@LinusBorg Oh thanks a lot, by the time I searched a lot and couldn't found a proper way, is it new from Vue? Even tho I read all the changelogs I might have missed this one.

@LinusBorg
Copy link

That option has been around for all of version 2 at least, if memory serves me right.

@James-Z-Tang
Copy link

@LinusBorg Your solution works for $store but I found that css from parent component is not applied to the dynamically created component.

@gianRVN
Copy link

gianRVN commented Jan 25, 2022

@LinusBorg Could you please explain to me what is "ModalComponent" there? because I try to follow your approach but nothing seems to be happened. thank you

kikuomax added a commit to kikuomax/buefy that referenced this issue Sep 4, 2023
* test(lib): update Input spec

- Updates the unit tests (spec) of `Input` so that they can work with
  Vue 3 and `@vue/test-utils` V2:
    - Replaces `wrapper.name()` with `wrapper.vm.$options.name` because
      `wrapper.name` no longer exists in `@vue/test-utils` V2.
    - Replaces the test on `wrapper.isVueInstance()` with presence of
      `wrapper.vm` because `wrapper.isVueInstance` no longer exists in
      `@vue/test-utils` V2.
    - Awaits `wrapper.setProps` and `wrapper.setData` to make sure the
      subsequent tests verify the updated state.
    - Corrects the v-model binding: `value` → `modelValue`
    - Removes the `methods` option for `mount` because `@vue/test-utils`
      V2 no longer deals with it. Replaces the code intended to override
      `checkHtml5Validity` method `useHtml5Validation: false`.
    - Replaces the expected value for `readonly` attribute: "readonly" →
      "" (an empty string). Vue 3 no longer assigns a value to a
      boolean attribute.
    - Replaces `wrapper.find` intended to locate a Vue component with
      `wrapper.findComponent` because `wrapper.find` is dedicated to DOM
      elements in `@vue/test-utils` V2.
    - Renames `propsData` → `props` because `propsData` was deprecated.
    - Refreshes the snapshot. I did not see any problems in the new
      snapshot.

issue ntohq#1

* feat(docs): add attr pass down example for Input

- Appends an example that passes attributes `placeholder` and `readonly`
  down to the underlying `<input>` element throught `Input` to
  `ExSimple`. I have introduced this example because I wanted to make
  sure the unit test "render the placeholder and readonly attribute when
  passed" was verifying the intended behavior.
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

7 participants