Query Params
More powerful than you'd ever imagined
@jeffreybiles
www.emberscreencasts.com
Part 1: Basic
@jeffreybiles
www.emberscreencasts.com
In which the audience acquires a basic understanding of query-params
through boring examples
Sorting
Before
export default Ember.Controller.extend(
Ember.SortableMixin, {
queryParams: ['sortProperties',
'sortAscending'],
sortProperties: ['createdAt'],
sortAscending: true
}
);
Sorting Basics
{{#each post in arrangedContent}}
<tr>
<td>{{post.title}}</td>
//repeated for each column
</tr>
{{/each}}
content -> arrangedContent
<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 changes the url
Query Params are part of the url
Therefore, link-to can change query-params
{{#link-to 'posts'
(query-params
sortProperties=sortProperties
sortAscending=true)
tagName="button"}}
Sorting
More sorting resources
- SortableMixin docs
- EmberScreencasts.com
Syntax overview
in controller
in handlebars
queryParams: ['param1', 'param2', ...]
{{#link-to 'routeName'
(query-params param1=foo param2=bar)
}}
Pagination
//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)
},
}
Pagination
More Pagination Resources
- EmberScreencasts.com
- 24: Handlebars Subexpressions (coming soon)
- 25: Client-side Pagination (coming soon)
Part 2: Awesome
@jeffreybiles
www.emberscreencasts.com
In which the audience acquires more understanding of query-params
through awesome examples
Dynamic Columns
First, abstract "columns"
//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}}
Filter based on columnsUsed
availableColumns
columns
columnsUsed
(query-parameter)
//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]
})
}),
Change columnsUsed
//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'))
}
}
}
Dynamic Columns
Rearrange Columns
//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
Rearrange Columns
Demo
Brainstorming
Part 3: Fun
@jeffreybiles
www.emberscreencasts.com
In which the audience's mind is blown
Level Design
Stages of Level Design
What about url size?
2048kb/68kb = 30.1
Part 4: Dangerous
@jeffreybiles
www.emberscreencasts.com
In which the audience's mind is blown
and they contemplate changing the world
again
Charts
Charts help us understand data
Charts "help" us "understand" data
Charts taken from http://blogging.alastair.is/charts-can-say-anything-you-want-them-to/
Charts twist data to fit the prejudices of the presenter
Charts taken from http://blogging.alastair.is/charts-can-say-anything-you-want-them-to/
Current Method of Investigating a Chart
- Locate and retrieve data source
- Make the data source fit into your favorite data-visualization software.
- You have a favorite, right?
- Recreate the data segmentation and data elimination (outliers, etc.) and adjustments for confounding factors that the original chart used.
- Information about this is usually hidden in a research paper somewhere. Hope you have access to a university library.
(theoretical)
Current Method of Investigating a Chart
- Locate and retrieve data source
- Make the data source fit into your favorite data-visualization software.
- You have a favorite, right?
- Recreate the data segmentation and data elimination (outliers, etc.) and adjustments for confounding factors that the original chart used.
- Information about this is usually hidden in a research paper somewhere. Hope you have access to a university library.
- Recreate the graph type and settings of the original visualization.
- Bonus points: coloring and font
- Investigate
- Export into a sharable format
- Share
- Preferably detailing how your graph is different and why it's better
- But you're probably too tired by now
(theoretical)
Current Method of Investigating a Chart
if (chart.conclusion == user.preconceptions){
return "So insightful!"
} else {
return "Such bullshit"
}
(actual)
Proposed Method of Investigating a Chart
- Click on the associated link
- Investigate
- Share your results in a url
Rational Discussion
Make it easier to have a
Talk Across Tribes
Make it easier to
Data Guided Discussions
Don't trust a chart you can't verify
Brainstorming
End
@jeffreybiles
www.emberscreencasts.com
Query Params
By Jeffrey Biles
Query Params
Query Params are a ridiculously powerful tool for enhancing your apps. Dream big.
- 1,626