Instant update backend with Knockoutjs - javascript

I am trying to create a web page with form that once user change any field, the validation and update commit immediately rather than letting user to click on submit button. I am using Knockout.js and mapping plugin. I know I can achieve this by creating a computed field for each original fields, but this kind of work is tedius and dumb, is there good practice to create a general listener to listen on any changes in any fields and update backend respectively?

In order to subscribe to any change you could use ko.toJS() method. Actually it allows to walk through object graph and unwrap observables. As your probably know when you use ko.computed it subscribes to all reads of observables fields and re-evaluate on every change. So if you use code like this:
ko.computed(function() {
ko.toJS(viewModel);
// update data on server
});
Also you should pay attention that this piece of code will update data on server right after initialization. It could be easily avoided. Please checkout this example: http://jsfiddle.net/UAxXa/embedded/result/
Also I think you might want to send only changed data to server. You could incorporate ko.editbales plugin ( https://github.com/romanych/ko.editables ) and some KO under-hood knowledge. Please checkout this sample: http://jsfiddle.net/romanych/RKn5k/
I hope it could help you.

You've got several options but if you want a single listener, one good way is to use the same code I used to create a change tracker. It simply listens for the observable changes. Its about 19 lines of code. You can grab this and instead of using it for change tracking, just wire in a method that saves the changes when they occur.
NuGet http://nuget.org/packages/Knockout.ChangeTracker
Codeplex http://kochangetracker.codeplex.com/
To Setup change tracking, add this tracker property to your view model:
viewModel.tracker = new ChangeTracker(viewModel);
Hook these into your view to determine when changes occur:
viewModel.tracker().somethingHasChanged();
Hook this into your view model when you want to reset state in functions (ex: load, save):
viewModel.tracker().markCurrentStateAsClean;
Optionally, you can pass your own hashFunction for state tracking, too.

Related

How to track user changes in Vue.js?

I have a website built with Vue.js and I need to do an audit and, optionally, implement cancel functionality for this website so I'm looking for my options/best practices.
Let's say I have an Items array defined in data() so on created () I'm doing an Ajax request and pushing data into this array of items.
Now user loads this page and does his job which for me means he changed a few objects. Let's say each Item is a Customer object and it has First name, Last name, DOB and a IsActive boolean field.
I would like to give this user an option to revert specific item to the original state without reloading anything and when he hits Save I would like to know what was changed (so I can log this information)
Here are my ideas so far:
keep a copy of the original list of Items and do a diff later to see what was changed or use it to restore objects as needed
try to utilize watch() and keep track of changes. Perhaps, I can even store this information in the object itself.
leave a UI as is and on the backend (while saving or updating) re-read object from the DB and do the job there since it is the only truly secure way of doing an audit anyway.
What's the best way to track changes and/or implement both cancel and audit?
Maybe there is a Vue-way of doing this which I'm missing, because I just switched to Vue from a different framework.
Thank you! Any help appreciated!

Three questions about Store in Flux

Following the flux concepts we can get the next assertions for which I couldn't find explanations.
Every store will receive every action.
Why? My suggestion: since a store contents some business-logic we have to provide it with all possible changes and data so the store can decide what to do with them on its own.
The data in a store must only be mutated by responding to an action.
Why? My suggestion: the reason is violation of unidirectional data-flow in case of not responding to an action.
Every time a store's data changes it must emit a "change" event.
Why? I can't get this point.
Flux is just a way of managing the data flow of your application, so it is up to the developer to make sure this actually happens. But I'll try to paint a picture of why these concepts are a part of Flux.
Every store will receive every action.
If you have only one dispatcher in your application, every store will listen to actions dispatched through that dispatcher. It is up to you whether or not the store should act on the action dispatched, but to be able to react on it the store has to know of it.
Not all actions should lead to changes in a store, though. But the dispatcher simply doesn't care, because it won't know anything about the store implementation. It's just telling all stores that this action happened, do what you want with it or go on with your life without caring.
The data in a store must only be mutated by responding to an action.
You're right that doing it with a different approach could be violation of unidirectional data-flow. Doing things this way makes sure all parts of your application has the correct state based on the actions that happens.
By not doing it this way you would let go of one of the flux strengths. Update your store based on dispatched actions, and other stores will also be aware that the action happened, and thereby react to it if they want to. If you update the store directly you will end up having no clear picture of what parts of your application that are altering the state of your store.
Every time a store's data changes it must emit a "change" event.
People often describe the stores in a flux application as the source of truth. When a store's data changes, the basis for the visualization of your data changes. You want to be confident that if my store holds a certain value, this is what my application uses as it's data.
It's related to the first quote here. The store doesn't know if a listener depends on it's data. By emitting a change, it will let all listeners know that hey, I changed. Make sure you have all my latest changes. If you don't emit change, the listener could end up displaying something based on old data.
All of these statements are related to the same thing: If an action happens in your application, don't make any assumptions about which part of your application that wants to know the details of it. Make sure everyone can act on it, if they want to.

Partial state changes for Vaadin's AbstractJavascriptComponent

I'm implementing a JavaScript-based Vaadin component that will need to show and update a relatively large data set. I'm doing this by extending AbstractJavaScriptComponent.
I'm trying to keep the JS side as "dumb" as possible, delegating user interactions to the server using RPC, and which updates the shared state. Then the JS connector wrapper's onStateChange function is called with the new state, which causes the DOM to be updated accordingly.
I have 2 problems:
I don't want to transfer the whole data set each time a small part gets updated.
I don't want to entirely rebuild the UI each time either.
I can solve the second problem by keeping the previous state and comparing parts of it to find out what changed and only make the necessary DOM changes.
But that still leaves the first problem.
Do I have to stop using Vaadin's shared state mechanism and instead only use RPC for communicating the changes to the state?
Update:
I've been doing some testing, and it certainly appears that Vaadin's shared state mechanism is horrible in terms of efficiency:
Whenever the component calls getState() in order to update some property in the state object (or even without updating anything), the whole state object is transferred. The only way to avoid this, as far as I can see, is to not use the shared state mechanism and instead use RPC calls to communicate specific state changes to client.
There are some issues with the RPC approach that will need to be resolved, for example: if you change a value multiple times within a single request/response cycle, you don't want to make the RPC call multiple times. Instead, you want only the last value to be sent just like the shared state mechanism only sends the final state in the response. You can keep dirty flags for each part of the state that you want to send separately (or just keep a copy of the previous state and compare), but then you need to somehow trigger the RPC call at the end of the request handling. How can this be done?
Any ideas on this are welcome!
Update 2:
Vaadin 8 fixes the root issue: it sends only the changed state properties. Also, it doesn't call onStateChange() on the JS connector anymore when only doing an RPC call (and not changing any state).
OP is correct in stating that shared state synchronisation is inefficient for AbstractJavaScriptComponent-based components. The entire state object is serialised and made available to the Javascript connector's onStateChange method whenever the connector is marked as dirty. Other non-javascript components handle state updates more intelligently by only sending changes. The exact place in the code where this happens is line 97 in com.vaadin.server.LegacyCommunicationManager.java
boolean supportsDiffState = !JavaScriptConnectorState.class
.isAssignableFrom(stateType);
I'm not sure why state update is handled differently for AbstractJavaScriptComponent-based components. Maybe it's to simplify the javascript connector and remove the need to assemble a complete state object from deltas. It would be great if this could be addressed in a future version.
As you suggest, you could dispense with JavaScriptComponentState completely and rely on server->client RPC for updates. Keep dirty flags in you server-side component or compare old state and new state by any mechanism you want.
To coalesce the changes and send only one RPC call for each change, you could override beforeClientResponse(boolean initial) in your server-side component. This is called just before sending a response to the client and is your chance to add a set of RPC calls to update the client-side component.
Alternatively, you could override encodeState where you have free-reign to send exactly whatever JSON you like to the client. You could choose to add a list of changes to the base JSON object returned by super.encodeSate. Your javascript connector could interpret as appropriate in its onStateChange method.
Edited to add: calling getState() in your server-side component will mark the connector as dirty. If you want to get state without marking it as dirty then use getState(false) instead.
Following our discussion about this, I've created a drop-in replacement for AbstractJavaScriptComponent that transmits state deltas and includes some extra enhancements. It's in the very early stages but should be useful.
https://github.com/emuanalytics/vaadin-enhancedjavascript
The solution is deceptively simple: basically re-enabling state difference calculation by bypassing this line of code in com.vaadin.server.LegacyCommunicationManager.java:
boolean supportsDiffState = !JavaScriptConnectorState.class
.isAssignableFrom(stateType);
The implementation of the solution is complicated by the fact that the Vaadin classes are not easily extended so I've had to copy and re-implement 6 classes.
Vaadin's shared state works exactly like you want out of the box: when a component is added to the DOM first time, the whole shared state is transferred from server to client, so that it's possible to display the component. After that, only changes are transferred. For example, one changes the caption of a visible component by calling component.setCaption("new caption"), Vaadin only transfers that new caption text to client and "merges" that to the client-side shared state instance of the component.

Changes-aware list in angularjs

I'm doing some work on existing angularjs code, and I have something of that sort: I have a list of objects on the client side, which I transfer via a put request to a server side.
The existing code simply takes the list of objects in the $scope and puts it in the json as is.
I want to implement a mechanism where only the objects that have been changed since some event would be sent.
I can do that hardcodedly and save another list of objects and clear it when I submit the changes, but I want something cleaner - f.e, a Changes aware list,
Then, I could do something in the sort of list.changedObjects.
I couldn't seem to find anything like that from basic research, so I was hoping you guys would know something about it.
I feel this is a use-case of Observer pattern. https://github.com/melanke/Watch.JS has an lib/example to observe changes in javascript object. Then you can trigger an event in Angular to do your job accordingly
http://jsfiddle.net/2zT4C/23/
$watch helps to listen for $scope changes
AngularJS can then check the value returned against the value the watch function returned the last time. That way AngularJS can determine if the value has changed.
$scope.$watch('list', $scope.sendNewList, true);
it will will update innerHtml if new value of object is not equal to old value of object i.e if it has been changed.
For detailed info check this - $watch() or $watch
AngularJS watch array of objects for data change

ajax update site from form submit

As mentioned in this question How can I check for live updates without using setInterval/timeout?
I am aware of websockets, but im interested in maybe a more simplistic solution, could I effectively just let php update a key value pair file and have all pages update accordingly only if a value has changed?
eg. a bidding site where instead of polling for 100 or more items I only update the whole application when someone has essentially placed a bid , making it a one way flow
place bid->process form->update database->refresh all instances of said bid currently open in other windows - hence the file that will store the info and maybe two way binding setup via angular template , or will caching be a issue?
how else do I update the views but all based on the action of someone placing a bid(submitting a form)?
Any ideas as to this approach?
You should use websockets...
if you are new to socket.IO you can use some backend as a service like firebase, this should be really easy to implement.

Categories