Skip to content

Instantly share code, notes, and snippets.

@neborn
Last active February 9, 2021 04:28
Show Gist options
  • Save neborn/039af08cbb8c3ad96e2598c83a145a2a to your computer and use it in GitHub Desktop.
Save neborn/039af08cbb8c3ad96e2598c83a145a2a to your computer and use it in GitHub Desktop.
Employee Search Example
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { inject as service } from '@ember/service';
export default class EmployeeSearchComponent extends Component {
@service employeeSearch;
_employeeSearchQuery;
get employeeSearchQuery() {
return this._employeeSearchQuery;
}
constructor() {
super(...arguments);
this._employeeSearchQuery = this.employeeSearch.createEmployeeSearchQuery();
}
}
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('employee-search', { path: '/employee-search' });
});
export default Router;
import Service from '@ember/service';
import { tracked } from '@glimmer/tracking';
export default class ConfigurationService extends Service {
@tracked currentEmployerId = 'employer1';
@tracked currentEmployerName = 'Test Employer';
}
import Service, { inject as service } from '@ember/service';
import { action } from '@ember/object';
import EmployeeSearchQuery from '../view-models/employee-search-query';
export default class EmployeeSearchService extends Service {
@service configuration;
@action
performEmployeeSearch(params) {
// use configuration service to construct the API request
const results = [
{ name: 'Employee 1', email: 'employee1@business.test' },
{ name: 'Employee 2', email: 'employee2@business.test' },
{ name: 'Employee 3', email: 'employee3@business.test' }
];
return new Promise(
resolve => setTimeout(() => resolve(results), 500)
);
}
@action
createEmployeeSearchQuery() {
return new EmployeeSearchQuery({
searchService: this
});
}
}
<nav>
<ul>
<li><LinkTo @route="employee-search">Employee Search</LinkTo></li>
</ul>
</nav>
<main>
{{outlet}}
</main>
<h1>Employee Search</h1>
<section>
<Input @value={{this.employeeSearchQuery.mutableSearchString}}/>
<button type="button" {{on "click" this.employeeSearchQuery.triggerSearch}}>Search</button>
</section>
{{#if this.employeeSearchQuery.resultsList.isRunning}}
<p>Loading results...</p>
{{else}}
<ul>
{{#each this.employeeSearchQuery.resultsList.value as |employee|}}
<li>
<div>Name: {{employee.name}}</div>
<div>Email: {{employee.email}}</div>
</li>
{{/each}}
</ul>
{{/if}}
{{#if this.employeeSearchQuery.fetchPageTask.isRunning}}
<p>Loading more results...</p>
{{/if}}
<div>
<button type="button" {{on "click" this.employeeSearchQuery.fetchAdditionalPage}}>Load more</button>
</div>
{
"version": "0.17.1",
"EmberENV": {
"FEATURES": {},
"_TEMPLATE_ONLY_GLIMMER_COMPONENTS": false,
"_APPLICATION_TEMPLATE_WRAPPER": true,
"_JQUERY_INTEGRATION": true
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.js",
"ember": "3.18.1",
"ember-template-compiler": "3.18.1",
"ember-testing": "3.18.1"
},
"addons": {
"@glimmer/component": "1.0.0",
"ember-concurrency": "1.3.0",
"tracked-built-ins": "1.0.2",
"tracked-toolbox": "1.2.1"
}
}
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
import { task } from 'ember-concurrency';
import { cached } from 'tracked-toolbox';
import { TrackedArray } from 'tracked-built-ins';
const PAGE_SIZE = 20;
const SortOrder = {
ASCENDING: 'ASCENDING',
DESCENDING: 'DESCENDING'
};
export default class EmployeeSearchQuery {
_searchService;
_pagesLoaded = 0;
@tracked
_resultsList;
@tracked
mutableSearchString = '';
@tracked
_searchString = '';
@tracked
_sortField;
@tracked
_sortOrder;
@cached
get resultsList() {
this._newSearchTask.perform();
return this._newSearchTask.last;
}
get sortField() {
return this._sortField;
}
get sortOrder() {
return this._sortOrder;
}
constructor({ searchService }) {
this._searchService = searchService;
}
@action
triggerSearch() {
this._searchString = this.mutableSearchString;
}
@action
updateSortField(fieldName) {
if (this._fieldName === fieldName) {
return;
}
this._fieldName = fieldName;
this._sortOrder = SortOrder.ASCENDING;
}
@action
toggleSortOrder() {
this._sortOrder = this._sortOrder === SortOrder.ASCENDING ?
SortOrder.DESCENDING : SortOrder.ASCENDING;
}
@action
fetchAdditionalPage() {
this.fetchPageTask.perform();
}
@(task(function * (pageNumber = 0) {
const {
_searchString: searchString,
sortField,
sortOrder
} = this;
const results = yield this._searchService.performEmployeeSearch({
pageNumber,
pageSize: PAGE_SIZE,
searchString,
sortField,
sortOrder
});
Array.prototype.push.apply(this._resultsList, results);
}).restartable()) _searchTask;
@(task(function * () {
if (this._searchTask.isRunning) {
return;
}
const results = yield this._searchTask.perform(this._pagesLoaded + 1, this._searchTask.value);
this._pagesLoaded += 1;
}).drop())
fetchPageTask;
@(task(function * () {
this._pagesLoaded = 0;
this._resultsList = new TrackedArray;
yield this._searchTask.perform();
return this._resultsList;
}).restartable())
_newSearchTask;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment