I am trying to set a value for the textbox on a PayPal Giving Fund donation page and am thoroughly stumped.
Here's what I've tried:
Setting input.value
From Chrome devtools, if I run the following JavaScript:
document.getElementById('nemo_inputAmount').value = '1'
The value '1' appears in the textbox, but when I click the "Donate Now" button, the value is cleared and the form does not submit.
Sending events
I used Chrome devtools to monitor all of the events when I tabbed into the textbox, typed the value '1', and tabbed out.
Then I recreated each of those events using the code below. The value '1' does not even appear in the textbox using this approach. I have tried every combination and style of dispatching events that I can think of.
function textEvent(text) {
let textEvent = document.createEvent('TextEvent');
textEvent.initTextEvent('textInput', true, true, null, text);
return textEvent;
}
function setDonationAmount(amount) {
let amountInput = document.querySelector('input#nemo_inputAmount');
if (amountInput) {
console.log('Setting amount to', amount)
const events = [
new FocusEvent('focus', {
composed: true
}),
new Event('select', {
bubbles: true
}),
new KeyboardEvent('keydown', {
bubbles: true,
cancelable: true,
composed: true,
code: 'Digit1',
key: '1',
keyCode: 49,
which: 49
}),
new KeyboardEvent('keypress', {
bubbles: true,
cancelable: true,
composed: true,
code: 'Digit1',
key: '1',
keyCode: 49,
which: 49
}),
textEvent('1'),
new Event('input', {
bubbles: true
}),
new KeyboardEvent('keyup', {
bubbles: true,
cancelable: true,
composed: true,
code: 'Digit1',
key: '1',
keyCode: 49,
which: 49
}),
new Event('change', {
bubbles: true
}),
new FocusEvent('blur', {
composed: true
})
]
events.forEach(function(event) {
amountInput.dispatchEvent(event);
})
}
}
setDonationAmount('1');
As you can see, I'm trying to do this in pure JavaScript. I'm completely baffled why neither of the solutions above work.
Does anyone have any suggestions?
The input is part of a React component. I was able to find this by searching the source for the ID of the input (nemo_inputAmount
). This search took me to the render function for the component. Here's the relevant section of it:
_react2.default.createElement('input', {
type: 'text',
id: 'nemo_inputAmount',
className: inputBoxStyling,
onChange: this.handleInputChange,
onFocus: this.handleInputFocus,
value: this.state.inputAmount,
autoComplete: 'off',
placeholder: 'Other Amount',
required: true
}),
You can see the event handlers on it: onChange
and onFocus
. The handlers are defined earlier on. Here are the snippets:
handleInputChange: function handleInputChange(event) {
var value = event.target.value;
var input = (0, _parseAmount2.default)(value);
if (input === undefined) {
return this.invalid();
}
this.setState({
inputAmount: input
});
},
handleInputFocus: function handleInputFocus() {
this.setState({
selectedAmount: '',
radioBtnClicked: false,
clickedIndex: -1
});
},
You can see that when the input changes it changes the inputAmount
in the store to the new amount. If you look back to the createElement
function you can see the inputAmount
in the store is bound to the value
attribute of the input
.
value: this.state.inputAmount,
This means the value of the input is set when the event handler is only run when the relevant event is fired.
Setting the value
attribute programmatically does not fire the event, which is why your input kept clearing because the store wasn't updated so it was still empty.
To make it work you will need this:
const input = document.getElementById('nemo_inputAmount');
const event = new Event('input', { bubbles: true });
input.value = '1';
input.dispatchEvent(event);
This part creates a new input
event, which is the event that handleInputChange
actually reacts to – I haven't looked at the React source to confirm, this statement is based on observations and this Stack Overflow answer.
const event = new Event('input', { bubbles: true });
This part then dispatches the event.
input.dispatchEvent(event);