quasarframework / quasar

Quasar Framework - Build high-performance VueJS user interfaces in record time
https://quasar.dev
MIT License
25.81k stars 3.51k forks source link

Issue with modal and tree component handler #812

Closed abacram closed 7 years ago

abacram commented 7 years ago

I'm trying to run Events.$emit('openModal') from a quasar tree component node (handler). It's supposed that openModal event must open a quasar modal via this.$refs like the following line: Events.$on('openModal', () => { this.$refs.openModal.open() })

The modal is tagged with the ref in the template code correctly.

But in fact, i have the error: Uncaught TypeError: Cannot read property 'open' of undefined

I have another events with drawers and modals working but i cannot find a logic for that issue. Can you help me?

Thanks!

rstoenescu commented 7 years ago

Hi, This sounds like a misusage. Can you post your whole component or better do you have a repo I can take a look at? Thanks!

abacram commented 7 years ago

Yes, i know it. It's curious because when i load the first time the component, console.log(this.$refs) give me a well formed array, but if i navigate inside the app and return to the component, console.log show me all values in the array as undefined. I think that's the issue.

I'm mounting the event listener in the mounted component hook, that's right?

rstoenescu commented 7 years ago

Some thoughts:

  1. Navigating away most likely destroys your component where you have the QModal. So might be a good idea to extract QModal to a place where navigating away does not destroy it (and by so doing Vue reference to modal becoming useless).
  2. If you register the event handler in the mounted component hook, then it means you will be constantly adding handlers for that event if you navigate back and forth to the route which renders your component.

Might be a good idea to rethink your strategy.

abacram commented 7 years ago
<template>
  <div>
    <!-- SALESFORCE MODAL -->
    <q-modal ref="salesForceModal" position="right" :content-css="{minWidth: '88vw', minHeight: '100vh'}">
    </q-modal>

    <!-- FILTERS -->
    <div class="card no-margin">

    </div>

    <!-- TREE -->
    <div class="card no-margin">
      <q-tree :model="treeModel" contract-html="<i>remove_circle</i>"></q-tree>
    </div>

  </div>
</template>

<script>
import { Utils, Toast, Events } from 'quasar'
import store from '../../../../vuex/store'
import helpers from '../../../../utils/helpers'
import moment from 'moment'

export default {
  mixins: [helpers],
  mounted () {
    Events.$on('openSalesForceModal', () => {
      console.log(this.$refs)
      this.$refs.salesForceModal.open()
    })
  },
  data () {
    return {
      treeModel: [
        {
          title: 'LCS',
          expanded: true,
          children: [
            {
              title: 'HQ-Dublín / HQ (active)',
              expanded: false,
              children: [
                {
                  title: 'HQ-Dublín Center / HQ (active)',
                  expanded: false,
                  children: [
                    {
                      title: 'HQ-Dublín Center Side A / HQ (active)',
                      expanded: false,
                      children: []
                    },
                    {
                      title: 'HQ-Dublín Center Side B / HQ (active)',
                      expanded: false,
                      children: []
                    }
                  ]
                },
                {
                  title: 'HQ-Dublín East / HQ (active)',
                  expanded: false,
                  children: []
                },
                {
                  title: 'HQ-Dublín West / HQ (active)',
                  expanded: false,
                  children: []
                }
              ]
            },
            {
              title: 'HQ-Madrid / HQ (active)',
              expanded: false,
              children: []
            },
            {
              title: 'HQ-París / HQ (active)',
              expanded: false,
              handler () {
                Events.$emit('openSalesForceModal')
                Toast.create.positive('Editando HQ-París / HQ (active)')
              },
              children: []
            },
            {
              title: 'HQ-Toulouse / HQ (active)',
              expanded: false,
              handler () {
                Events.$emit('openSalesForceModal')
                Toast.create.positive('Editando HQ-París / HQ (active)')
              },
              children: []
            }
          ]
        }
      ]
    }
  }
}
</script>

<style>
</style>
abacram commented 7 years ago

Yes, i understand it. I have another Event listener for the drawers behaviours in app.vue, where is the main layout and it works perfect, but i cannot find the way to make it work inside a component as you say.

But the point is, if i open the modal from template with @click and $refs.openModal.open() it works perfectly.

I'll give a look around to this, but all help is welcome :100:

rstoenescu commented 7 years ago

Hmm, no need to use an Event bus for this.

export default {
  mixins: [helpers],

  // no mounted() necessary anymore, just delete this line:
  mounted () { },

  data () {
    return {
      treeModel: [
        {
          title: 'LCS',
          expanded: true,
          children: [
            {
              title: 'HQ-Dublín / HQ (active)',
              expanded: false,
              children: [
                {
                  title: 'HQ-Dublín Center / HQ (active)',
                  expanded: false,
                  children: [
                    {
                      title: 'HQ-Dublín Center Side A / HQ (active)',
                      expanded: false,
                      children: []
                    },
                    {
                      title: 'HQ-Dublín Center Side B / HQ (active)',
                      expanded: false,
                      children: []
                    }
                  ]
                },
                {
                  title: 'HQ-Dublín East / HQ (active)',
                  expanded: false,
                  children: []
                },
                {
                  title: 'HQ-Dublín West / HQ (active)',
                  expanded: false,
                  children: []
                }
              ]
            },
            {
              title: 'HQ-Madrid / HQ (active)',
              expanded: false,
              children: []
            },
            {
              title: 'HQ-París / HQ (active)',
              expanded: false,

              // notice we use ES6 arrow functions
              handler: () => {
                 // we got access to our component here, so referencing modal directly
                 this.$refs.salesForceModal.open()
                Toast.create.positive('Editando HQ-París / HQ (active)')
              },
              children: []
            },
            {
              title: 'HQ-Toulouse / HQ (active)',
              expanded: false,

              // same as above with ES6 arrow functions
              handler: () => {
                // we got access to our component here, so referencing modal directly
                this.$refs.salesForceModal.open()
                Toast.create.positive('Editando HQ-París / HQ (active)')
              },
              children: []
            }
          ]
        }
      ]
    }
  }
}
abacram commented 7 years ago

Awesome @rstoenescu, sorry for my dumb issue!!! I cannot realize on that.

Thanks for your help and time! :)

rstoenescu commented 7 years ago

Glad I could help! Now go build an awesome app so we can showcase it :)