-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
✨amp-form: Initialize form from URL #24671
Conversation
@ampproject/wg-ui-and-a11y I understand this isn't ready for a complete review, but any guidance you can provide on the TODO items in the summary is appreciated. |
Nice initiative developing the TODOs! Some comments:
Before spending more time on implementation, I recommend having further conversation with regards to design. Have you considered filing an intent-to-implement (I2I)? |
Hey @ampproject/wg-caching, these files were changed:
|
Thanks for the feedback @caroqliu . Regarding your fist suggestion, to move Commit efdb8f4:
|
You're right, disregard this suggestion 😄 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Saw you signed up for design review! The I2I had some discussion about content jumping--it would be useful to nail that topic down in your review.
Right. I hope that I've removed this worry by omitting checkbox and radio inputs from those that can be handled by this feature. I look forward to discussing it in design review. |
Introduce amp-form attribute `data-initialize-from-url` and form field attribute `data-allow-initialization` to selectively populate form fields from URL query parameter values on page load. Fixes #24533
const value = queryParams[key] || ''; | ||
const type = field.getAttribute('type') || 'text'; | ||
const tag = field.tagName; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about using isFieldDefault
and isFieldEmpty
methods from the src/form
to early return if the user has already interacted with the input? That way we also don't have to worry about the field value checks before setting them. This suggestion assumes that the form would not want to change/clear any user progress that has been made.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My original intention with the field value checks was to determine whether to trigger a form update event after all fields were updated. Since that feature is removed (we settled on the form being considered clean instead of dirty after populating from URL), I suppose these checks are not strictly necessary. I still feel uneasy about setting .value
when unnecessary (thinking about additional listeners that may be attached to inputs in the future), so I tend to like the field value checks.
W.r.t isFieldDefault
and isFieldEmpty
, do you think it's a significant concern that a user could modify a form before amp-form.js
loads and the constructor runs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on how the generic form dirtiness check is implemented it looks like it is really only a concern at initialization if amp-bind has modified the inputs but not if the user has. In that case I think this is fine as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I appreciate you taking the time to look through the PR closely. Thanks much for the review.
extensions/amp-form/0.1/amp-form.js
Outdated
|
||
const queryParams = parseQueryString(this.win_.location.search); | ||
Object.keys(queryParams).forEach(key => { | ||
const field = this.form_./*OK*/ querySelector(`[name="${key}"]`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use this.form_.elements[key]
here? It would also support non-descendant fields that reference the form by name and might even be a bit faster.
We don't do this consistently in existing amp-form code unfortunately.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this suggestion, but might need a little help understanding where/why check-types fails.
form.elements[key]
can return a NodeList
(for radio inputs) or an Element
. I took this into account with my refactor of the maybeInitializeFromUrl_()
function. See gist. Now, the check-types
test fails:
Type checking failed:
extensions/amp-form/0.1/amp-form.js:1297: ERROR - [JSC_TYPE_MISMATCH] actual parameter 1 of iterateCursor$$module$src$dom does not match formal parameter
found : HTMLElement
required: IArrayLike<?>
missing : [length]
mismatch: []
iterateCursor(fields, field => maybeFillField(field, key));
Does this indicate that the check-types test needs to be updated to understand that form.elements[key]
can return a NodeList
? Or is there a way that I can tell the test "hey, i know this is iterable"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, the Closure type for HTMLFormElement.elements
might be incorrect (missing the list case). Typically we typecast to workaround.
if (fields.length) {
// Typecast since Closure is missing NodeList union type in HTMLFormElement.elements.
const list = /** @type {!NodeList} */ (fields);
[...]
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds reasonable, but not allowed:
extensions/amp-form/0.1/amp-form.js:1307: ERROR - [JSC_INVALID_CAST] invalid cast - must be a subtype or supertype
from: HTMLElement
to : NodeList
const list = /** @type {!NodeList} */ (field);
^^^^^^^
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I think I have a handle on this:
// Typecast since Closure is missing NodeList union type in HTMLFormElement.elements.
const field = /** @type {(!NodeList|!Element)} */ (this.form_.elements[key]);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be resolved in 1894b76. Thanks much for the review and assistance!
extensions/amp-form/0.1/amp-form.js
Outdated
if (field.value !== value) { | ||
field.value = value; | ||
} | ||
} else if (tag === 'INPUT' && checkedInputTypes.includes(type)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Extract duplicate tag === 'INPUT'
check into an outer conditional.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be resolved in 1894b76.
extensions/amp-form/amp-form.md
Outdated
@@ -129,6 +129,30 @@ The value for `action-xhr` can be the same or a different endpoint than `action` | |||
|
|||
To learn about redirecting the user after successfully submitting the form, see the [Redirecting after a submission](#redirecting-after-a-submission) section below. | |||
|
|||
##### data-initialize-from-url | |||
|
|||
Initializes supported form fields from the URL. When this attribute is present, `<input>`, `<select>`, and `<textarea>` fields under the form can optionally be initialized from URL query parameter values. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: "Initializes input fields from the document URL's search string, where the query parameter name matches the field's name."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm ok with modifying this, but I'm not sure your suggestion is the right final text.
- This is the only place where the supported form field tags are written:
<input>
,<select>
, and<textarea>
. - From the document URL makes it sound like the URL of the AMP document matters more than
window.location
in a PWA. This is not the case. - I've been trying to avoid using the word "input" when describing form fields because
<input>
is just one of three supported form fields (or form controls, which would be more accurate but less recognizable by readers).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I just meant to supplement the first sentence. Window URL and "form field" sound fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be resolved in 1894b76.
- Prefer form.element['key'] to form.querySelector('[name=key]') - Refactor if/else to extract tag === 'INPUT' conditional - Revise summary description of data-initialize-from-url in readme
Thank you for the reviews everyone. Are there others that should be given a chance to review this before it is green-lighted? |
@choumx @honeybadgerdontcare , is this ready to submit, or do you feel we need another review. If the former, will one of you merge? |
LGTM. I'd like to let @mattwomple merge since he can. :) |
Ah, perfect. I didn't know he had merge power. I'm usually confused on this point, sorry Matt. |
* ✨amp-form: Initialize form from URL Introduce amp-form attribute `data-initialize-from-url` and form field attribute `data-allow-initialization` to selectively populate form fields from URL query parameter values on page load. Fixes ampproject#24533 * Documentation tweaks * Revisions based on self-review * Revisions from review - Prefer form.element['key'] to form.querySelector('[name=key]') - Refactor if/else to extract tag === 'INPUT' conditional - Revise summary description of data-initialize-from-url in readme
Introduce amp-form attribute
data-initialize-from-url
and form fieldattribute
data-allow-initialization
to selectively populate formfields from URL query parameter values on page load.
Fixes #24533
Fixes #24876