Yes, that's a perfectly reasonably approach.
however, you need to somehow manually call toggleCall somehow.
My favorite way to load things or do anything async in a component, is to do so lazily and reactively via derived-data using "Resources".
There is a utility called trackedFunction from: https://github.com/nullvoxpopuli/ember-resources
Specific docs here
Your example could be re-written as:
import Component from '@glimmer/component';
import { trackedFunction } from 'ember-resources';
export default class Example extends Component {
fetchItems = trackedFunction(this, async () => {
let response = await fetch( /* ... */);
return await response.json();
});
get items() {
// specify a default value of empty array when value is undefined
// (value is undefined before the function finishes running)
return this.fetchItems.value ?? [];
}
}
Key differences:
- the
trackedFunction will automatically be invoked upon access
- repeat-accesses will not re-invoke the function
- any
@tracked data used before the await in the trackedFunction will "entangle" so that changes to that @tracked data will cause the function to run again, for example, if you had a query parameter
@tracked filter = 'name:starts_with=a';
fetchItems = trackedFunction(this, async () => {
let url = `...?${this.filter}`;
let response = await fetch(url /* ... */);
return await response.json();
});
fetchItems is reactive, in that now when filter changes, fetchItems will re-invoke itself.
However, if you plan on keeping the request-on-click behavior (which is common!), you may be interested in ember-concurrency, which provides some nice ergonomic utilities for handling / protecting your data from the sillyness that use human-computer-interaction -- such as not re-requesting after a user has clicked a button, and clicked that button again before the request finishes.
Your example would then be:
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { dropTask } from 'ember-concurrency';
export default class Example extends Component {
@dropTask
*fetchItems() {
let response = await fetch( /* ... */);
return await response.json();
}
get items() {
return this.fetchItems.lastSuccessful.value ?? [];
}
// click handler can be called any number of times,
// which would, in turn, call fetchItems any number of times,
// but only one `fetch` request will ever run at a given time.
@action
handleClick() {
this.fetchItems.perform();
}
}
Docs on ember-concurrency here: https://ember-concurrency.com/