1

I'm working with Vuejs and have 3 images, a schedule determines which image displays. The appropriate src is loaded in the Computed section so that the images cycle reactively, but it still won't change image unless I manually refresh.

<template>
    <div class="mainDisplay">
      <!--Image div for morning schedule-->
      <div class="imgContainer" v-if="getSchedule(currentHour()).includes('s1')">
        <img class="banner" :src="getSrc" alt="Morning Cappucino">
      </div>
      <!--Image div for afternoon schedule-->
      <div class="imgContainer" v-else-if="getSchedule(currentHour()).includes('s2')">
        <img class="banner" :src="getSrc" alt="Afternoon Latte">
      </div>
      <!--Image div for evening schedule-->
      <div class="imgContainer" v-else-if="getSchedule(currentHour()).includes('s3')">
        <img class="banner" :src="getSrc" alt="Evening Hot Chocolate">
      </div>
    </div>
</template>



<script>
import axios from 'axios';
export default {
  data() {
    return {
      morningCaption: " ",
      afternoonCaption: " ",
      eveningCaption: " ",
      morningSrc: "./public",
      afternoonSrc: "./public",
      eveningSrc: "./public",
      schedule: "",
      src: "",
    }
  },
  mounted() {
    //xml file calling
    axios.get("/screen-schedule-config.xml")
      .then(response => {
        //parse xml data 
        let xmlobj = response.data;
        let domParser = new DOMParser();
        let xmlDocument = domParser.parseFromString(xmlobj, "text/xml");
        // set image path
        let imagePath = xmlDocument.getElementsByTagName("assets");
        //set image src paths
        this.morningSrc = imagePath[0].querySelector("asset").getAttribute("path");
        this.afternoonSrc = imagePath[0].querySelectorAll("asset")[1].getAttribute("path");
        this.eveningSrc = imagePath[0].querySelectorAll("asset")[2].getAttribute("path");
      }
      )
  },
  methods: {
    //get current hour
    currentHour() {
      const currentDate = new Date();
      const hour = currentDate.getHours();
      return hour
    },
    //get schedule for sequence 
    getSchedule(hour) {
      let schedule = "";
      if (hour >= 0 && hour < 12) {
        schedule = "s1";

      } else if (hour >= 12 && hour < 19) {
        schedule = "s2";
      } else {
        schedule = "s3";
      }
      return this.schedule = schedule
    }
  },
  // computed property allows you to have logic that is dependent on reactive data.
  computed: {
    getSrc() {
      if (this.schedule.includes("s1")) {
        this.src = this.morningSrc
      } else if (this.schedule.includes("s2")) {
        this.src = this.afternoonSrc
      } else if (this.schedule.includes("s3")) {
        this.src = this.eveningSrc
      }
      return this.src
    }
  }
}
</script>

My image paths come from the public folder and I have an inkling it's to do with this. Thank you!

bad_coder
  • 11,289
  • 20
  • 44
  • 72
  • Does this answer your question? [How to bind img src to data in Vue](https://stackoverflow.com/questions/48847644/how-to-bind-img-src-to-data-in-vue) – yoduh Oct 17 '22 at 00:38

1 Answers1

1

I just had a problem with this, and for me it was caused by the fact that the server always named images as original.ext, so it wasn't reactive because the filename was always original.jpg

My fix without changing the server to use more reasonable filenames was to simply append a timestamp to the filename.

For example, in my app, there are two functions that load user data: the login function and the check-access-token function. Both of those make a request to the server that returns the user object that has an image field with the filename that remains unchanged even though the file itself is mutating.

My fix was to set the user object as normal but also store the timestamp that the user data was set, such as:

this.user = response.data.user;
this.refreshed_user_at = (new Date()).valueOf();

This allowed me to version the filename which makes it reactive when the filename remains unchanged and the timestamp is changed:

<img :src="`${auth.user.image}?v=${auth.refreshed_user_at}`">

That results in a DOM element:

<img src="http://www.com/original.jpg?v=1779384756845">

I think the original question here is a different problem. In my experience, the img src is reactive when the filename changes in Vue JS, so the problem can only be related to getSrc not updating when values used inside it are changed, thus the filename is not changing. I think more likely here the problem is related to v-if="getSchedule(currentHour()).includes('s1')" because the condition is the result of the method call, and those are not reactive. I would prefer to see a solution that uses a computed prop instead for the condition.

It's tough to recommend a quick fix because I don't understand what the UX goal is. The component seems to be lacking logic related when it should call this.getSchedule(currentHour()).

Perhaps you can simply call it once a second:

data() {
    return {
        intervalId: null,
    };
},

mounted() {
    this.intervalId = setInterval(() => {
        this.getSchedule(this.currentHour());
    }, 1000);
},

beforeDestroy() {
    clearInterval(this.intervalId);
},

Most likely my preferred solution would be to merge getSchedule and getSrc into one computed prop that reads the current hour and returns the correct filename, and then put a setInterval function that sets the current hour into the component state once per second. Then if that merged function is a computed prop, it will automatically update the filename every time the hour changes.

agm1984
  • 15,500
  • 6
  • 89
  • 113