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

Closes ciena-frost/ember-frost-list#121 #122

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ Detailed API and example usage can be found in the sample application in tests/d
| `Sub Attribute` | `properties` | `array` | | Array of sortable attributes. eg. [{"label: "foo", "value": "bar"}], This is an attribute on frost-sort component.|
| `Sub Attribute` | `onSort` | `action closure` | | callback functions user provided to handle sorting. This is an attribute on frost-sort component.|
| `Attribute` | `itemKey` | `string` | | Optional: With itemKey set, item.get(itemKey) will be used for comparision, Else the default item === item comparison used. |
| `Attribute` | `isLoading` | `boolean` | | Optional: When `true` the `frost-loading` component is displayed in place of either the *Infinite Scroll* or *Finite / pagination* lists. |
| `Attribute` | `loadingType` | `string` | | Optional: The `frost-loading` loading effect. See [frost-loading](https://github.com/ciena-frost/ember-frost-core/blob/master/docs/frost-loading.md) |


### Infinite scroll
Expand Down Expand Up @@ -92,7 +94,7 @@ In these cases pagination may optionally be used
}}
```

The onChange action will receive the `page` being requested, which can be combined with
The onChange action will receive the `page` being requested, which can be combined with
the `itemsPerPage` to make an API request and provide the new items for the list

```
Expand Down
3 changes: 3 additions & 0 deletions addon/components/frost-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ export default Component.extend({
PropTypes.EmberObject,
PropTypes.object
])),
isLoading: PropTypes.bool,
itemExpansion: PropTypes.EmberComponent,
loadingType: PropTypes.string,
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd like this to be change to a component closure rather than relying directly on frost-loading

So the interface would be

{{frost-list
  loading=(component 'frost-loading')
  ...
}}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

scrollTop: PropTypes.number,
selectedItems: PropTypes.arrayOf(PropTypes.oneOfType([
PropTypes.EmberObject,
Expand Down Expand Up @@ -77,6 +79,7 @@ export default Component.extend({
getDefaultProps () {
return {
// Options - general
isLoading: false,
scrollTop: 0,

// Smoke and mirrors options
Expand Down
81 changes: 44 additions & 37 deletions addon/templates/components/frost-list-content-container.hbs
Original file line number Diff line number Diff line change
@@ -1,44 +1,51 @@
{{! Template for the frost-list-content-container component }}

{{#if pagination}}
{{#frost-scroll
hook=(concat hookPrefix '-scroll')
{{#if isLoading}}
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this be satisfied using the inverse block of the #each?

{{frost-loading
hook=(concat hookPrefix '-loading')
type=loadingType
}}
{{#each items as |model index|}}
{{yield model index}}
{{else}}
{{yield to="inverse"}}
{{/each}}
{{/frost-scroll}}
{{else}}
{{#vertical-collection
alwaysRemeasure=true
alwaysUseDefaultHeight=alwaysUseDefaultHeight
bufferSize=bufferSize
content=items
defaultHeight=defaultHeight
firstReached=onLoadPrevious
lastReached=onLoadNext
scrollPosition=scrollTop
useContentProxy=false
{{#if pagination}}
{{#frost-scroll
hook=(concat hookPrefix '-scroll')
}}
{{#each items as |model index|}}
{{yield model index}}
{{else}}
{{yield to="inverse"}}
{{/each}}
{{/frost-scroll}}
{{else}}
{{#vertical-collection
alwaysRemeasure=true
alwaysUseDefaultHeight=alwaysUseDefaultHeight
bufferSize=bufferSize
content=items
defaultHeight=defaultHeight
firstReached=onLoadPrevious
lastReached=onLoadNext
scrollPosition=scrollTop
useContentProxy=false

key='@identity'
resizeDebounce=64
firstVisibleChanged=null
lastVisibleChanged=null
didMountCollection=null
idForFirstItem=null
renderFromLast=false
renderAllInitially=false
shouldRender=true
minimumMovement=15
containerSelector=null
containerHeight=null
key='@identity'
resizeDebounce=64
firstVisibleChanged=null
lastVisibleChanged=null
didMountCollection=null
idForFirstItem=null
renderFromLast=false
renderAllInitially=false
shouldRender=true
minimumMovement=15
containerSelector=null
containerHeight=null

as |model index|
}}
{{yield model index}}
{{else}}
{{yield to="inverse"}}
{{/vertical-collection}}
as |model index|
}}
{{yield model index}}
{{else}}
{{yield to="inverse"}}
{{/vertical-collection}}
{{/if}}
{{/if}}
2 changes: 2 additions & 0 deletions addon/templates/components/frost-list.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
bufferSize=bufferSize
defaultHeight=defaultHeight
hook=(concat hookPrefix '-contentContainer')
isLoading=isLoading
items=_items
loadingType=loadingType
pagination=pagination
scrollTop=scrollTop
onLoadNext=onLoadNext
Expand Down
3 changes: 3 additions & 0 deletions tests/dummy/app/pods/application/template.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
<div class='frost-modal-demo-selector-title'>
Cookbook
{{#link-to 'simple'}}Basic{{/link-to}}
{{#link-to 'simple-loading'}}Basic - Loading{{/link-to}}
Copy link
Contributor

Choose a reason for hiding this comment

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

You can put the examples directly into the existing routes - no need to do a duplicate explicitly to demonstrate the loading

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@sglanzer The demo app currently uses small viewports for the existing demos so that users don't have to scroll as far to experience the infinite paging experience, not as many records need to be created for the paging screens, etc. Because this viewport is not very tall (due to it's overflow being hidden) the loading indicator does not show in its entirety. In the new routes I created to demo the loading support I have increased the viewport size. If you have any recommendations on how to remedy this or approach it differently I am interested. In either case I am in need of direction on how you wish me to proceed.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, I don't think we made a conscious decision about the demo height initially, if you can increase it and satisfy your case of showing the loader I'm fine with that. I believe it's easier to use the demo for a reference if you don't have to go through multiple demos to get the data you need (less is more).

Not a big deal though, so if you see value in keeping both I won't block it

{{#link-to 'infinite'}}Infinite{{/link-to}}
{{#link-to 'infinite-loading'}}Infinite - Loading{{/link-to}}
{{#link-to 'paged'}}Paged{{/link-to}}
{{#link-to 'paged-loading'}}Paged - Loading{{/link-to}}
</div>
{{/frost-scroll}}
</div>
Expand Down
81 changes: 81 additions & 0 deletions tests/dummy/app/pods/infinite-loading/controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/**
* TODO
*/

import Ember from 'ember'
const {A, Controller, inject, isEmpty} = Ember
import computed, {readOnly} from 'ember-computed-decorators'
import {sort} from 'ember-frost-sort'

export default Controller.extend({

// == Dependencies ==========================================================

notifications: inject.service('notification-messages'),

// == Properties ============================================================

expandedItems: A([]),
isLoading: false,
itemsPerPage: 100,
lastPage: 0,
selectedItems: A([]),
sortOrder: A(['id']),
sortingProperties: [
{label: 'Id', value: 'id'},
{label: 'Label', value: 'label'}
],

// == Computed Properties ===================================================

@readOnly
@computed('model.[]', 'sortOrder.[]')
items (model, sortOrder) {
if (isEmpty(model)) {
return []
}
return sort(model, sortOrder) // Client side sorting
},

// == Functions =============================================================

fetchPage (page) {
this.get('notifications').success(`Fetching page ${page}`, {
autoClear: true,
clearDuration: 2000
})
this.store.query('list-item', {
pageSize: this.get('itemsPerPage'),
start: (page * this.get('itemsPerPage'))
}).then(() => {
this.set('model', this.store.peekAll('list-item'))
})
},

// == Lifecycle Hooks =======================================================

// == Actions ===============================================================

actions: {
onExpansionChange (expandedItems) {
this.get('expandedItems').setObjects(expandedItems)
},

onLoadNext (page) {
this.set('lastPage', this.get('lastPage') + 1)
this.fetchPage(this.get('lastPage'))
},

onSelectionChange (selectedItems) {
this.get('selectedItems').setObjects(selectedItems)
},

onSortingChange (sortOrder) {
this.get('sortOrder').setObjects(sortOrder)
},

onClick () {
this.send('refreshModel')
}
}
})
27 changes: 27 additions & 0 deletions tests/dummy/app/pods/infinite-loading/route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Ember from 'ember'
const {Route, run: {later}} = Ember

export default Route.extend({
isModelRefreshing: false,

setupController (controller, model) {
this._super(controller, model)

if (this.isModelRefreshing) {
later(() => {
controller.fetchPage(0)
this.controller.set('isLoading', false)
}, 2500)
} else {
controller.fetchPage(0)
}
},

actions: {
refreshModel () {
this.set('isModelRefreshing', true)
this.controller.set('isLoading', true)
this.setupController(this.controller, this.modelFor('list-item'))
}
}
})
25 changes: 25 additions & 0 deletions tests/dummy/app/pods/infinite-loading/template.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{{frost-list
class='demo-loading'
hook='demo'
isLoading=isLoading
item=(component 'list-item')
itemExpansion=(component 'list-item-expansion')
items=items
expandedItems=expandedItems
selectedItems=selectedItems
onExpansionChange=(action 'onExpansionChange')
onLoadNext=(action 'onLoadNext')
onSelectionChange=(action 'onSelectionChange')
sorting=(component 'frost-sort'
sortOrder=sortOrder
sortingProperties=sortingProperties
onChange=(action 'onSortingChange')
)
}}

{{frost-button
hook='whatever'
onClick=(action 'onClick')
priority='primary'
text='Refresh model'
}}
2 changes: 1 addition & 1 deletion tests/dummy/app/pods/infinite/template.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@
sortingProperties=sortingProperties
onChange=(action 'onSortingChange')
)
}}
}}
82 changes: 82 additions & 0 deletions tests/dummy/app/pods/paged-loading/controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* TODO
*/

import Ember from 'ember'
const {A, Controller, isEmpty} = Ember
import computed, {readOnly} from 'ember-computed-decorators'
import {sort} from 'ember-frost-sort'

export default Controller.extend({

// == Dependencies ==========================================================

// == Properties ============================================================

expandedItems: A([]),
isLoading: false,
itemsPerPage: 10,
page: 0,
scrollTop: 0,
selectedItems: A([]),
sortOrder: A(['id']),
sortingProperties: [
{label: 'Id', value: 'id'},
{label: 'Label', value: 'label'}
],
totalItems: 100, // Typically extracted from meta on the request

// == Computed Properties ===================================================

@readOnly
@computed('model.[]', 'sortOrder.[]')
items (model, sortOrder) {
if (isEmpty(model)) {
return []
}
return sort(model, sortOrder) // Client side sorting
},

// == Functions =============================================================

fetchPage (page) {
this.store.unloadAll('list-item')
this.store.query('list-item', {
pageSize: this.get('itemsPerPage'),
start: (page * this.get('itemsPerPage'))
}).then(() => {
this.set('model', this.store.peekAll('list-item'))
this.set('page', page)
})
},

// == Lifecycle Hooks =======================================================

// == Actions ===============================================================

actions: {
onExpansionChange (expandedItems) {
this.get('expandedItems').setObjects(expandedItems)
},

onPaginationChange (page) {
this.setProperties({
page,
scrollTop: 0
})
this.fetchPage(page)
},

onSelectionChange (selectedItems) {
this.get('selectedItems').setObjects(selectedItems)
},

onSortingChange (sortOrder) {
this.get('sortOrder').setObjects(sortOrder)
},

onClick () {
this.send('refreshModel')
}
}
})
Loading