Updating a resource in Vue JS reactively? - javascript

I want to save form data to my backend every time the user changes the data on the page, (ideally with a timeout to wait until the user has stopped making changes and then save it).
I've thought of a few ways of handling this. I could put change events on all the fields to do so. I could also try and use a computed variable and add a call to the set method every time the object is set but this seems overly complex.
I haven't seen many examples of people doing this with Vue JS. Is there a clear way to do it? Is there a way to simply say upon the data object changing, run the following function?

Use the debounce attribute on your inputs:
https://vuejs.org/guide/forms.html#debounce
Then you can use the watch() method as Yerko suggested. The attributes in Vue won't be updated until after the timeout, at which point your watch function will fire.
If that isn't strong enough, you'd have to save the setTimeout variable and then cancel it and restart it in your watch function using clearTimeout. This isn't as complex as it sounds, just an extra variable and a deep watch function.

Related

Most efficient way to detect a variable changed and execute a callback

I would like to detect when a variable's value is updated on a server and run a callback that sends the new value to a client in order to provide a real-time feed. For example, say a server generates a random number at random intervals, but it's important for the client to be aware of a new number being generated as soon as it happens.
One simple solution is to define a custom function that you use to set your value instead of directly setting it with '=':
function setValue(val) { a = val; websocket.send(a) }
But that requires going back through already written code and replacing all instances of that variable being updated to instead use the custom function. A tedious and error-prone process but only has to be done once.
Another solution that I read about is to define a setter on the variable when initializing it, as described here.
This would only require replacing all the places where the variable is being initialized for the first time, but since it's listening hidden in the background I worry it reduces readability and someone may forget there's a callback firing each time the variable is being updated.
I don't code professionally so I'm not sure which of these solutions would be more widely accepted, or if there's a better way I should be approaching it. Also not sure of the performance hit this would cause but I'm guessing pretty negligible.
Define the custom function. Take the refactor pain now and keep it readable. Coding is 20% creation and 80% maintenance, but it always feels like 99% creation and 1% maintenance when you’re in the thick of making something new.

Undo dom changes in JS

I am writing a custom HTML editor. User can edit an entire HTML content and the changes will be updated in DOM. We have an option to undo all the changes.
Logic:
Clone an entire container before making change and apply it again.
Disadvantages:
Storing a huge variable in js memory.
And applying the changes again a dom will repaint everything.
Is there any way to achieve the same?.
Your question is very useful. I don’t know what’s the optimal way of handling this situation, but I do know that there is Command Design Pattern that could work in this case. With Command Design Pattern you can undo events that have been saved in your program. To my understanding the trick to use Command Design Pattern is that you need to have functions that do the opposite thing when you need to undo something. For example if you need to undo add function result, you need to have subtract function. For draw function you need to have clear/erase function. Here is JavaScript example.
You could try using some compression in order to reduce the amount of memory:
http://pieroxy.net/blog/pages/lz-string/index.html
http://code.google.com/p/jslzjb/
String compression in JavaScript
Use the web storage to keep the DOM history.
Imagine you want to undo the last three actions executed. You shouldn't save it in memory because you can lose information on a page refresh. And you really don't know if this action will be used to save in memory.
You can use the web storage with data compression to keep the smallest amount of data.

Coalesce / defer multiple child scope $apply calls

In my app I am receiving data via an HTTP channel that's handled in a custom way. I'm building some [data] objects from the pipe, wrap them in a scope.$new(true) and when I receive an update call childScope.$apply() to set the new properties.
This works fine for light loads, all the watchers get notified and has really been running without any issues or missed updates.
Now I'm trying to push a lot more updates and don't know if the pattern used above is the way to go. I think (though have not checked) that each call to $apply calls the digest on the root scope and I want to coalesce these on browser cycles or ~50ms intervals. Currently, whenever I receive ~100 updates on 5000 objects/scopes it kills the browser.
I saw that angular docs say each scope has an $applyAsync method but I cannot find it anywhere, this would be essentially what I am after.
Is this a bad idea and the performance is already good enough? Should I implement my own applyAsync method by using $browser.defer() or some other method?
Edit: just tested the code and indeed the $rootScope.$digest is called for each child scope $apply(). Perhaps moving this part away from Angular JS and using a listener-based approach is better, so this is also a valid answer.
In the end I used evalAsync and this seems to work as intended.
I probably need to call $digest (or $apply) every so often to make sure there are no pending scope changes but I have not seen the need to do this yet.
So my idea would be to:
call evalAsync for all the scope changes that need to happen very fast
increment a counter before the evalAsync call
set a variable with the current time inside the evalAsync function parameter and decrement the counter
on a timer (50-100ms) see if the counter is >0 and if the last evaluation time was some time ago (>50-100ms) and if yes force a digest loop.
I will not mark this as a correct answer since it does not seem like the best idea but it was the best I could come up with and it does the job as intended.

AngularJS and location.path()

I'm working on a webpage based on AngularJS and sometimes I need to change the path (the shebang if you prefer it). The thing is that sometimes $location.path("/my_path_here") works, but sometimes I need to call $scope.$apply() after calling $location.path to make the webbrowser switch to the new path.
Why is this happening?
EDIT:
Example http://pastebin.com/d1SjfCHd
Take a look at this question and Misko's answer: How does data binding work in AngularJS?
That answer explains the process in technical great detail. So, I'm gonna tell it in layman's terms.
AngularJS makes itself work by using dirty checking, there are sets of values that angular is watching. Everytime something big happens, (a click, a function call in controller), angular runs a digest cycle, comparing the watched values to see if there is any change. If there is a change, depending on the watcher, angular will take necessary action (update view, fire a callback, update route).
When you use default directives and no jquery event handling in controller, you will be fine.
However, if you do, you need to know that you are NOT in the angular's digest cycle. Which means the watchers will not fire until a digest occurs.
You need to know when are you updating a variable that is being watched. Mostly it is custom DOM event (or jquery events). When it is the case, you need to let angular know that something is changed and it needs to re-check what happened (ie. update watchers).
This is by doing scope.$apply() after you have changed something.
Bear in mind that you cannot run an $apply() if you are already in the angular's digest cycle. It will throw an error like $digest already in progress.

Is it okay to use data-attributes to store Javascript 'state'

I often use data-attributes to store configuration that I can't semantically markup so that the JS will behave in a certain way for those elements. Now this is fine for pages where the server renders them (dutifully filling out the data-attributes).
However, I've seen examples where the javascript writes data-attributes to save bits of data it may need later. For example, posting some data to the server. If it fails to send then storing the data in a data-attribute and providing a retry button. When the retry button is clicked it finds the appropriate data-attribute and tries again.
To me this feels dirty and expensive as I have to delve into the DOM to then dig this bit of data out, but it's also very easy for me to do.
I can see 2 alternative approaches:
One would be to either take advantage of the scoping of an anonymous Javascript function to keep a handle on the original bit of data, although this may not be possible and could perhaps lead to too much "magic".
Two, keep an object lying around that keeps a track of these things. Instead of asking the DOM for the contents of a certain data-attribute I just query my object.
I guess my assumptions are that the DOM should not be used to store arbitrary bits of state, and instead we should use simpler objects that have a single purpose. On top of that I assume that accessing the DOM is more expensive than a simpler, but specific object to keep track of things.
What do other people think with regards to, performance, clarity and ease of execution?
Your assumptions are very good! Although it's allowed and perfectly valid, it's not a good practice to store data in the DOM. Sure, it's fine if you only have one input field, but, but as the application grows, you end up with a jumbled mess of data everywhere...and as you mentioned, the DOM is SLOW.
The bigger the app, the more essential it is to separate your interests:
DOM Events -> trigger JS functions -> access Data (JS object, JS API, or AJAX API) -> process results (API call or DOM Change)
I'm a big fan of creating an API to access JS data, so you can also trigger new events upon add, delete, get, change.

Categories

Resources