1

When I run this code (which is part of a chrome extension) it should just fill out the information for the #username and #password inputs of a specific website, in this case https://wordplay.com/login.

However, the value of the input element does not really change. Visually, there is text in the input field, but when I inspect the element and look at the value attribute it remains blank. That is until I type something in the box manually. If I type something in the input then the value updates fine.

Also, when I try submitting the form they both change back to empty.

const username = document.getElementById('username');
username.value = request.username;

const password = document.getElementById('password');
password.value = request.password; 
Danziger
  • 19,628
  • 4
  • 53
  • 83

1 Answers1

3

Why Is This Happening?

That might have to do with whatever framework that site is using.

In this case, https://wordplay.com/login is using React and those fields are controlled inputs, so the logic on that form doesn't rely on the input's DOM value, but on the one in React's state. From the docs:

Controlled Components

In HTML, form elements such as <input>, <textarea>, and <select> typically maintain their own state and update it based on user input. In React, mutable state is typically kept in the state property of components, and only updated with setState().

We can combine the two by making the React state be the “single source of truth”. Then the React component that renders a form also controls what happens in that form on subsequent user input. An input form element whose value is controlled by React in this way is called a “controlled component”.

✨ Document.execCommand():

So, the easiest way to do that might be to focus the inputs and then use Document.execCommand():

const username = document.getElementById('username');
const password = document.getElementById('password');

username.focus();
document.execCommand('insertText', false, 'Alice');

password.focus();
document.execCommand('insertText', false, 'password');
<input id="username" />
<input id="password" />

⚒️ Manually Dispatching Events:

Otherwise, you might try manually dispatching a change, input and/or blur event using the Event() constructor in those fields after you change their value. In this case, only input works.

Also, note Event()'s second optional argument contains a field, bubbles, that is false by default. You need that one to be true. Otherwise, this won't work, as React is listening for events on the document.

Additionally, you might need to use Element.setAttribute() too, as that will update the value attribute on the DOM (the initial value on the field), while element.value will update the current value (and so the display value). In this case, though, it's not needed. For more on this see What is the difference between properties and attributes in HTML?.

This approach might have some timing issues you might need to handle using setTimeout when updating multiple inputs, so if the first one works, I'd go for that one instead.

const username = document.getElementById('username');

// This updates the value displayed on the input, but not the DOM (you can do that with setAttribute,
// but it's not needed here):
username.value = 'Bob';

// Dispatch an "input" event. In some cases, "change" would also work:
username.dispatchEvent(new Event('input', { bubbles: true }));

// It looks like only one field will be updated if both events are dispatched
// straight away, so you could use a setTimeout here:

setTimeout(() => {
  const password = document.getElementById('password');
  password.value = 'password';
  password.dispatchEvent(new Event('input', { bubbles: true }));    
});
<input id="username" />
<input id="password" />
Danziger
  • 19,628
  • 4
  • 53
  • 83
  • I tried this and the same thing happened. I have to manually update the field before the value changes. – Brandon Kirincich Jan 03 '20 at 12:53
  • @BrandonKirincich Can you share the site where you are testing the extension? – Danziger Jan 03 '20 at 13:25
  • @BrandonKirincich Sorry, forgot to mention the `bubbles` option. That's `false` by default, so you need to set it to `true` for React to receive those events. – Danziger Jan 03 '20 at 15:37
  • 1
    This worked perfectly for the username input but not for the password. When I check the value of the password field it is correct however it doesn't show visually and when I press the login button manually or via the extension then it says it is invalid. Thank you so much for helping me. – Brandon Kirincich Jan 03 '20 at 16:01
  • @BrandonKirincich I think it's just a timing issue, try with the updated code, just wrapping the password field in a `setTimeout`. – Danziger Jan 03 '20 at 16:04
  • @BrandonKirincich I think I've found a better solution with `execCommand()`. ☝️ – Danziger Jan 03 '20 at 16:18