New techniques in VueJS 3: managing value changes without using watchers

I am currently working on coding a table with pagination components and I have implemented multiple v-models along with the use of watch on these variables to fetch data. Whenever the perPage value is updated, I need to reset the page value to 1. However, this results in the watch method being triggered twice - once for perPage and then again for page.

Is there a way to update a variable without triggering the watch at that specific moment?

Below is my current code snippet:


<script setup lang="ts">

const sort = ref(route.query.sort || 'created_at')
const filters = ref(route.query.filters || {})
const page = ref(route.query.page ? parseInt(route.query.page.toString()) : 1)
const perPage = ref(route.query.per_page ? parseInt(route.query.per_page.toString()) : 10)

watch([sort, filters, page, perPage], ([oldSort, oldFilters, oldPage, oldPerPage], [newSort, newFilters, newPage, newPerPage]) => {
  if (oldPerPage !== newPerPage)
    page.value = 1

  fetchItems()

  router.push({
    query: {
      ...route.query,
      sort: sort.value,
      // filters: filters.value,
      page: page.value,
      per_page: perPage.value,
    },
  })
})

async function fetchItems() {
  items.value = await userApi.list({
    filters: toRaw(filters.value),
    sort: sort.value,
    page: page.value,
    perPage: perPage.value,
  })
}
</script>

<template>
    <CTable
      :pagination-enabled="true"
      v-model:sort="sort"
      v-model:page="page"
      v-model:per-page="perPage"
      :total-items="items.meta.total"
      :total-pages="items.meta.last_page"
    />
</template>

The only workaround I found is to add a return statement when resetting the page value:

watch(..., () => {
  if (oldPerPage !== newPerPage) {
    page.value = 1
    return
  }

  fetchItems()

  ...
})

This solution works for my case, but I would prefer a method to update the variable without triggering the watch method for other situations as well.

Thank you!

Answer №1

Set up a new observer for the perPage parameter:

watch([sort, filters, page, perPage], ([oldSort, oldFilters, oldPage, oldPerPage], [newSort, newFilters, newPage, newPerPage]) => {

  fetchItems()

  router.push({
    query: {
      ...route.query,
      sort: sort.value,
      // filters: filters.value,
      page: page.value,
      per_page: perPage.value,
    },
  })
})

watch(perPage, (newPerPage,oldPerPage ) => {
  if (oldPerPage !== newPerPage)
    page.value = 1
})

To improve efficiency and reduce conflicts, it's advisable to monitor each property separately. For the initial observer, consider using watchEffect instead since you don't require the comparison between old and new values:

watchEffect(() => {
  fetchItems()
  router.push({
      query: {
        ...route.query,
        sort: sort.value,
        // filters: filters.value,
        page: page.value,
        per_page: perPage.value,
      },
  })
})

Answer №2

Thanks to everyone for your help! I finally discovered the solution I was searching for by utilizing VueUse - watchIgnorable:

const { stop, ignoreUpdates } = watchIgnorable(page, (value) => {
  fetchItems()
})

watch(perPage, (newPerPage, oldPerPage) => {
  if (newPerPage !== oldPerPage) {
    ignoreUpdates(() => {
      page.value = 1
    })
  }

  fetchItems()
})

Answer №3

When using v-model to change the state, it's important to keep an eye on it with a watcher.

To prevent multiple triggers of the watcher, additional conditions should be implemented as shown in the previous code snippet. However, it is crucial not to skip an update when the page is already set to 1, as this won't lead to any extra updates:

  if (oldPerPage !== newPerPage) {
    page.value = 1

    if (newPage !== 1)
      return
  }

If there are other factors at play aside from perPage that may trigger the watcher causing asynchronous side effects (such as fetchItems), it's best to debounce it to ensure it only runs when necessary. Here is an example:

watch(perPage, () => {
  page.value = 1
});

watch([sort, filters, page, perPage], debounce(() => {
  fetchItems()
  ...
}, 100));

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

Steps to restrict input in a text area to only backspace and cursor movements

I'm in search of a jQuery function that restricts movements to only arrow keys and backspace within a textarea. However, there seems to be an issue with the arrow key movements not functioning correctly. function moveArrow(e){ if(e.which >= 3 ...

Setting up GameClosure on a Windows machine

Is it possible to install GameClosure on Windows? The installation guide mentions that only OSX is officially supported, but there have been reports of success running it on Linux and Windows. However, the process for doing this is not well-documented. A ...

Capturing the value of a child element using an Angular directive

When I include scope: {finishcallback: "&"} in my directive, the binding of values with $scope.minutes = 1 to ng-bind="minutes" stops working. I am currently working on creating a countdown timer using Angular directives. However, I am facin ...

The animation came to a halt after a brief period

Here is the code I wrote. When the button is clicked, the 3 containers should start flashing indefinitely, but they stop after a while. I can't figure out why. Any ideas? <!DOCTYPE html> <html> <head> <title></title> & ...

There seems to be a lack of definition for Angular within the angular

Currently, I am in the process of developing an Angular application. The modules I have created contain services and controllers that are all working as intended. Recently, I added angular-animate to my list of scripts, which are loaded from a cshtml file ...

When a radiobutton is clicked, a jQuery call to a PHP function triggers an AJAX request which results in a JavaScript function becoming unrefer

Currently, I have a situation where two radio buttons are representing different products. When one of them is clicked, the goal is to update the price displayed on the website based on the selected product. Everything seems to be working fine when using t ...

The process of uploading images to a server by making an AJAX call to a PHP file

I have an input file and I want to upload the attached file to the server with a message saying "uploaded successfully" when I click on the upload button. However, I am getting a "file not sent" message. (The uploaded images need to be saved in the uploa ...

Is there a performance benefit to using node.js over client-side JavaScript in comparison to Chrome/V8?

Currently, I am working on a client-side javascript application for image manipulation. However, some of the operations are running quite slowly in the browser, taking about 2-3 seconds to complete. To address this issue, I am considering implementing a s ...

Exploring ways to query a mapped array in React Native

Struggling to search a mapped list in react native? While using a Flatlist would be easier, this task is currently causing me major frustration. If anyone has any insights or solutions, please share them! Here's a snippet of the code: import React ...

Troubles arise when trying to convert a schema using Normalizr

Is there a way to efficiently convert a JSON array containing travel expenses into a format that allows for easy retrieval of expenses by travelExpenseId and tripId? [ { "travelExpenseId":11, "tripId":2, "paymentPurpose":"some payment ...

What is the best way to specify a function parameter as the `QUnit` type using TypeScript in conjunction with QUnit?

In my project, which is partially written in TypeScript and licensed under MIT, I am utilizing QUnit. I have some TypeScript functions that require QUnit as a parameter, and I would like to define their types based on its interface from the typings. For e ...

What could be causing my AJAX code to fail in retrieving information from an API?

Hey everyone, I'm new here and hoping to get some help with an issue I'm facing. I've written a code to fetch data from an API and display it on my HTML page, but for some reason the AJAX code isn't working. There's nothing showing ...

What is the best way to iterate over a multidimensional array in Angular/Ionic?

I've been struggling to find a solution tailored for looping in a .ts file instead of HTML. My main objective is to iterate over an array and compare the entered value with the keys. If there's a match, I want to retrieve the values stored withi ...

Creating dynamic canvas elements with images using HTML and JavaScript

Currently, I am working on a unique project involving a canvas filled with dynamic moving balls. This project is an extension or inspired by the codepen project located at: https://codepen.io/zetyler/pen/LergVR. The basic concept of this project remains t ...

React is producing a collection of <td>'s

My React code is very straightforward and it runs smoothly: function Columns(){ return ( <React.Fragment> <li>Hello</li> <li>World</li> </React.Fragment> ); } function Example(){ ...

Define default array values in Mongoose schemas using Node.js

My model definition includes: appFeatures: [{ name: String, param : [{ name : String, value : String }] }] I am looking to assign a default value to appFeatures, such as: name: 'feature', para ...

Re-rendering components using arrow functions

Using an arrow function, I have implemented a feature to toggle a div and show/hide a button based on the div's visibility. toggleDeliveryDiv = () => { document.getElementById('btn_collapse_delivery').click(); this.s ...

What is causing the continuous appearance of null in the console log?

As part of my JavaScript code, I am creating an input element that will be inserted into a div with the id "scripts" in the HTML. Initially, I add a value to this input field using JavaScript, and later I try to retrieve this value in another JavaScript fu ...

Instructions for transforming rows into columns in JSON format

Looking to convert an array of JSON objects into a format where rows become columns and the values at the side become column values, similar to the crosstab function in PostgreSQL. The JSON data looks something like this: {"marketcode":"01","size":"8,5", ...

AngularJS login form with JSON data

I am currently learning Angular and focusing on the login form implementation. The specific model I am working with can be found in this PLNKR. There are two challenges that I am struggling to resolve. Issue 1: I'm trying to figure out how to tur ...