user9024437
user9024437

Reputation:

Overriding the value of a global variable

I just created two variables $isCompany and $isLoggedIn in my main.js.

import Vue from "vue";
import App from "./App.vue";
import "./registerServiceWorker";
import router from "./router";

Vue.config.productionTip = false;
Vue.prototype.$isCompany = true;
Vue.prototype.$isLoggedIn = true;

new Vue({
  router,
  render: h => h(App)
}).$mount("#app");

My Question: How can I access these variables in my <Button> component in Navigation.vue? v-ifs are working but I'm not able to toggle the value of the variable, so I think there is an issue with overriding the value.

<div v-if="this.$isLoggedIn" class="header-left">
  <User v-if="this.$isCompany" name="Company" img="..."></User>
  <User v-if="!this.$isCompany" name="Not Company" img="..."></User>
  <Button @onclick="this.$isCompany = !this.$isCompany" :color="'grey'" :isIconOnly="true"><b-icon icon="arrow-down-up"></b-icon></Button>
</div>

If you need it, here is the way how I bind the @onclick to my <Button> component:

<button @click="$emit('onclick')" :class="['button', 'size-'+size, 'color-'+color, isRounded ? 'type-rounded' : '', isIconOnly ? 'type-icon-only' : '']">

EDIT: Just noticed this error in my console if I click the button: enter image description here

Upvotes: 0

Views: 758

Answers (1)

Decade Moon
Decade Moon

Reputation: 34306

v-ifs are working

Are you sure? I expect v-if="this.$isLoggedIn" not to work because this should not be used here (it is redundant; there is an implicit this. already there so you're basically doing this.this.$isLoggedIn).

but I'm not able to toggle the value of the variable

This is probably because you have not defined the variables in a "reactive" way.

Vue.prototype.$isCompany = true;
Vue.prototype.$isLoggedIn = true;

It feels a bit awkward to define the variables like this on the Vue prototype object.

You can define the global variables in a reactive way by defining them as data properties of the root Vue instance:

new Vue({
  router,
  render: h => h(App),

  data: {
    isCompany: false,
    isLoggedIn: false,
  }
}).$mount("#app");

You can access them from any descendant component via this.$root.isCompany. So, in your template, you would do:

<User v-if="$root.isCompany" name="Company" img="..."></User>

If you really want to avoid doing $root. in the template, then you can define proxy properties on the Vue prototype object (in addition to the above):

Object.defineProperties(Vue.prototype, {
  $isCompany: {
    get() { return this.$root.isCompany },
    set(x) { this.$root.isCompany = x }
  },
  $isLoggedIn: {
    get() { return this.$root.isLoggedIn },
    set(x) { this.$root.isLoggedIn = x }
  },
})

Now you can do this in the template:

<User v-if="$isCompany" name="Company" img="..."></User>

Here is a small demo:

Object.defineProperties(Vue.prototype, {
  $isCompany: {
    get() { return this.$root.isCompany },
    set(x) { this.$root.isCompany = x }
  }
})

Vue.component('child', {
  template: '<div><input type="checkbox" v-model="$isCompany"> {{ $isCompany }}</div>'
})

new Vue({
  el: '#app',
  data: {
    isCompany: false,
  },
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <child></child>
</div>

Upvotes: 1

Related Questions