-1

I would like to update my object and keep the reactivity. selectedTime is a Date object, substractMonths will return a new Date object.

<span
   class="calendar__pickable__chevron"
   @click="selectedTime = substractMonths(1, selectedTime)"
   >
   <span>
      <font-awesome-icon icon="chevron-left" />
   </span>
</span>

The problem is that by doing this, my state is not updated because Vue 3 is not able to detect the replacement of the object.

How I can fix this it ? (I specify that I have used const selectedTime = ref(new Date()) to create a reactive object).

enter image description here

Substract function does return new Date object.

Part of code: https://gist.github.com/SirMishaa/efb0efe74c6355aabbcb853f7650c22f

The only thing I try to do is to execute a function that returns a new date, and replace my selectedTime with the return value of the function.

Sir Mishaa
  • 541
  • 1
  • 6
  • 19
  • Are you aware of [computed properties](https://v3.vuejs.org/guide/computed.html)? Did you try to extract `substractMonths(1, selectedTime)` into a computed? – Temoncher Dec 03 '20 at 11:37
  • I'm using the [composition API](https://composition-api.vuejs.org/), how this is working with it ? – Sir Mishaa Dec 03 '20 at 11:47
  • @BoussadjraBrahim Why you need it ? I'm only taking a date, I add the selected number of months and I return the new Date. – Sir Mishaa Dec 03 '20 at 11:49
  • I don't think I need a computed method, I'm just trying to mutate my state. I make a datepicker, for context. – Sir Mishaa Dec 03 '20 at 11:57
  • This is not reproducible – Dan Dec 03 '20 at 13:46
  • @Dan, this is simple. Make a component, use an object and mute it using a function. And you will see the error. This is kinda simple. – Sir Mishaa Dec 03 '20 at 14:57
  • Have a look at the [site guidelines](https://stackoverflow.com/help/minimal-reproducible-example) to understand the meaning of a good question with reproducible error. And also notice: `DO NOT use images of code.` – Dan Dec 03 '20 at 15:07
  • The image is just to represent the type of return functions and they are not useful in solving my problem. I still know that images are not practical. I'm going to make a reply with a new simple code to show my problem. – Sir Mishaa Dec 03 '20 at 15:16
  • @Dan Thanks you for your jsfiddle, Indeed, this is working good. My code is here, and I'm on this error since 2 days : https://github.com/SirMishaa/vue-datepicker/blob/master/src/components/DatePicker.vue sorry If i'm a bit salty. I can't get why this isn't working. – Sir Mishaa Dec 03 '20 at 15:36
  • A good next step would be replacing `substractMonths(1, selectedTime)` with `new Date()` and reporting the results. – Dan Dec 03 '20 at 22:05
  • 1
    @Misha The might be a duplicate of https://stackoverflow.com/questions/40959483/why-does-vue-js-not-update-the-dom-with-datepicker-using-moment-js. Your date functions modify the original date and return it. Since the reference to `selectedTime` hasn't changed, Vue doesn't detect it, so the template doesn't update. One workaround is for your date functions to create a new date from the original (which I think you might've intended to begin with). https://codesandbox.io/s/updating-date-object-in-template-9nmlj?file=/src/utils/date-utils.js:203-239 – tony19 Dec 03 '20 at 22:29
  • I've made a codesanbox with a small example, this is kinda boring... : https://codesandbox.io/s/wandering-paper-o952k?file=/src/App.vue Thank you for your answer, I'll try it. – Sir Mishaa Dec 04 '20 at 10:05
  • @tony19 Indeed, this is wokring. – Sir Mishaa Dec 04 '20 at 10:06

1 Answers1

3

I have finally solved the problem, so I will describe the solution.

I created a small example : https://codesandbox.io/s/wandering-paper-o952k?file=/src/App.vue

<template>
  <h1>{{ currentTime.toString() }}</h1>
  <button @click="currentTime = addMonths(1, currentTime)">
    Add one month
  </button>
</template>

function addMonths(numberOfMonths, currentTime) {
  const x = currentTime.getDate();
  currentTime.setMonth(currentTime.getMonth() + numberOfMonths);
  console.log(`Function has been called with : ${currentTime}`);
  if (currentTime.getDate() !== x) {
    currentTime.setDate(0);
  }
  return currentTime;
}

Vue is unable to detect the change because I return an object that has the same reference (as the old object). The solution is therefore to create a new object, in order to allow the change to be detected.

Insead of return currentTime;, do something like this return new Date(currentTime) will work.

I'm glad If I could help. I've been looking for the solution for a long time

Sir Mishaa
  • 541
  • 1
  • 6
  • 19