Skip to content

Instantly share code, notes, and snippets.

@NullVoxPopuli
Last active March 14, 2021 17:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NullVoxPopuli/9c261e95e3817306711e2107372cd398 to your computer and use it in GitHub Desktop.
Save NullVoxPopuli/9c261e95e3817306711e2107372cd398 to your computer and use it in GitHub Desktop.
RFC 712: Specifying Query Params
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
export default class ApplicationController extends Controller {
@service router;
get qps() {
return this.router.currentRoute.queryParams;
}
}
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
export default class ArticlesController extends Controller {
queryParams = ['_category'];
@service router;
// Read-only Query Param
// Encourages Query Params to only be changed via transition
get category() {
// Because controllers implicity set properies that match entries
// in the queryParams array, we cannot have naming conflicts
// between getters and the Query Params
// (Until RFC 715: https://github.com/emberjs/rfcs/pull/715)
return this.router.currentRoute.queryParams._category;
}
get filteredArticles() {
let category = this.category;
let { articles } = this.model;
if (category) {
return articles.filter(article => {
// HackerNews doesn't have categories, but we'll simulate that
// by filtering on type / title
let { type, title } = article;
if (type === category) return true;
return title.toLowerCase().startsWith(category);
});
} else {
return articles;
}
}
}
import { helper } from '@ember/component/helper';
export default helper(function stringify(params/*, hash*/) {
return JSON.stringify(params[0], null, 4);
});
import EmberRouter from '@ember/routing/router';
import config from './config/environment';
const Router = EmberRouter.extend({
location: 'none',
rootURL: config.rootURL
});
Router.map(function() {
this.route('articles');
});
export default Router;
import Route from '@ember/routing/route';
export default class Articles extends Route {
async model() {
let stories = await getLatestHackerNews();
return {
articles: stories,
};
}
}
// --------------------------------------------------------
async function getLatestHackerNews() {
let [ask, show, job] = await Promise.all([
latestStories('ask'),
latestStories('show'),
latestStories('job'),
]);
let mostRecent = [...ask, ...show, ...job];
// N+1 Query, yay!
let stories = await Promise.all(mostRecent.map(id => getItem(id)));
return stories;
}
async function getItem(id) {
return await get(`https://hacker-news.firebaseio.com/v0/item/${id}.json`);
}
async function get(url) {
let response = await fetch(url);
return await response.json();
}
async function latestStories(type) {
let latest = await get(`https://hacker-news.firebaseio.com/v0/${type}stories.json`);
let mostRecent = latest.slice(0, 10);
return mostRecent;
}
body {
margin: 12px 16px;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 12pt;
}
h1 {
margin-bottom: 0.5rem;
}
.flex {
display: flex;
}
.gap-4 {
gap: 1rem;
}
<h1>Example for <a target="_blank" href="https://github.com/emberjs/rfcs/pull/712">RFC 712</a></h1>
<em>Query Params as Derived Data</em>
<br>
<small>Specifying Query Params and using them to filter data locally</small>
<pre>
QPs: {{stringify this.qps}}
URL: {{this.router.currentURL}}
</pre>
<br>
<nav class="flex gap-4">
{{!--
Query Params set on a controller are "sticky"
So to get rid of them, we must explicitly set to *undefined*
This will not scale for lots of Query Params
- See related RFC: https://github.com/emberjs/rfcs/pull/715
--}}
<LinkTo @route="articles" @query={{hash _category=undefined}}>
Articles
</LinkTo>
<LinkTo @route="articles" @query={{hash _category="ask"}}>
AskHN
</LinkTo>
<LinkTo @route="articles" @query={{hash _category="show"}}>
ShowHN
</LinkTo>
<LinkTo @route="articles" @query={{hash _category="job"}}>
Job
</LinkTo>
</nav>
<hr>
{{outlet}}
<br>
<br>
{{#each this.filteredArticles as |article|}}
<div>
{{log article}}
{{article.score}} | <a target="_blank" href={{article.url}}>{{article.title}}</a>
<br>
<em>by {{article.by}}</em>
<hr>
</div>
{{/each}}
{
"version": "0.17.1",
"EmberENV": {
"FEATURES": {},
"_TEMPLATE_ONLY_GLIMMER_COMPONENTS": false,
"_APPLICATION_TEMPLATE_WRAPPER": true,
"_JQUERY_INTEGRATION": false
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"ember": "3.18.1",
"ember-template-compiler": "3.18.1",
"ember-testing": "3.18.1"
},
"addons": {
"@glimmer/component": "1.0.0"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment