Vue Class Component property not defined on instance

1.1k views Asked by At

I have the problem that my UI is somehow not updating after the applications fetches some data from the sever backend.

I have the following code:

<template>
  <div v-if="restaurant">
    <div class="center logo-container">
        <img class="img-fit" v-bind:src="'/api/restaurant/logo/' + restaurant.id" alt=""/>
    </div>
    <h2 class="title center dm-text-header">{{ restaurant.name }}</h2>
    <h4 class="subheading center">{{ restaurant.address.street }}, {{ restaurant.address.city }}</h4>     
  </div>
</template>

<script lang="ts">
import axios from 'axios';
import { Options, Vue } from "vue-class-component";
import { Tag } from "./Tag";
import { Restaurant } from "./Restaurant";

@Options({
  props: {
  }
})
export default class Menu extends Vue {  
  // hardcoded for testing 
  restaurantId =  "8ykw9ljq";   

  tagUrl = "/api/menu/" + this.restaurantId + "/tags";
  restaurantUrl = "/api/restaurant/" + this.restaurantId;

  restaurant!: Restaurant;
  tags: Tag[] = [];

  mounted() {
    // get tags
    this.getTags();
    // get restaurant
    this.getRestaurant();
  }

  getRestaurant(): void {
    axios.get<Restaurant>(this.restaurantUrl)
    .then(res => {
      this.restaurant = res.data;
    });
  }

  getTags(): void {
    axios.get(this.tagUrl)
    .then(res => {
      this.tags = res.data;
    });
  }

}
</script>

I verified that the backend actually serves the correct restaurant and logged the results after the axios call finishes. The problem is that the DOM is not updated. If I add the following to the the DOM is upadated:

<template>
...
  <div>
    {{tags}}
  </div>
<template>

It seems to me that vue somehow only updated the DOM if it recognizes changes to the already initialized empty array but not the currently uninitialized restaurant object.

I further get a warning: [Vue warn]: Property "restaurant" was accessed during render but is not defined on instance. on the v-if what I kind of find strange because that is the exact reason it is there. How do I need to initialize the restaurant, such that the update through axios is correctly recognized by vue?

1

There are 1 answers

0
Dan On BEST ANSWER

Try a Typescript union with null:

restaurant: Restaurant | null = null;

From the Vue Class Component docs:

Note that if the initial value is undefined, the class property will not be reactive which means the changes for the properties will not be detected

and

To avoid this, you can use null value or use data hook instead:

import Vue from 'vue'
import Component from 'vue-class-component'

@Component
export default class HelloWorld extends Vue {
  // `message` will be reactive with `null` value
  message = null

  // See Hooks section for details about `data` hook inside class.
  data() {
    return {
      // `hello` will be reactive as it is declared via `data` hook.
      hello: undefined
    }
  }
}