ToddT
ToddT

Reputation: 3258

V-if not reactive in Vue template

I have a button that I'm rendering with a Vue component. The button depends on some async data from the backend that controls its visibility. The data is being returned and updated fine. However, the button is not shown for some reason. I'm not sure if its because the DOM has already loaded? Not sure why I'm not seeing the button. I've tried both using a computed property as well as a simple data property and both don't work.

However, the console.log IS showing the correct data at the correct time.

Plus if I just set displayLauncherButton it displays fine.

EDIT: To clarify this is a component that gets inserted into an HTML document that was rendered with liquid.

Here is my simplified code:

Vue.component('fresh-credit', {
  data: function () {
    return {
      creditAmount: '',
      currencySymbol: '',
      customerId: '',
      displayLauncherButton: false,
    }
  },
  mounted() {
    this.getCustomerCredit
    this.makeItShow
  },
  template: 
    `
    <div :style="buttonContainer" v-if="makeItShow">
      <button 
        :style="buttonStyle"
        >You Have $</button>
    </div>
    `,
  computed: {
    makeItShow() {
      console.log("this is returning " + this.displayLauncherButton)
      return this.displayLauncherButton
    },
    buttonContainer() {
      return {
        position: 'fixed',
        right: '10px',
        top: '150px',
        zIndex: '99999',
      }
    },
    buttonStyle() {
      return {
        'border-radius': '4px',
        'border': 'none',
        'height': '44px',
        'min-width': '78px',
        'padding': '0 19.5555555556px',
        'font-size': '14px',
        'font-weight': 'bold',
        'text-transform': 'uppercase',
        'cursor': 'pointer',
        'color': 'white',
        'background-color': '#4D4D4DFF',
        'box-shadow': '0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12)!important',
        'outline': 'none',
      }
    },
    async getCustomerCredit() {
      if(this.customerId) {
        let response = await axios.post(`/apps/fresh_credit_proxy`, { shopify_customer_id: this.customerId, type: 'customer_credit'})
        if(response.status == 200) {
          if(response.data.customer_credit == 'no_credit') {
            this.displayLauncherButton = false
            return 
          }
          else {
            this.creditAmount = response.data.customer_credit.current_credit_balance
            this.currencySymbol = response.data.customer_credit.current_credit_balance
            this.displayLauncherButton = true
            console.log("during get credit " + this.displayLauncherButton)
          }
        }
      }
    },
  },
})

new Vue({ el: '#freshie' })

Upvotes: 0

Views: 1473

Answers (1)

tao
tao

Reputation: 90013

computed are getters.

This means that

mounted() {
  this.getCustomerCredit
  this.makeItShow
}

is equivalent to:

mounted() {
  this.getCustomerCredit
  false
}

... because makeItShow gets the current value of displayLauncherButton, which is false in mounted.

You probably want:

mounted() {
  this.getCustomerCredit().then(() => {
    console.log(this.makeItShow);
  });
}, 
methods: {
  // move if here from getters
  async getCustomerCredit() {
    /.../
  }
}

Note that you don't need makeItShow at all. It will always return the current value of displayLauncherButton, so you can just use displayLauncherButton instead.

If you want to run some effect whenever displayLauncherButton changes, don't use a computed, use a watch on displayLauncherButton. For example, to log the value of displayLauncherButton every time it changes, add:

watch: {
  displayLauncherButton: console.log
}

to your component. This will log both parameters (newVal, oldVal), every time it changes.


Note the mounted above can also be written as:

async mounted() {
  await this.getCustomerCredit();
  console.log(this.makeItShow)
}

Don't let async mounted trick you into believing it will delay the rendering of the component. The component will render before mounted returns if mounted is async.

Upvotes: 2

Related Questions