✨Built-in see-more for amp-list#13796
Conversation
|
Sync'd w/ the group again, and the current naming proposed in the ITI looks great, so we can proceed with that version. Thanks! |
|
@ericlindley-g wrt naming (and in the spirit of bikeshedding), since we're always providing a url to the next page in the response, I think it actually makes sense to swap things back a bit: or The |
|
@cpapazian my 2 cents: I find |
There was a problem hiding this comment.
@cpapazian Thanks, this is a pretty good initial PR. Few requests also heads up that there is another biggish change to amp-list #13782 that will cause conflicts with this.
extensions/amp-list/0.1/amp-list.js
Outdated
| this.nextSrc_ = null; | ||
|
|
||
| /** @private {?float} */ | ||
| this.pageOnScrollRatio_ = null; |
There was a problem hiding this comment.
some of the variable names may need to changed after bikeshedding, so I won't nit pick on them for now.
extensions/amp-list/0.1/amp-list.js
Outdated
| * @private | ||
| */ | ||
| fetchList_() { | ||
| fetchList_(append) { |
There was a problem hiding this comment.
jsDoc for append. Since it is optional, let's name it opt_append so js doc would be {boolean=} opt_append
extensions/amp-list/0.1/amp-list.js
Outdated
| } | ||
| } else if (this.element.hasAttribute('next-page')) { | ||
| const nextExpr = this.element.getAttribute('next-page'); | ||
| this.nextSrc_ = getValueForExpr(result, nextExpr); |
There was a problem hiding this comment.
Need to do assertHttpsUrl on nextSrc_.
Ideally we do a better error message if it is not specified, so a null assert before doing assertHttpsUrl would be nice. (e.g. user().assert(this.nextSrc_, "JSON response must specify a ....")
extensions/amp-list/0.1/amp-list.js
Outdated
| this.initialSrc_ = element.getAttribute('src'); | ||
|
|
||
| /** @private {?string} */ | ||
| this.nextSrc_ = null; |
There was a problem hiding this comment.
nit: loadMoreSrc_? helps make it a bit more clear what internal variables are tied to what feature.
extensions/amp-list/0.1/amp-list.js
Outdated
| items = [items]; | ||
| } | ||
| } else if (this.element.hasAttribute('load-more')) { | ||
| const nextExpr = this.element.getAttribute( |
There was a problem hiding this comment.
I suggest expecting load-more-src as the default key. WDYT? (it is verbose, but having load-more as prefix for everything related to it creates an easier to understand API IMO)
extensions/amp-list/0.1/amp-list.js
Outdated
| }); | ||
| } | ||
|
|
||
| setupNextPage_() { |
There was a problem hiding this comment.
ditto naming: all nextPage -> loadMore
extensions/amp-list/0.1/amp-list.js
Outdated
| const overflow = this.getOverflowElement(); | ||
| const triggerOnScroll = this.element.getAttribute('load-more') === 'auto'; | ||
| if (!overflow && !triggerOnScroll) { | ||
| user().warn(TAG, |
There was a problem hiding this comment.
I will make this user.error() (also something we can prevent using validation rules)
extensions/amp-list/0.1/amp-list.js
Outdated
| overflow.onclick = null; | ||
| } | ||
|
|
||
| if (this.positionObserver_) { |
There was a problem hiding this comment.
I agree, I don't see a benefit to turning this off just for the duration of the fetch.
extensions/amp-list/0.1/amp-list.js
Outdated
| } | ||
|
|
||
| this.element.setAttribute('src', this.nextSrc_); | ||
| this.nextSrc = null; |
extensions/amp-list/0.1/amp-list.js
Outdated
| return batchFetchJsonFor(ampdoc, this.element, '.', policy); | ||
| } | ||
|
|
||
| maybeInstallPositionObserver_() { |
3f8f522 to
7b6003f
Compare
|
@aghassemi @choumx I'm just getting back to this. I fixed the naming and jsdoc over the weekend. I'm not an expert at jsdoc, so I added some explicit type annotations that may not be needed (the I also added a few tests, Other outstanding issues:
Thanks! |
|
@cpapazian I believe appending to |
0ab89dc to
d37ae0a
Compare
|
@aghassemi I think this is getting close. Just a few outstanding questions ...
thanks! |
|
@cpapazian 2- Yes, essentially any DOM manipulation that does not happen synchronously during 3A- Before writing tests, we also need to put an experiment flag around this feature (as we do with most new features in AMP). This involves adding a new entry in 3B- Regarding testing strategy, ideally existing tests just pass without modifications, then we can add a separate 4- Agreed. |
aae9082 to
9d21c27
Compare
|
Having some trouble with tests after rebasing. It looks like changing the I had initially set this up this way to avoid a race condition between the overflow logic in the parent and |
| list.mutatedAttributesCallback({'src': 'https://new.com/list.json'}); | ||
| }); | ||
| listMock.expects('toggleLoading').withExactArgs(false).once(); | ||
| listMock.expects('togglePlaceholder').withExactArgs(false).once(); |
There was a problem hiding this comment.
these listMocks were set twice: once in expectFetchAndRender and once in the test itself, but they are only called once. when rendered_() returns a promise (measurePromise), these conditions fail.
aghassemi
left a comment
There was a problem hiding this comment.
This is looking great!
css/amp.css
Outdated
| visibility: visible; | ||
| } | ||
|
|
||
| amp-list [overflow] > .i-amphtml-loader { |
There was a problem hiding this comment.
This may break existing cases where another amp-element exists inside inside overflow by hiding their loading icon.
I believe should should do two things (for this and the roles below)
1- do amp-list[load-more] as the prefix to control all this behaviour to load more.
2- use direct child selector for .i-amphtml-loader so we don't hide other loading indicators from whatever else might be in [overflow]
extensions/amp-list/0.1/amp-list.js
Outdated
| this.loadMoreSrc_ = null; | ||
|
|
||
| /** @private {?Element|undefined} */ | ||
| this.loadMoreOverflow_ = undefined; |
There was a problem hiding this comment.
we normally do null instead of undefined as default then type can be just {?Element}
extensions/amp-list/0.1/amp-list.js
Outdated
| if (this.loadMoreOverflow_) { | ||
| this.loadMoreOverflow_.classList.toggle( | ||
| 'amp-visible', !!this.loadMoreSrc_); | ||
| this.loadMoreOverflow_.onclick = () => this.loadMoreCallback_(); |
There was a problem hiding this comment.
listen(elem, 'click', cb) would be preferred (listen can be imported from event-helper.js)
extensions/amp-list/0.1/amp-list.js
Outdated
| * @private | ||
| */ | ||
| getLoadMoreLoadingElement_() { | ||
| if (this.loadMoreLoadingElement_ === undefined) { |
There was a problem hiding this comment.
oh I see that you are using the undefined vs null for lazy querying. Honestly I don't mind this happening in buildCallback (if isLoadMoreEnabled) rather than doing it lazily (buildCallback runs during prerender mode and is meant for querying things you may need later anyway)
| }); | ||
| }); | ||
|
|
||
| describe('load more', () => { |
There was a problem hiding this comment.
Another type of test to consider if these start to become too fragile/hacky, is integration tests using describes.integration. For those tests, essentially you provide some valid AMP HTML/CSS and they run as if it is a really AMP page, then you can use normal DOM API to wait for stuff and verify. So more blackbox testing closer to something you would normally do with WebDriver. Nothing can be mocked.
If you search for describes.integration you can find some good examples. The test-position-observer one for example actually scrolls the page and then asserts stuff.
526160f to
36318ad
Compare
63c1ed9 to
9a6ec8f
Compare
with auto load-more
9a6ec8f to
5b995a2
Compare
|
@cpapazian is this something you are working on actively? To reduce the stale PRs I will close this for now since there hasn't been action on this in 4 months. Please reopen this if you intend to work on this. |
|
@cpapazian @nainar I've been the hold up for this PR. |
|
Rebasing and testing this. |
8f1a0cd to
43b4d1a
Compare
|
@aghassemi can you please review this again? Merged master and fixed the overflow element issue by using a new overflow element instead of the existing one. I've tested and regression tested most of amp-list except for the SSR template changes from @alabiaga on which I have very little context. I've fixed the relevant tests, but I'm not 100% confident that I didn't break anything for SSR. @alabiaga could you review this as well? Would appreciate it if you could test the SSR functionality or give guidance on testing. =) |
|
@cathyxz this feature should just remain unsupported for SSR until we decide whether we want to enable this for AMP4Email which SSR is mainly for. So we are safe there were no changes to load more in the condition that ssr is enabled. Code changes in ssr path looks good to me. |
43b4d1a to
57003dc
Compare
|
Yup, you're absolutely correct on that end. This is not a feature for SSR, and we just need to know that it doesn't accidentally break SSR. Thanks a lot @alabiaga ! |
57003dc to
92a8a39
Compare
|
|
||
| it('should fetch and render', () => { | ||
| const items = [{title: 'Title1'}]; | ||
| const fetched = {'items': [{title: 'Title1'}]}; |
There was a problem hiding this comment.
I think this change is a function of how the test works, and does not imply a change in code logic, but a second opinion here would be helpful.
There was a problem hiding this comment.
seems fine to me. I can see how this is the result of fetch_ not taking expr anymore and the implications of it with the mocking. Also looks "more correct" than the old version.
There was a problem hiding this comment.
Thanks for the sanity check! I pulled this out to a constant so that in case we ever have to change this again, we don't have to type it 30 times in this file.
aghassemi
left a comment
There was a problem hiding this comment.
I had reviewed this before and focused on the new changes, testing and looking for regression potentials. LGTM.
extensions/amp-list/0.1/amp-list.js
Outdated
| * @private | ||
| */ | ||
| fetch_(opt_refresh = false, opt_itemsExpr) { | ||
| const expr = opt_itemsExpr || '.'; |
There was a problem hiding this comment.
I don't see any place where fetch is called with opt_itemsExpr set
There was a problem hiding this comment.
Good catch! This is possibly an error. Let me look into it.
There was a problem hiding this comment.
Okay, this is actually legacy code that was made unnecessary because we pulled out the call to getValueForExpr(data, itemsExpr) and put that in the parent in fetchList_ per:
fetch = this.fetch_(opt_refresh).then(data => {
let items = getValueForExpr(data, itemsExpr);
I think this is actually okay and we can safely remove the opt_itemsExpr parameter (which I did).
|
|
||
| it('should fetch and render', () => { | ||
| const items = [{title: 'Title1'}]; | ||
| const fetched = {'items': [{title: 'Title1'}]}; |
There was a problem hiding this comment.
seems fine to me. I can see how this is the result of fetch_ not taking expr anymore and the implications of it with the mocking. Also looks "more correct" than the old version.
extensions/amp-list/0.1/amp-list.js
Outdated
| } | ||
| this.renderItems_ = {data, resolver, rejecter}; | ||
|
|
||
| this.renderItems_ = {data, opt_append, resolver, rejecter}; |
There was a problem hiding this comment.
nitL it's not really opt at this point, just append would do.
| visibility: hidden; | ||
| } | ||
|
|
||
| amp-list[load-more] > [load-more-loading].amp-visible, |
There was a problem hiding this comment.
nitpick, alphabetize
amp-list[load-more] > [load-more-button].amp-visible,
amp-list[load-more] > [load-more-failed].amp-visible,
amp-list[load-more] > [load-more-loading].amp-visible,
here and below
* implement paging for amp-list with auto load-more * Address comments * Pull out literals to constants * Fix missed constant conversion
Implements #13575
First pass. Outstanding issues/questions:
onFocus event prevents additional overflow interactions from working reliably. see: Click events don't always fire from overflow div #13774
amp-listto indicate various loading states