Vue watcher restore old values? - vue.js

im using this component to make a list of sortable items.
https://sortablejs.github.io/Vue.Draggable/#/simple
I have one array with the items in my view component data.
Then i use an v-for to pain the list, one row for each item in my array.
So everytime i move one item, the array of items gets sorted and change the order of the array items, thats the behaviour of this component.
But i have to make a post call to an api to save the new order fot the list.
So i defined a watcher over the array of items, and everytime it gets sorted by the draggable component, i make the request to the api if the array order has changed.
The problem comes when this request fails, i want to restore the old values in the view, so i dont have one order in the view an another different stored in database.
Inside my watcher i have prevValues and newValues, that i use to compare and check if there is any change in the items order, then make the request, and then, if the request fails, restore the datavalue with the prevValues array.
The problem is that could get to an infinite loop, because when i restore the old values, the watcher over the original array is triggered again, make the request, fails, restore values and so on.
Is there any way to restore old values passed to a watcher without triggering the watcher again?
Thank you

It would be more reliable to react to drag events to trigger your API calls, rather than watching the data. That way your code only does work in response to user action.
Alternatively, stash a copy of the original array and use something like deep-equal to compare it to the latest value to determine if changed before making a call.

Related

VUE 3 JS Save value if object changes

I'm new to VUE but not to programming. The project is to convert an older server-built website to VUE and I'm looking to find the most efficient method to save data.
When a form (page) is loaded I pull the data from our server in a JSON object which is nicely converted to a JS object. Its big -- hundred or so properties.
I'm currently storing the object in a PINIA store as a reactive object, applying the object values directly to form inputs using v-model and everything works, is reactive, and once completed my object has all the necessary information to update (patch) the document.
What I'd like to do is send to the server JUSt the object that was changed and its new value.
For example: assume the object has many fields -- I'll just provide a few here
event:{user:'scott',pass:'12345',startDate:'11/01/2023',endDate:'11/01/2024'.....}
The page has tabs and in each tab we pull a subset of the complete object (fetched and stored).
Therefore, store.event object has one change -- startDate --
I'd like to build a function that watches the entire (100+ object), fire if any field has changed, then save it somewhere without an individual watch or computed property for each 100+ objects.
Suggestions?
I tried using watch with multiple elements -- it did fire but I was unable to determine which element (object) changed.
Watch(() => [store.event.contractdate,store.event.contractduedate],(cv,ov){.. do something}

Vue component loses input when asynchronous call updates another property

I have a component that has an <input> with a :value set to a certain property. The component has another property unrelated to this input, which can get updated asynchronously (AJAX call). Whenever you're typing inside the input and the asynchronous call finishes, updating the other property, your typed input is reset.
To recreate this problem I've created a jsfiddle using a setInterval to simulate the async call and increment the other passed property. Try typing in the input, it will get reset every second. If you're quick enough, you can tab out and cause the #change to trigger the actual update.
The question is: why is the update to the other prop invalidating/rerendering the component and how can I work around this?
Note that v-model="person.name" is not a valid solution here - I need to know the old and new value, which is why I'm using a manual :value/#change combo.
Edit: The updateName method also really only needs to be triggered when the user leaves the input field. This is because the code run inside it is relatively CPU intensive and only needs to run when the user is done with the input and leaves it (in my actual code, not the jsfiddle).
Edit2: Is there some way to not let it re-render the entire component, but only the relevant pieces?
Because the parent component is changing a property of the child component, it has to re-render (parts of) the child component. Since you are using #change, instead of #input, your changes are not saved yet to the reactive variable person.name, it only works if you click tab quick enough. One solution would be to change #change to #input (which better resembles v-model):
https://jsfiddle.net/mf67xq1e/
Another (better) option is to use v-model and use a watcher to retrieve both the old and the new value:
watch: {
// whenever person.name changes, this function will run
"person.name": function (newName, oldName) {
console.log("newName:", newName);
console.log("newName:", oldName);
}
}
https://jsfiddle.net/mf67xq1e/1/
EDIT:
As you mentioned you only need to trigger something when you blur/leave the input field, seperate the reactivity of the variable and the triggering of your other method (e.g. updating some other variable or something), in two seperate variables:
https://jsfiddle.net/ta9cgnx0/
EDIT 2: Cleaner option with v-model and a seperate call for your other trigger on blur:
https://jsfiddle.net/ay1g63u8/

update store element adds row in grid without removing the old version

I would like updates to the dstore appearing in the dgrid without having to call refresh.
do you know why the grid does not remove the old row?
my records has no id property but Ive setup the idProperty correctly.
My grid is expected to receive multiple updates and calling to refresh would probably have performance implications.
So if you can point a way to throttle refresh events it can also help.
Thanks,
Nimrod.
dgrid listens to change events if the store provides them. dstore's Trackable mixin adds change events to the store. Try mixing in Trackable to your store and you should see dgrid automatically render in response to any of the store's add/put/remove calls.

Weird reactivity issue with arrays in Vue.js

I'm trying to debug a rather weird problem I've run into with a Vue.js application. Unfortunately it's way too complex to be able to isolate some code showing the problem, so I'm hoping that a clear description might be enough to enable people to give me some pointers as to where to look.
I have a component called ItemSelector, which has a 'targetList' prop of type Array. On a form, I use this component 3 times, passing a different array for each instance. Each array consists of sale item objects, and the ItemSelector component displays these items and allows the user to add, edit and delete them. All works just fine, except for one thing. The objects contain a property called 'subtotal'. If in one instance of my ItemSelector component I edit one of the item objects and clear the value of the 'subtotal' property, the item with the same index in the other instances of ItemSelector also has the 'subtotal' property cleared! That is, if I edit the second item in one of the ItemSelector instances, clearing the subtotal property, the second item, if present, in the other ItemSelector instances is also cleared. However, if I instead change the value to a different number, this has no effect on other instances of the component. It's only clearing the value which does it.
Does this make any sense at all to anyone? I cannot see how a change in one array could affect other arrays at all.

Insert newly added Item at the top of an EnhancedGrid in Dojo

I have an EnhancedGrid which is bound to a dynamic Store. I am using lazy loading, so as I scroll down, more data will be fetched and bound.
I also have an "add new Item" functionality. This will open a pop-up where the user creates the new Item in a form, and on Save the item is added to the store. with dojo.data.ObjectStore.newItem() and dojo.data.ObjectStore.save().
My problem, after using those two functions, the item is automatically appended to the grid at the bottom, which is kinda of a nuisance. The user will have to scroll down to find it, which would trigger the lazy loading.
After following the code around, I found out that newItem() calls the dojox.grid.DataGrid._addItem(item, index, noUpdate) function.
I managed to overwrite it so when I am adding a new item, the _addItem function will be called with index 0. But that does not work since it was just replacing the first row with the new one instead of prepending it.
Is there any other way to look at this? is it possible to actually do it?