More powerful than you'd ever imagined
@jeffreybiles
www.emberscreencasts.com
@jeffreybiles
www.emberscreencasts.com
In which the audience acquires a basic understanding of query-params
through boring examples
export default Ember.Controller.extend(
Ember.SortableMixin, {
queryParams: ['sortProperties',
'sortAscending'],
sortProperties: ['createdAt'],
sortAscending: true
}
);
{{#each post in arrangedContent}}
<tr>
<td>{{post.title}}</td>
//repeated for each column
</tr>
{{/each}}
<thead>
<tr>
// was simply `<td>title</td>` before
{{sortable-header
title='Title'
sortProperty='title'
selectedSorts=sortProperties
isAscending=sortAscending}}
//repeated for each column
</tr>
</thead>
//sortable-header.js
tagName: 'th',
downArrow: '▼',
upArrow: '▲',
isSelectedSort: Ember.computed('selectedSorts', 'sortProperty', function(){
return this.get('selectedSorts')[0] === this.get('sortProperty');
}),
upArrowHighlighted: Ember.computed('isSelectedSort', 'isAscending', function(){
return this.get("isSelectedSort") && this.get('isAscending');
}),
downArrowHighlighted: Ember.computed('isSelectedSort', 'isAscending', function(){
return this.get("isSelectedSort") && !this.get('isAscending');
}),
sortProperties: Ember.computed('sortProperty', function(){
return [this.get('sortProperty')]
})
//sortable-header.hbs
{{title}}
{{#link-to 'posts' (query-params sortProperties=sortProperties sortAscending=true) tagName="button"}}
<div class="{{if upArrowHighlighted 'gold'}}">
{{{upArrow}}}
</div>
{{/link-to}}
{{#link-to 'posts' (query-params sortProperties=sortProperties sortAscending=false) tagName="button"}}
<div class="{{if downArrowHighlighted 'gold'}}">
{{{downArrow}}}
</div>
{{/link-to}}
{{#link-to 'posts'
(query-params
sortProperties=sortProperties
sortAscending=true)
tagName="button"}}
<div class="{{if upArrowHighlighted 'gold'}}">
{{{upArrow}}}
</div>
{{/link-to}}
{{#link-to 'posts'
(query-params
sortProperties=sortProperties
sortAscending=true)
tagName="button"}}
{{#link-to 'posts'
(query-params
sortProperties=sortProperties
sortAscending=true)
tagName="button"}}
queryParams: ['param1', 'param2', ...]
{{#link-to 'routeName'
(query-params param1=foo param2=bar)
}}
//controllers/posts.js
queryParams: ['sortProperties',
'sortAscending',
'pageNumber',
'pageSize']
pageNumber: 0,
pageSize: 10,
possiblePageSizes: [10, 25, 50, 100],
//controllers/posts.js
pages: Ember.computed('arrangedContent', 'pageSize', 'sortAscending', function(){
var pages = [];
var arrangedContent = this.get('arrangedContent').copy();
while (arrangedContent.length > 0) {
pages.push(arrangedContent.splice(0, this.get('pageSize')));
}
return pages;
}),
paginatedContent: Ember.computed('pages', 'pageNumber', function(){
return this.get('pages')[this.get('pageNumber')]
}),
//posts.hbs
{{#each post in paginatedContent}}
<tr>
<td>{{post.title}}</td>
//repeated for each column
</tr>
{{/each}}
//posts.hbs
{{#each pages as |page index|}}
<span class="{{if (is-equal index pageNumber) 'bold big-text'}}">
{{#link-to 'posts' (query-params pageNumber=index) tagName="button"}}
{{add-one index}}
{{/link-to}}
</span>
{{/each}}
//posts.hbs
<button {{action 'previousPage'}}>Previous Page</button>
{{#each pages as |page index|}}
<span class="{{if (is-equal index pageNumber) 'bold big-text'}}">
{{#link-to 'posts' (query-params pageNumber=index) tagName="button"}}
{{add-one index}}
{{/link-to}}
</span>
{{/each}}
<button {{action 'nextPage'}}>Next Page</button>
//controllers/posts.js
actions: {
previousPage: function(){
if(this.get('pageNumber') > 0){
this.set('pageNumber', this.get('pageNumber') - 1);
}
},
//nextPage is similar
}
//controllers/posts.hbs
<span class="option-name">Page size</span>
{{#each possiblePageSizes as |newSize|}}
<button {{action 'changePageSize' newSize}}
class="{{if (is-equal newSize pageSize) 'bold big-text'}}">
{{newSize}}
</button>
{{/each}}
//controllers/posts.js
actions: {
//other actions
changePageSize: function(newPageSize){
var currentOffset = this.get('pageSize') * this.get('pageNumber');
var newPageNumber = Math.floor(currentOffset / newPageSize);
this.set('pageNumber', newPageNumber);
this.set('pageSize', newPageSize)
},
}
@jeffreybiles
www.emberscreencasts.com
In which the audience acquires more understanding of query-params
through awesome examples
//controllers/posts.js
availableColumns: [
{'title': 'Title', 'property': 'title', 'display': 'plain'},
{'title': 'Author', 'property': 'author', 'display': 'plain'},
{'title': 'Updated', 'property': 'updatedAt', 'display': 'date'},
{'title': 'Created', 'property': 'createdAt', 'display': 'date'}
],
columns: Ember.computed.alias('availableColumns') //changing soon
//posts.hbs
{{#each column in columns}}
{{sortable-header
title=column.title
sortProperty=column.property
selectedSorts=sortProperties
isAscending=sortAscending}}
{{/each}}
...
{{#each column in columns}}
<td>
{{table-block-output column=column item=post}}
</td>
{{/each}}
//table-block-output.js
export default Ember.Component.extend({
isPlain: Ember.computed.equal('column.display', 'plain'),
isDate: Ember.computed.equal('column.display', 'date'),
itemProperty: Ember.computed('column.property', 'item', function(){
return this.get('item').get(this.get('column.property'))
})
});
//table-block-output.hbs
{{#if isPlain}}
{{truncate-text itemProperty 50}}
{{else if isDate}}
{{format-date itemProperty}}
{{/if}}
//controllers/posts.js
queryParams: ['sortProperties', 'sortAscending',
'pageNumber', 'pageSize', 'columnsUsed'],
availableColumns: [{property: 'author', ...}, ...], //same as before
columnsUsed: [
'title',
'author',
'updatedAt'
],
columns: Ember.computed('availableColumns', 'columnsUsed.@each', function(){
var controller = this;
return this.get('columnsUsed').map(function(columnProperty){
return controller.get('availableColumns').filter(function(column){
return columnProperty == column.property
})[0]
})
}),
//posts.hbs
{{#each availableColumns as |column|}}
{{list-item-toggle displayedList=columnsUsed displayableItem=column}}
{{/each}}
//list-item-toggle.hbs
<button {{action 'toggle'}} class={{if isDisplayed 'bold big-text' 'text-muted'}}>
{{displayableItem.title}}
</button>
//list-item-toggle.js
tagName: 'span',
isDisplayed: Ember.computed('displayableItem.property', 'displayedList.@each', function(){
var displayedList = this.get('displayedList')
return displayedList.contains(this.get('displayableItem.property'))
}),
actions: {
toggle: function(){
if(this.get('isDisplayed')){
this.get('displayedList').removeObject(this.get('displayableItem.property'))
} else {
this.get('displayedList').addObject(this.get('displayableItem.property'))
}
}
}
//controllers/posts.js
actions: {
...
moveLeft: function(property){
var columns = this.get('columnsUsed')
var index = columns.indexOf(property)
columns.removeObject(property)
if(index == 0){
columns.insertAt(index, property)
} else {
columns.insertAt(index - 1, property)
}
},
//moveRight is similar
}
//sortable-header.hbs
<button {{action 'moveLeft'}} class="pull-left">{{show-brackets '<'}}</button>
...
<button {{action 'moveRight'}} class="pull-right">{{show-brackets '>'}}</button>
//action passed up through component
//in posts.hbs and sortable-header.js
//but it's boring code
@jeffreybiles
www.emberscreencasts.com
In which the audience's mind is blown
@jeffreybiles
www.emberscreencasts.com
In which the audience's mind is blown
and they contemplate changing the world
again
Charts taken from http://blogging.alastair.is/charts-can-say-anything-you-want-them-to/
Charts taken from http://blogging.alastair.is/charts-can-say-anything-you-want-them-to/
if (chart.conclusion == user.preconceptions){
return "So insightful!"
} else {
return "Such bullshit"
}
@jeffreybiles
www.emberscreencasts.com