Debounced submission of form in onChange - redux-form

I have a field like this:
{
render() {
return <Field type="text" onChange={this.debouncedSubmit} />
....
}
debouncedSubmit = debounce(this.props.submit, 500)
}
export default reduxForm({
form: 'week-form',
onSubmit: async function() {
await new Promise(resolve => setTimeout(resolve, 5000))
}
})
This works fine except for one issue. We see here submission takes 5 seconds. We see also that deboucne is 500ms. So lets say user typed in two characters, then waited 1sec. The debounce triggered and submission is in process. Now while submission is in process, lets say user inputs another character. This triggers debounce, and at time 1.5sec it triggers submit. However because submission is currently in progress, this one gets missed.
Is there a pattern with redux-form to not miss this?
What I tried:
I thought to "reinitialize" the form, but "do not update field value if current field value differs from value it is about to initialize with", and then in componentDidUpdate if form is dirty, then I would trigger submit again. However Im running into a problem:
I set in reduxForm:
enableReinitialize: true,
keepDirtyOnReinitialize: true,
And I initialize the form with data. However after the first submission, for some reason it overwrites the field and I lose the "third character" i put in while submission was going on. Why is this happening when I set keepDirtyOnReinitialize to true.

So actually my logic above works. I created a demo here on the web and it works perfectly:
https://codesandbox.io/s/37z9217q6
The problem is I am doing this in react-native on Android and there is a bug there that is causing this problem for me, I filed the bug - https://github.com/facebook/react-native/issues/19085

Related

How to get DetailsList/Selection component on React Fabric UI to work with ReactHooks?

I'm having issue getting the React Fabric UI DetailsList to work with React Hooks. It renders, but the selection part does not. Whenever, you select a row, I expect the count of the selection to be updated. However, i'm not seeing that. It looks like the selection component items never get updated even thou the UI shows it being selected. I'm also seeing the onSelectionChange being triggered when you select a row. Now sure if its because i'm using react hooks or what
I took the provided class example which works:
[Codepen]https://codepen.io/pen/?&editable=true (Example)
Same as the original but stripped down
[Codepen]https://codepen.io/darewreckk/pen/NQRWEd?editors=1111
converted it to a react hook component. I would expect the same thing, but i'm not and can't figure out what's different.
Modified Example with Hooks
[Codepen]https://codepen.io/darewreckk/pen/GVjRNb?editors=1111
Any advice appreciated,
Thanks,
Derek
The selection count is stored on the Selection object that you are creating. You could log it out like so:
const _selection = new Selection({
onSelectionChanged: () => {
console.log('Selected count:' + _selection.count);
}
});
You can set the value of selectionCount and selectionDetails whenever onSelectionChanged is called:
const _selection = new Selection({
onSelectionChanged: () => {
setSelectionCount(_selection.count);
setSelectionDetails(`${_selection.count} items selected`)
}
});
As a side note: If you want selectionDetails to update when selectionCount updates, you can use the useEffect hook:
React.useEffect(() => {
setSelectionDetails(`${selectionCount} items selected`);
}, [selectionCount]);
The above effect will run whenever selectionCount updates, and so in turn update selectionDetails.

Prevent multiple form submission on hitting enter twice

When I'm trying to submit form, then I accidentally hit enter twice on submit button. In that case my form is submitted twice. Can any one advice me how I can handle this.
Here is the output which I needed:-
form values must be submitted once
even if user hit enter twice..
You can achieve this by jquery. Below is the same code.
In this example it will disable submit button for 2 seconds. After 2 seconds button will enable again. You can modify this according to your requirement.
$('form').submit(function(){
$(this).find(':submit').attr( 'disabled','disabled' );
//the rest of your code
setTimeout(() => {
$(this).find(':submit').attr( 'disabled',false );
}, 2000)
});
Try this and let me know if you have any concern.
You can add unique property on a certain column on your database or validate it through Laravel Request
You can also do it with disable the submit button for multiple clicks.
$(function() {
$('button').click(function() {
$($(this)).prop('disabled', true);
});
});
You can achieve this by jquery
In this example, it will disable submit button for 2 seconds. After 2 seconds button will enable again. You can modify this according to your requirement.
$('form').submit(function(){
$(this).find(':submit').attr( 'disabled','disabled' );
//the rest of your code
setTimeout(() => {
$(this).find(':submit').attr( 'disabled',false );
}, 2000)
});
Let me know if it works.

Angular2 - DOM events lost on re-render when using Redux and uni-directional data flow

I wasn't sure of the best way to word the title, but hopefully the description will clarify.
I have an Angular2 component that uses Redux for state management.
That component uses *ngFor to render an array of small inputs with buttons like this. The "state" is something like this...
// glossing over how I'd get this from the Redux store,
// but assume we have an Immutable.js List of values, like this...
let items = Immutable.fromJS([{value: foo}, {value: bar}, /*...etc*/ })
And the template renders that like so...
<input *ngFor="let item of items, let i = index"
type="text"
value="item.get('value')"
(blur)="onBlur($event, i)">
<button (click)="onClick($event)">Add New Input</button>
When an input is focused and edited, then focus is moved away, the onBlur($event) callback is called, a redux action (ie: "UPDATE_VALUE") is dispatched with the new value.
onBlur($event, index) {
let newValue = $event.target.value;
this.ngRedux.dispatch({
type: "UPDATE_VALUE",
value: {index, newValue}
});
}
And the reducer updates the value (using Immutable.js):
case "UPDATE_VALUE": {
let index = getIndex(action.value.index); // <-- just a helper function to get the index of the current value.
return state.updateIn(["values", index], value => action.value.newValue);
}
The state is updated, so the component is re-rendered with the updated value.
When the button next to the input is clicked, the onClick($event) callback is fired which dispatches a different redux action (ie: "ADD_VALUE"), updates the state, and the component is re-rendered with a new blank input & button.
The problem comes up when the input is focused (editing) and the user clicks the button. The user intended to click the button, but because they happened to be focused on the field, it doesn't behave as expected. The (blur) event is fired first, so the input onBlur callback is fired, redux action dispatched, state updated, component re-rendered. BUT, the button (click) is lost, so the new input isn't created.
Question:
Is there a way to keep track of the click event and trigger the second action after the re-render? Or, is there a way to somehow chain the redux actions so they happen in sequence before the re-render?
Side-note - I've tried changing the (click) event to use (mousedown) which is triggered before the (blur) but that caused Angular (in devMode) to complain that the #inputs to the components were changed after being checked (the state changed during the change detection cycle). I didn't dig into that too deeply yet though. I'm hoping to find a solution using click and blur as is.
Thanks!

How to notify the FormWizard plugin about skipped steps (not shown) to avoid losing data?

I have the formwizard plugin integrated with an 8-step form; The problem is, whenever I'm trying to edit information and then jump to an specific step in the form so basically jumping ignoring previous steps, all steps that were not shown (cuz I jumped them) are not sent!!! :( so losing all data already populated into those fields.
For example,
$("#demoForm").formwizard("show","Step4");
This will trigger Step4, but if I am at Step1 and havent seen Step2 and Step3, and jump right into Step4.. then the plugin ignores those Step2 and 3 so when my processing script will process empty data. I would like to know how to notify the plugin that there are steps that were now shown in order to submit those values.
Note: I'm not using Ajax for this.
This is where the settings are:
$("#demoForm").formwizard({
formPluginEnabled: false,
validationEnabled : true,
disableUIStyles : true,
textNext: "Siguiente",
textBack: "Anterior",
textSubmit: "Guardar",
focusFirstInput : true
},
{
messages: { email: "Invalid email"}
},
{
// form plugin settings
}
);
Jumping to an specific step like this...
$('#gotostep').change(function(){
if($(this).val() != '')
{
$("#demoForm").formwizard("show",$(this).val());
return false;
}
});
..same thing happens if I try to force a submit changes on any steps using: $("#demoForm").submit(); :/
Thanks in advanced!
Frank
I guess it should suffice to enable all disabled input elements in the form when the form is submitted? Do this e.g. by hooking up a callback to the forms submit event like this:
$(function(){
var form = $("#demoForm");
form.submit(function(){
form.find(":input:disabled").removeAttr("disabled");
})})
Hope this helps.

Using jQuery Autocomplete with Validator onBlur timing problem

Here's my problem, I have an input element in a form that is implementing jQuery.Autocomplete and jQuery.validate, all working normally except when I click an element in the autocomplete list to select it.
What happens is validation occurs before the autocomplete sets its value. Because validation occurs on onBlur, and you just clicked an item in the autocomplete list, blur fires and validation occurs a split second before the input is filled with its new value.
I wouldn't mind a double-validation if it was client side, but I happen to be executing an expensive remote ajax validation on this field, so I'd really like to solve this the right way.
My first thought is to proxy all validation onBlur events through a function that times out 10ms later, essentially flip flopping the event order. But, I think, that means tearing into the jQuery.Validate.js code, which I'd rather not do.
Any ideas?
I was able to get this working but perhaps not as elegantly as I would have liked. Ideally I would have liked to call the prototype or defaults version of of onfocusout from within a timeout closure but I wasn't able to figure out how to reference it from that scope.
The approach that I took instead was to override the onfocusout method with its code copy/pasted into a timeout closure. The only other tweak was to change references from this to _this to work within the different scope of the timeout closure.
$("#aspnetForm").validate({
success: "valid",
onkeyup: "false",
onfocusout:
function(element) {
//Delay validation so autocomplete can fill field.
var _this = this;
setTimeout(function() {
if (!_this.checkable(element) && (element.name in _this.submitted || !_this.optional(element)))
_this.element(element);
_this = null;
}, 250);
}
});
Feel free to post improvements.

Resources