0
votes

I've created a backend and am now trying to build a frontend, using it. I'm very new to Vue.js and am having a hard time telling it to do what I want; probably because of missing some basic concepts. Hopefully someone can point me in the right direction.

The App.vue groups following components: Header, main section (routed), footer and a modal login dialog.
The issue I'm trying to solve is to display the modal login dialog when clicking the Login button (which lives in the header component); currently, nothing besides the messages being logged happens.
For this I've created an event bus and am firing an event:

export default {
  name: 'SppdTeamTunerHeader',
  methods: {
    emitShowLoginDialogEvent () {
      EventBus.$emit('ShowLoginDialog', true)
    }
  }
}

Emitting the event works as I can see in the Vue DevTools for Chrome.

Here's the complete code of App.vue:

<template>
  <div id="app">
    <SppdTeamTunerHeader/>
    <router-view></router-view>
    <SppdTeamTunerFooter/>

    <LoginDialogModal
      v-show="isLoginDialogVisible"
    />
  </div>
</template>

<script>
import SppdTeamTunerHeader from '@/components/TheHeader'
import SppdTeamTunerFooter from '@/components/TheFooter'
import LoginDialogModal from '@/components/LoginDialogModal'
import { EventBus } from '@/common/EventBus'

export default {
  name: 'App',
  components: {
    SppdTeamTunerHeader,
    SppdTeamTunerFooter,
    LoginDialogModal
  },
  data: function () {
    return {
      isLoginDialogVisible: false
    }
  },
  mounted () {
    EventBus.$on('ShowLoginDialog', function (isVisible) {
      console.log('Setting ShowLoginDialog isVisible=' + isVisible + '. isLoginDialogVisible=' + this.isLoginDialogVisible)
      if (isVisible) {
        this.isLoginDialogVisible = true
      } else {
        this.isLoginDialogVisible = false
      }
      console.log('Finished setting isLoginDialogVisible=' + this.isLoginDialogVisible)
    })
  },
  destroyed () {
    EventBus.$off('ShowLoginDialog')
  }
}
</script>

When checking the console, following is being printed when clicking the login button:

Setting ShowLoginDialog isVisible=true. isLoginDialogVisible=undefined
Finished setting isLoginDialogVisible=true

The value logged for isLoginDialogVisible can't come from the variable defined in the data function as it prints undefined, whereas it has been defined as false (I guess that's my main problem).

I've read quite a few articles about the subject, e.g:

The modal dialog example I've based the implementation comes from here: https://alligator.io/vuejs/vue-modal-component/

2

2 Answers

2
votes

This is happening because you are not using an Arrow function. Instead of a plain function, use arrow function like this:

mounted () {
    // Note the use of arrow function.
    EventBus.$on('ShowLoginDialog', (isVisible) => {
      // .. All your code
    })
}

If you use plain function function () {}, then this pointer is not accessible within inner function. Arrow function will lexically bind this pointer to mounted() function's this context. So use an arrow function i.e. () => {};

Note: If you insist on using plain old function syntax then use closure variable to keep track of this pointer:

mounted () {

    // Assign this pointer to some closure variable
    const vm = this;

    EventBus.$on('ShowLoginDialog', function (isVisible) {
      console.log('Setting ShowLoginDialog isVisible=' + isVisible + '. isLoginDialogVisible=' + vm.isLoginDialogVisible)
      if (isVisible) {
        vm.isLoginDialogVisible = true
      } else {
        vm.isLoginDialogVisible = false
      }
      console.log('Finished setting isLoginDialogVisible=' + vm.isLoginDialogVisible)
    })
}

This has nothing to do with Vue.js. It is a typical JavaScript behavior.

2
votes

I believe your listener for the EventBus events needs to be accessible to App. Right now EventBus and App are two separate instances. You could mount the event handler inside App like this:

mounted () {
   EventBus.$on('ShowLoginDialog', function (isVisible) {
      ...
    });