From 6dcb5478b5f724e161ceb04d50e37bb8f4b07274 Mon Sep 17 00:00:00 2001 From: Scott Newcomer Date: Wed, 13 Feb 2019 15:35:28 -0800 Subject: [PATCH] Minor improvements to docs and make `isLoaded` public (#364) --- README.md | 31 ++++---- addon/lib/infinity-model.js | 138 ++++++++++++++++++++---------------- addon/services/infinity.js | 23 ++++-- 3 files changed, 108 insertions(+), 84 deletions(-) diff --git a/README.md b/README.md index 189a9c65..0ab585ec 100644 --- a/README.md +++ b/README.md @@ -352,6 +352,8 @@ and `ember-infinity` will be set up to parse the total number of pages from a JS You can also prevent the `per_page` or `page` parameters from being sent by setting `perPageParam` or `pageParam` to `null`, respectively. Moreover, if your backend passes the total number of records instead of total pages, then as it's replacement, set the `countParam`. +Lastly, if you need some global configuration for these params, setup an extended infinity model to import in each of your routes. + ### Example JSON-API customization ```js @@ -425,7 +427,7 @@ return this.infinity.model('product', { perPage: 12, startingPage: 1, category: 'furniture' }); ``` -### Extending infinityModel +### Extending InfinityModel As of 1.0+, you can override or extend the behavior of Ember Infinity by providing a class that extends InfinityModel as a third argument to the Route#infinityModel hook. @@ -471,23 +473,16 @@ export default Route.extend({ }); ``` -* **modelPath** +## Model Public Properties -`modelPath` is optional parameter for situations when you are overriding `setupController` -or when your model is on different location than `controller.model`. +* **isLoaded** + +`isLoaded` says if the model is loaded after fetching results + +* **isError** + +`isError` says if the fetch failed -```js -model() { - return this.infinity.model('product', { - perPage: 12, - startingPage: 1, - modelPath: 'controller.products' - }); -}, -setupController(controller, model) { - controller.set('products', model); -} -``` ## Model Event Hooks @@ -638,7 +633,7 @@ Closure actions are enabled in the `1.0.0` series. hideOnInfinity=true}} ``` -Now, when the Infinity Model is fully loaded, the `infinity-loader` will hide itself. +Now, when the Infinity Model is fully loaded, the `infinity-loader` will hide itself and set `isDoneLoading` to `true`. ***Versions less than 1.0.0 called this property destroyOnInfinity*** @@ -693,7 +688,7 @@ own custom markup or styling for the loading state. When the Infinity Model loads entirely, the `reached-infinity` class is added to the component. -* **infinity-template Generator** +* **infinity-template generator** `ember generate infinity-template` diff --git a/addon/lib/infinity-model.js b/addon/lib/infinity-model.js index aaaf28c1..2c87b548 100644 --- a/addon/lib/infinity-model.js +++ b/addon/lib/infinity-model.js @@ -14,96 +14,79 @@ import { resolve } from 'rsvp'; */ export default ArrayProxy.extend(Evented, { /** - @public - @property reachedInfinity - @default null - */ - reachedInfinity: false, - - /** - @public - @property store - @default null - */ - store: null, - - /** - The supported findMethod name for - the developers Ember Data version. - Provided here for backwards compat. - @public - @property storeFindMethod - @default null - */ - storeFindMethod: null, + Increases or decreases depending on scroll direction - /** @private - @property _perPage + @property currentPage @type Integer - @default 25 + @default 0 */ - perPage: 25, + currentPage: 0, /** - Used as a marker for the page the route starts on - @private - @property firstPage - @type Integer - @default 0 + @property extraParams + @type Object + @default null */ - firstPage: 0, + extraParams: null, /** - Increases or decreases depending on scroll direction + Used as a marker for the page the route starts on @private - @property currentPage + @property firstPage @type Integer @default 0 */ - currentPage: 0, + firstPage: 0, /** - @private - @property extraParams - @type Object - @default null + @public + @property isError + @type Boolean + @default false */ - extraParams: null, + isError: false, /** - @private - @property _loadingMore + @public + @property isLoaded @type Boolean @default false */ - _loadingMore: false, + isLoaded: false, /** - @private - @property _count - @type Integer - @default 0 + Arbitrary meta copied over from + the HTTP response, to maintain the + default behavior of ember-data requests + @type objects + @default null */ - _count: 0, + meta: null, /** @private - @property _totalPages + @property _perPage @type Integer - @default 0 + @default 25 */ - _totalPages: 0, + perPage: 25, /** - @private - @property _infinityModelName - @type String + @public + @property reachedInfinity + @default false + */ + reachedInfinity: false, + + /** + @public + @property store @default null - */ - _infinityModelName: null, + */ + store: null, /** Name of the "per page" param in the @@ -138,13 +121,38 @@ export default ArrayProxy.extend(Evented, { countParam: 'meta.count', /** - Arbitrary meta copied over from - the HTTP response, to maintain the - default behavior of ember-data requests - @type objects + The supported findMethod name for + the developers Ember Data version. + Provided here for backwards compat. + @public + @property storeFindMethod @default null + */ + storeFindMethod: null, + + /** + @private + @property _count + @type Integer + @default 0 */ - meta: null, + _count: 0, + + /** + @private + @property _totalPages + @type Integer + @default 0 + */ + _totalPages: 0, + + /** + @private + @property _infinityModelName + @type String + @default null + */ + _infinityModelName: null, /** @private @@ -162,6 +170,14 @@ export default ArrayProxy.extend(Evented, { */ _increment: 1, + /** + @public + @property _loadingMore + @type Boolean + @default false + */ + _loadingMore: false, + /** simply used for previous page scrolling abilities and passed from infinity-loader component and set on infinityModel diff --git a/addon/services/infinity.js b/addon/services/infinity.js index 30cb8529..e8d1a132 100644 --- a/addon/services/infinity.js +++ b/addon/services/infinity.js @@ -4,7 +4,7 @@ import InfinityPromiseArray from 'ember-infinity/lib/infinity-promise-array'; import EmberError from '@ember/error'; import { getOwner } from '@ember/application'; import { A } from '@ember/array'; -import { isEmpty, typeOf } from '@ember/utils'; +import { typeOf } from '@ember/utils'; import { scheduleOnce } from '@ember/runloop'; import { get, set } from '@ember/object'; import { inject as service } from '@ember/service'; @@ -207,7 +207,7 @@ export default Service.extend({ } } - if (isEmpty(modelName)) { + if (!modelName) { throw new EmberError("Ember Infinity: You must pass a Model Name to infinityModel"); } @@ -315,6 +315,7 @@ export default Service.extend({ @return {Ember.RSVP.Promise} A Promise that resolves the model */ loadNextPage(infinityModel, increment = 1) { + set(infinityModel, 'isLoaded', false); set(infinityModel, '_loadingMore', true); set(this, '_previousScrollHeight', this._calculateHeight(infinityModel)); @@ -327,20 +328,29 @@ export default Service.extend({ infinityModel.incrementProperty('currentPage'); } else { if (typeof FastBoot === 'undefined') { - let viewportElem = get(infinityModel, '_scrollable') ? document.querySelector(get(infinityModel, '_scrollable')) : (document.scrollingElement || document.documentElement); + let viewportElem = + get(infinityModel, '_scrollable') + ? document.querySelector(get(infinityModel, '_scrollable')) + : (document.scrollingElement || document.documentElement); + scheduleOnce('afterRender', this, '_updateScrollTop', { infinityModel, viewportElem }); // scrolled up to load previous page infinityModel.decrementProperty('currentPage'); } } + set(infinityModel, '_firstPageLoaded', true); let canLoadMore = get(infinityModel, '_canLoadMore'); set(infinityModel, 'reachedInfinity', !canLoadMore); + if (!canLoadMore) { this._notifyInfinityModelLoaded(infinityModel); } + return infinityModel; - }).finally(() => set(infinityModel, '_loadingMore', false)); + }) + .catch(() => set(infinityModel, 'isError', true)) + .finally(() => set(infinityModel, '_loadingMore', false)); }, /** @@ -404,6 +414,8 @@ export default Service.extend({ @return {Ember.Array} returns the new objects */ _doUpdate(queryObject, infinityModel) { + set(infinityModel, 'isLoaded', true); + const totalPages = queryObject.get(get(infinityModel, 'totalPagesParam')); const count = queryObject.get(get(infinityModel, 'countParam')); set(infinityModel, '_totalPages', totalPages); @@ -418,6 +430,7 @@ export default Service.extend({ } this._notifyInfinityModelUpdated(queryObject, infinityModel); + return newObjects; }, @@ -484,7 +497,7 @@ export default Service.extend({ @method _ensureCompatibility */ _ensureCompatibility(store, storeFindMethod) { - if (isEmpty(store) || isEmpty(store[storeFindMethod])){ + if (!store || !store[storeFindMethod]){ throw new EmberError('Ember Infinity: Store is not available to infinity.model'); } }