Using a computed property setter in Vue.js/Javascript while focusing on a datepicker can lead to crashing the browser

Can anyone explain why my javascript / vuejs code is crashing on my JSFiddle when I focus on the start date datepicker (causing the browser to hang)? If you uncomment the endDate computed property and comment out the current one, it works fine but the functionality is lost.

endDate: {
      get() {
        return moment(this.startDate).add(this.interval * this.periods, 'days')
      },
      set(value) {
        this.interval = (moment(value).diff(this.startDate, 'days')+1) / this.periods
      }
    },

Here is the original post discussing the functionality I tried to implement.

Answer №1

Update: While this solution may sacrifice the reactivity of the endDate, it highlights the unnecessary rendering overload caused by the plugin. With an infinite number of dates, the plugin renders for each date in the datepicker. For a more effective approach, refer to the latest post discussing the removal of computed properties.


Upon revisiting the initial code you shared, I have implemented a solution that addresses the issue. It's surprising I didn't think of this sooner.

Take a look at this jsfiddle: https://jsfiddle.net/ghLmnm2c/301/

To prevent unnecessary re-renders in your code, simply include v-once on top of the plugin directives you use.

  <date-picker v-model="startDate" :config="config" v-once></date-picker>
  <date-picker v-model="endDate" :config="config" v-once></date-picker>

Observe how I incorporate the v-once directive. The issue wasn't with your code itself, but rather Vue's automatic re-rendering of the datepicker, which can be avoided to maintain the datepicker's inherent rendering behavior.

https://v2.vuejs.org/v2/api/#v-once

Furthermore, I came across a useful feature that you might find beneficial. If you refer to the provided link below and navigate to the events section, you'll find that the plugin you're using can emit change, update, and hide events:

https://github.com/ankurk91/vue-bootstrap-datetimepicker

Therefore, you can utilize features like the following:

<date-picker v-model="date" @dp-hide="doSomethingOnHide" @dp-change="doSomethingOnChange"></date-picker>

Answer №2

Check out this new solution: https://jsfiddle.net/ghLmnm2c/483/

After further consideration, I decided to revisit an older approach that was initially mentioned when I first attempted to assist you. I removed the computed properties as they may have been affecting the component rendering process. Instead, I replicated the functionality using the plugin's event emitters and added a watcher on the interval plugin to achieve the same functionality.

Below is what the HTML structure looks like:

Start Date: <date-picker v-model="startDate" :config="config" @dp-change="updateEndDateInterval"></date-picker>
End Date: <date-picker v-model="endDate" :config="config" @dp-update="updateInterval"></date-picker>
Interval: <input class="form-control" type="text" v-model="interval" @keyup="updateEndDate">

It was determined that only the start date and the interval inputs would affect the end date.

Here are the methods used:

methods: {
   updateEndDateInterval: function() {
      this.updateEndDate(); // this automatically triggers updateInterval due to @dp-change="updateInterval" on the end date component
  },
  updateEndDate: function() {
      this.endDate = moment(this.startDate).add(this.interval * this.periods, 'days');
  },
  updateInterval: function(v) {
      if (this.periods > 0) {
         var dateVal = "";
         if (v.target) {
              dateVal = v.target.value;
         } else {
            dateVal = v;
         }
         this.interval = (moment(dateVal).diff(this.startDate, 'days')+1) / this.periods;
      }
  }
}

The updateInterval function accepts a 'v' parameter, which will receive the moment object passed from updateEndDateInterval or the event object when changing the interval value. Passing in this.endDate from the interval textbox would create a circular reference, causing the interval to update the end date and vice versa indefinitely.

Moreover, it is necessary to ensure that the endDate property is reactive:

data: {
    interval: 7,
    startDate: moment(),
    endDate: ''   // keep this property empty
}

Upon loading the component, update the endDate property to match the start date value (as defined in updateEndDate):

mounted: function(){
      this.updateEndDate();
}

After verifying all functionalities against your previous fiddle and checking for reactivity, it appears that this strategy, utilizing the recommended plugin methods, is preferable. There were no indications of computed properties being used in the examples, making the implementation more modular and allowing for easier adjustments without inadvertently affecting other components.


Initially, I considered using a Vue watcher on the interval textbox triggering the updateEndDate function in this manner:

// do not do this
watch: {
    interval: function() {
        this.updateEndDate()
    }
}

This approach is not viable due to the circular reference issue, leading to a crash in your browser. Hence, I opted for the @keyup event to prevent interference with date selections, ensuring that the updateEndDate function is only triggered by key inputs when altering the interval.


(FIXED) Addressing the root issue. The problem at hand has been resolved. It was discovered that when solely using computed properties, the underlying issue remained unnoticed, hindering the proper editing of the interval.

When modifying only the end date, the interval calculation formula functions correctly since only the interval is being altered. However, adjusting the start date impacts both the end date and the interval.

Updating the end date first becomes challenging as the interval value becomes outdated, resulting in an incorrect end date calculation. Conversely, reversing the order makes the end date value outdated, rendering the interval value incorrect.

 // stale this.interval value as it isn't updated beforehand
 this.endDate = moment(this.startDate).add(this.interval * this.periods, 'days').format('DD MMM YYYY');
 // utilizing the incorrect this.endDate to compute the incorrect this.interval
 this.interval = (moment(this.endDate).diff(this.startDate, 'days')+1) / this.periods;

Attempting to switch the execution order leads to a similar predicament where the stale this.endDate prevents an accurate interval value. Subsequently, using the incorrect interval value results in an incorrect end date.

 // stale this.endDate value as it isn't updated beforehand
 this.interval = (moment(this.endDate).diff(this.startDate, 'days')+1) / this.periods;
 // utilizing the incorrect this.interval to deduce the incorrect this.endDate
 this.endDate = moment(this.startDate).add(this.interval * this.periods, 'days').format('DD MMM YYYY');

Answer №3

Examination This response does not directly address the original question but aims to provide guidance on identifying the root cause of browser crashes and potential remedies to resolve them.

https://jsfiddle.net/ghLmnm2c/227/

In line with my fourth conclusion outlined below, I implemented a reactive proxy variable named endDateProxy. By linking the endDate to this endDateProxy and updating its value in the getter method, the issue was resolved.

<date-picker v-model="endDateProxy" :config="config"></date-picker>

...

data: {
    .... // other stuff

   endDateProxy: ''   //proxy reactive variable
},

....

get() {
   //set the reactive endDateProxy property
    this.endDateProxy = moment(this.startDate).add(this.interval * this.periods, 'days');
    return this.endDateProxy
  }

Past Response


The situation presented is indeed peculiar. After diligent analysis, I have crafted potential solutions that may aid in resolving the issue or directing you towards the right path.

Conclusions

  1. Consider abandoning the use of VueBootstrapDatetimePicker and creating a custom wrapper component using Moment.js incorporated into Vue.js. Reference the select2 example on Vue's official documentation.

  2. Alternatively, switch from Moment.js to JavaScript's conventional Date object.

  3. Alternatively, experiment with wrapping your setter with Math.random(), although the effectiveness is uncertain. This method yielded positive results in the analysis below.

  4. My final recommendation suggests avoiding computed properties directly linked to the v-model of the plugin. Instead, create a reactive data variable named "endDate", associate the v-model with this variable, and define a setEndDate Vue method accompanied by event listeners on relevant controls.

Analysis:

A detailed examination, accompanied by numerous browser crashes - quite entertaining!

The initial challenge was isolating the cause behind the browser crashes within your code. After ruling out circular dependencies, it was apparent that altering the calculated setter's formula could alleviate the issue:

set(value) {
    this.interval = 8
  }

Modifications like removing the divisor or using Math.round proved successful in rectifying the problem. Various test scenarios were conducted to gauge the impact of specific formula changes.

Adjusting the format to comply with standards like ISO 8601 and RFC 2822, while addressing deprecated values, enhanced code readability and minimized errors, despite the browser's behavior remaining consistent.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

ReactJs throws an error of "Uncaught SyntaxError: Unexpected token '<' while utilizing the map() function in ReactJs that produces JSX (specifically MaterialUi-icons) within an array

In the file constant.js, I have defined object names and icons as keys. The key icon contains the icon component from @mui/icons-material, but when I attempt to retrieve the value from the icon, I encounter an error. Uncaught SyntaxError: Unexpected toke ...

Oops! There seems to be a problem with the Node.js App. The MongooseError is indicating that the parameter `uri` in the `openUri()` function should be a string,

I've encountered an issue with my Next.js app involving MongoDB that I've been struggling to resolve. Hoping someone here can provide some insight and help me out. This is quite crucial for my project. First, I'll share the code from my serv ...

Modify the values of several dropdown menus (5 in total) at once using jQuery. The values will be dynamically retrieved from a JSON file

https://i.sstatic.net/9vjlz.png Dropdown values for the first dropdown are 1, 2, 3, 4, 5. Dropdown values for the second dropdown are 25, 26, 27, 28, 29. Dropdown values for the third dropdown are 35, 36, 37, 38, 39. The goal is to have each dropdown load ...

To activate two separate click events, one for an absolute element and another for the element positioned behind it, simply click on the desired absolute element to trigger both actions

Is it possible to trigger click events for both of these elements? position: relative container ELEMENT 1: standard div ELEMENT 2: position: absolute div In real life, element 2 is a transparent backdrop designed to capture clicks on top of the header ...

Guide on exporting values from a Promise within an imported module

Recently, I encountered a challenge where I needed to integrate a pure ESM package into a non-module. Unfortunately, modifying the script to accommodate this requirement was not an option. To tackle this issue, I turned to using the import() function (als ...

Creating a dynamic list filter using JavaScript and three select boxes

Looking for a way to implement a similar feature to the one on this webpage: I will be showcasing a list of brands on the page, with each brand requiring three pieces of information: Starting letter Store (multiple options) Category (multiple options) ...

Combining round brackets and square brackets when initializing an array

In the snippet below, values are assigned with a mix of parentheses and square brackets without any errors. However, most other combinations (such as parentheses inside square brackets) do not work at all. var myItems = []; myItems[5] = ("A1", "B1", ["C1" ...

Is the AngularJS application failing to transmit data accurately to Node.js?

I've been grappling with this issue for a few days now and I can't seem to pinpoint the problem. As someone relatively new to the MEAN stack, I might be overlooking something obvious. I followed the boilerplate code from mean.io for both the back ...

Unable to establish SocketIO callback from client to server resulting in a null object instead

I'm encountering an unusual issue with SocketIO. On the server-side, I am using the emit() method like this: $s.sockets.emit(scope, {some: datas}, function(feedback) { console.log('received callback'); } ) ...

Caution: Refs cannot be assigned to function components

I'm currently using the latest version of Next.js to create my blog website, but I keep encountering an error when trying to implement a form. The error message reads as follows: Warning: Function components cannot be given refs. Attempts to access t ...

"Assigning an array as a value to an object key when detecting duplicates in a

Let's assume the table I'm iterating through looks like this: https://i.stack.imgur.com/HAPrJ.png I want to convert each unique value in the second column into an object, where one of the keys will hold all values from corresponding rows. Here& ...

Tips on updating the default checkbox dynamically based on the current checkbox using JavaScript

Seeking to enhance the design of a Perl-generated form with custom CSS effects, rather than relying on the default Perl form. Despite successful functionality, encountering an issue where radio button focus reverts to default selection (Date) after submitt ...

Exploring the money library in typescript after successfully installing it on my local machine

I've been struggling to set up a new library in my TypeScript project for the first time, and I can't seem to get it functioning properly. The library in question is money. I have downloaded it and placed it in the root of my project as instructe ...

a pair of browser windows displaying a web application built with ASP.NET MVC

We are currently in the process of developing an ASP.NET MVC web application for internal use within our organization. Our users' productivity can greatly benefit from having a larger screen space, which is why we have decided to provide each user wit ...

"Creating a cohesive design: Using CSS to ensure the navigation background complements

I am working on a project with a horizontal navbar that I want to stay fixed while scrolling. The main window has different colored divs as you scroll down, and I would like the navbar to match the image of the main div while scrolling, creating a looping ...

What is the best way to ensure that the value passed from v-select to a method remains consistent and does not change from the default setting

I'm facing an issue where I need to pass a value from a v-select dropdown in my Vue app to a function. The v-select is populated from an array called 'chapters' and the selected ID needs to be used as an input for the function. To pre-filte ...

Customized validation message in Angular Formly with live data

I'm currently working with angular-formly and attempting to create a validation that checks if the user input falls within a dynamically set range of two numbers. I thought the simplest way to achieve this was by using a few variables, and while the v ...

How to retrieve the button value in HTML

One of the HTML components I am working with is a button that looks like this: <button>Add to cart</button> My goal is to retrieve the text within the button, which in this case is "Add to cart." To achieve this, I need to extract this value ...

Changing the color of a selected list element using an Angular directive

I'm currently facing an issue with my directive that is supposed to turn a list element red when clicked. It works fine, but I also want it to revert back to black when another list item is selected, so only one item stays in red color. Here is how I ...

Retrieving information from a JSON web service can easily be done using just JavaScript and jQuery

I recently downloaded a sample application from the following URL: . I am pleased to report that the part I have implemented is functioning flawlessly: <script src="scripts/jquery-1.3.2.debug.js" type="text/javascript"></script> <script src ...