Hi,
I’ve built an input search component that I’m pretty happy with. The component contains an html input element, and performs a JSON API style search using the text value in the input. I’m currently using Mirage as a mock server, and I’ve included debouncing in the component that looks for a 250ms pause between keystrokes before firing off another search request. All good so far.
{{!-- SearchBoards component JS --}}
export default class SearchBoardsComponent extends Component {
@tracked query = null;
@tracked results = [];
// This task performs a 250ms debounce so that a query to the
// server is only performed after the user has paused slightly
// The "restartable" option at the end of the task cancels all
// but the latest task request when the task is run multiple
// times concurrently.
@(task(function * () {
yield timeout(250);
if(this.query) {
let response = yield fetch(`/search?query=${this.query}`);
this.results = yield response.json();
} else {
this.results = [];
};
}).restartable()) updateResults;
}
I have used the “on modifier” in the component’s template to call an update method in the component. As I understand it this is the DDAU approach that we should be taking.
{{!-- SearchBoards component template --}}
<div>
<Input
placeholder="search"
autofocus
{{!-- The search query text; bound to an attribute in the component --}}
@value={{this.query}}
{{!-- Trigger a search after a key press (i.e. keyup event) --}}
{{on "keyup" (perform this.updateResults)}}
/>
</div>
Next I wanted to incorporate query parameters so that the text value in the search component corresponds (i.e. is synchronised) with the value of the query parameter, but I’m not sure the best way to do this.
Query parameters can be easily implemented on the controller (corresponding to a route) so I can see how I can pass in a parameter to my search component from the route’s template, but then what?
Search route template:
{{!-- app/pods/search/template.hbs --}}
<SearchBoards />
Search route controller:
// app/pods/search/controller.js
import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking';
export default class SearchController extends Controller {
queryParams = ['query'];
@tracked query = null;
}
Options I have considered, but I know there must be a better way:
- Take the component template code and implement it as a route (doing away with the component)
- Add the “on modifier” to the route’s template (not the component’s template) and then pass a parameter to the component. …but this doesn’t feel like a clear separation of concerns anymore
I’m really keen to understand the right design pattern (and patterns in general) as I build up my application. I’m finding that learning ember is like riding waves: waves of elation, and waves of despair, but I can see when done right the code can be expressive and neat.
Thanks,
Dave
4 posts - 2 participants