Skip to content
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-bind: Don't depend on template location to locate dynamic elements #8367

Merged
merged 7 commits into from
Mar 29, 2017

Conversation

kmh287
Copy link
Contributor

@kmh287 kmh287 commented Mar 24, 2017

Added a method to base-element for an element to report any elements it "owns" that are containers for dynamic contents. For instance, <div items> on an amp-live-list can have elements added/removed from its child list and so amp-live-list should return that div. The returned elements will be observed for mutations by bind. I'm not thrilled with the method name, getDynamicElements so I'm open to renaming.

I've also changed bind-impl to depend on this new method instead of the locations of templates. One caveat is forms; amp-form isn't an element, and so I've implemented custom behavior for the success/failure divs.

Fixes #8341

/to @choumx @jridgewell

if (typeof element.getDynamicElements === 'function') {
dynamicElements = element.getDynamicElements();
} else if (element.tagName === 'FORM') {
// FORM is not an amp element, so it doesn't have the getter.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could add a static method to AmpForm that returns the related instance for a given form element. Similar to what we do with Resource#forElement

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

When I tried to add the type annotation

@return {?../extensions/amp-form/0.1/amp-form.AmpForm}

on the functions in src/form.js I got the following error:

WARNING - Failed to load module "../extensions/amp-form/0.1/amp-form.js"

Any idea what's happening here?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably need to add it to the sources list for Closure type checker in build-system/tasks/compile.js.

@dreamofabear
Copy link

/to @choumx @jridgewell

* element owns that could have children added or removed dynamically.
* The array should not contain any ancestors of this element, but could
* contain this element itself.
* @return {Array<!Element>}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

!Array<!Element>. Classes are nullable by default in Closure typing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

* @return {Array<!Element>}
* @public
*/
getDynamicElements() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe getDynamicElementContainers is a bit more precise? We don't actually return every dynamic element.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good

if (typeof element.getDynamicElements === 'function') {
dynamicElements = element.getDynamicElements();
} else if (element.tagName === 'FORM') {
// FORM is not an amp element, so it doesn't have the getter.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably need to add it to the sources list for Closure type checker in build-system/tasks/compile.js.

const errorDiv =
this.form_./*OK*/querySelector(`[${FormState_.SUBMIT_ERROR}]`);
successDiv && dynamicElements.push(successDiv);
errorDiv && dynamicElements.push(errorDiv);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO it's more readable to use conditionals when your statements have side effects. || or the ternary operator are typically used for returning values without side effects.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

@@ -89,7 +89,7 @@ export class Resource {
* @return {?Resource}
*/
static forElementOptional(element) {
return /** @type {!Resource} */ (element[RESOURCE_PROP_]);
return /** @type {?Resource} */ (element[RESOURCE_PROP_]);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: ? unnecessary. Objects are nullable by default.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

} else if (element.tagName === 'FORM') {
// FORM is not an amp element, so it doesn't have the getter directly.
const form = formOrNullForElement(element);
if (form) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure we'd ever expect this to be null. May want to assert here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

@kmh287 kmh287 force-pushed the bind_dynamic_elements branch from acdc68d to d3a0f42 Compare March 27, 2017 15:01
*/

/** @const {string} */
const FORM_PROP_ = '__AMP_FORM';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it's beneficial to extend this beyond just Forms. As in, do we expect there'll be another element that has an AMP class equivalent, but doesn't use it directly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's definitely a useful pattern. My understanding is that bind doesn't support any other elements that behave this way but might in the future.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems unlikely since IIRC Dima somewhat regrets not having forms follow the same custom element pattern.

@kmh287
Copy link
Contributor Author

kmh287 commented Mar 29, 2017

@jridgewell good to go?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants