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
Dispatch VALUE_CHANGE on amp-bind
value changes
#22840
Dispatch VALUE_CHANGE on amp-bind
value changes
#22840
Conversation
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.
General ideas LG.
Commented on future use cases and naming, feel free to plus Will for answers.
This comment has been minimized.
This comment has been minimized.
extensions/amp-bind/0.1/bind-impl.js
Outdated
*/ | ||
function doesPropertyAffectFormValue(tagName, property) { | ||
switch (property) { | ||
case 'disabled': |
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.
Should we consider [hidden] attribute as well in this case then? Feel free to left a TODO and resolve in another PR.
Note that hidden
attribute can be mutated on the ancestry of a form 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.
Ugh right. So there are:
disabled
for form fields and fieldsetshidden
for essentially all elementstype
for<input>
I am still leaning towards using a mutation observer on the form for all of the above, and leave AmpEvents.FORM_VALUE_CHANGE
as close to the native InputEvent
as possible. (It's also semantically cleaner as Will mentioned)
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.
Yup that also works.
I'll left it to Will to make the call.
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.
SGTM
This introduces a new `AmpEvents.VALUE_CHANGE` event. It is dispatched when `amp-bind` mutates form input values, specifically: `<input [value]>`, `<textarea [text]>`, `<input [checked]>`, and `<option [selected]>`. A custom event is chosen over a mutation observer, because binding `[text]` on `textarea` does not change the DOM (and it's expected), thus a mutation observer won't pick up the change. The same applies to `input` elements, when we eventually have two separate bindings for `[value]` and `[defaultValue]`.
d764b59
to
d356e4d
Compare
extensions/amp-bind/0.1/bind-impl.js
Outdated
|
||
if (isPropertyAFormValue(element.tagName, property)) { | ||
const dispatchAt = | ||
element.tagName === 'OPTION' ? element.closest('SELECT') : element; |
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.
Out of curiosity, why is this necessary? Also use closestAncestorElementBySelector()
helper in dom.js in case Element.closest
is not available.
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.
Thanks! The native InputEvent
is also dispatched at the parent <select>
when the selected <option>
changes. I think it makes sense, since it is the value of the <select>
element that is changed.
I just added a comment explaining this!
extensions/amp-bind/0.1/bind-impl.js
Outdated
if (dispatchAt) { | ||
dispatchAmpFormValueChangeEvent(this.localWin_, dispatchAt); | ||
} | ||
} |
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: Can we keep everything in a single class function? It would also save you from checking tagName
twice.
this.dispatchFormValueChangeEventIfNecessary_(element, property);
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.
To only check tagName
once, the switch
gets a bit intense with the nested if
s and early returns: https://gist.github.com/xrav3nz/6fd7b048080aedbaa1e87c418b4193e4 Are you okay with this?
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.
True, probably better as is. Speaking of switch statements, a lookup map might be more readable.
Optional:
/** @const {!Object<string, !Array<string>>} */
const FORM_VALUE_PROPERTIES = {
'INPUT': ['checked', 'value'],
'OPTION': ['selected'],
'TEXTAREA': ['text'],
};
dispatchFormValueChangeEventIfNecessary_(element, property) {
const props = FORM_VALUE_PROPERTIES[element.tagName];
if (props && props.includes(property)) {
...
}
}
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 think I'm gonna to leave it as is Updated! Thanks again for the reviews! 💪
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.
LGTM
Nice work, thanks for contributing. |
* Dispatch VALUE_CHANGE on `amp-bind` value changes This introduces a new `AmpEvents.VALUE_CHANGE` event. It is dispatched when `amp-bind` mutates form input values, specifically: `<input [value]>`, `<textarea [text]>`, `<input [checked]>`, and `<option [selected]>`. A custom event is chosen over a mutation observer, because binding `[text]` on `textarea` does not change the DOM (and it's expected), thus a mutation observer won't pick up the change. The same applies to `input` elements, when we eventually have two separate bindings for `[value]` and `[defaultValue]`. * more elaborate test names * rename event to FORM_VALUE_CHANGE * dispatch event at <select> when <option> changes * extract FORM_VALUE_CHANGE_EVENT_ARGUMENTS in test * dont use `closest` & move everything into a helper * refactor to use a lookup map instead * avoid a linear `includes` search
This introduces a new
AmpEvents.VALUE_CHANGE
event. It is dispatchedwhen
amp-bind
mutates form input values, specifically:<input [value]>
,<textarea [text]>
,<input [checked]>
, and<option [selected]>
.A custom event is chosen over a mutation observer, because binding
[text]
ontextarea
does not change the DOM (and it's expected), thusa mutation observer won't pick up the change. The same applies to
input
elements, when we eventually have two separate bindings for[value]
and[defaultValue]
.Part of #22534.
/cc @GoTcWang @choumx thanks!