Stig Bosmans
Stig Bosmans

Reputation: 11

Vue.js view doesn't update when an event is received using an eventbus

I'm new to Vue.js 2 and am building my first (vue) web application. The application uses two components, one header component and one login component. When the login is succesfull a "loggedIn"-flag variable will be toggled in a singleton authentication service. This service is responsible to emit an event to the header component (and maybe other listening components) to notify that the user is logged in. The header in turn should update it's view and display the username.

Everything works as described, events are generated and emitted/received using a global event bus. However, when the event is received by the header component it's unable to update the view.

I already tried different approaches: basic subscriber pattern, vuex and now the event bus. Nothing seems to work. Does anyone know what the problem might be?

EventBus.js:

import Vue from 'vue'
var eventBus = new Vue()
export default eventBus

SessionService.js

import eventBus from '../util/EventBus'

class SessionService {
  loggedIn=false
  constructor () {
    if (this.isValid(this.getSessionToken())) {
      this.loggedIn = true
    }
  }
  setSessionToken (token) {
    localStorage.setItem('token', token)
    if (this.isValid(token)) {
      eventBus.$emit('LOGGEDIN')
    } else {
      eventBus.$emit('LOGGEDOUT')
    }
  }
  getSessionToken () {
    return localStorage.getItem('token')
  }
  isValid (token) {
    return token !== undefined && token != null && token !== ''
  }
}
var sessionService = new SessionService()
export default sessionService

Header.vue: Script

  import eventBus from '../../services/util/EventBus'
  var loggedIn = false
  var m = this
  eventBus.$on('LOGGEDIN', function () {
    console.log('RECEIVED')
    m.loggedIn = true
  })

  export default{
    name: 'Header',
    data () {
      return {loggedIn}
    }
  }

Header.vue: HTML

<template>
  <div>
  <nav class="navbar navbar-expand-lg ap-top-nav">
    <div class="container" >
      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="navbarSupportedContent">

        <form class="form-inline my-2 my-lg-0 mr-auto">
          <div class="ap-searcher">
            <input class="ap-search" type="text" placeholder="Search" aria-label="Search"/>
            <i class="fa fa-search"></i>
          </div>

        </form>
        <div class="logo ml-auto mr-auto">
          <img src="../../assets/images/logo.png"/>
        </div>
        <ul class="navbar-nav ml-auto">
          <li class="nav-item ap-button blue wide">
            <router-link to="/login">Login: {{loggedIn}}</router-link>
          </li>
          <li class="nav-item ap-button light-blue wide">
            <router-link to="/registration">Register</router-link>
          </li>
          <li class="nav-item ap-button blue-border">
            <a href="#">EN <i class="fa fa-sort-desc" aria-hidden="true"></i></a>
          </li>
        </ul>
      </div>

    </div>
  </nav>
    <nav class="navbar navbar-expand-lg ag-bottom-nav">
      <div class="container">
        <div class="collapse navbar-collapse " id="navbarNav">
          <ul class="navbar-nav ml-auto">
            <li class="nav-item active">
              <router-link class="nav-link ap-link" to="/">Auctions</router-link>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="#">Lots</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="#">About</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="#">Organize your own auction</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="#">Contact </a>
            </li>
          </ul>
        </div>
      </div>

    </nav>
    <div class="ap-line">
    </div>
  </div>
</template>

Upvotes: 1

Views: 1708

Answers (3)

Ayoub Bousetta
Ayoub Bousetta

Reputation: 316

Old, But the answer is '=>' ARROW_Function

  eventBus.$on('LOGGEDIN', (playload)=>{
  console.log('RECEIVED')
  self.loggedIn = true
})

Upvotes: 0

thanksd
thanksd

Reputation: 55644

In your Header.vue component, when you are registering the 'LOGGEDIN' listener, you are trying to access the Vue instance via this outside the scope of the Vue instance.

Move that logic inside the created hook of the component so that the eventBus listener is still registered when the component is instantiated, but so that this is referencing the Vue instance:

import eventBus from '../../services/util/EventBus'

export default {
  name: 'Header',
  data() {
    return { loggedIn: false }
  },
  created() {
    let self = this;
    eventBus.$on('LOGGEDIN', function () {
      console.log('RECEIVED')
      self.loggedIn = true
    })
  }
}

Upvotes: 3

Axel Stone
Axel Stone

Reputation: 1580

You have some weird structure of Header component code, but I think it should be like this:

  export default{
    name: 'Header',
    data () {
      return { loggedIn: loggedIn }
    }
  }

Upvotes: 0

Related Questions