Ember Patterns
**************
- :doc:`dev-ember`
- :doc:`dev-ember-addons-kb`
- :doc:`dev-ember-addons`
- :doc:`dev-ember-auth`
- :doc:`dev-ember-data`
Forms
=====
Move your form to it's own component e.g::
{{#if @model.schedule.isRunning}}
{{else}}
{{#with @model.schedule.value as |schedule|}}
{{/with}}
{{/if}}
Using ``ember-changeset`` and validations::
import Component from "@glimmer/component"
import lookupValidator from "ember-changeset-validations"
import ScheduleValidations from "../validations/schedule"
import { action } from "@ember/object"
import { Changeset } from "ember-changeset"
import { inject as service } from "@ember/service"
import { task } from "ember-concurrency"
import { tracked } from "@glimmer/tracking"
export default class WorkflowDeleteFormComponent extends Component {
@service kbMessages
@tracked changeset = null
constructor(owner, args) {
super(owner, args)
console.log(this.args.schedule)
this.changeset = new Changeset(
this.args.schedule,
lookupValidator(ScheduleValidations),
ScheduleValidations
)
}
@action
submitForm() {
this.saveTask.perform()
}
@task *saveTask() {
let process_id = this.changeset.get("id")
this.changeset.validate()
if (this.changeset.isValid) {
try {
yield this.changeset.save()
if (this.args.routeTransition) {
this.args.routeTransition(process_id)
} else {
console.log(
"WorkflowDeleteFormComponent ('components/workflow-delete-form.js') no 'routeTransition'"
)
}
} catch (e) {
this.kbMessages.addError("Cannot delete the workflow process", e)
}
}
}
}
To allow empty dates, use the following code::
if (this.changeset.isValid) {
try {
if (this.changeset.get("startDate") == "") {
this.changeset.set("startDate", null)
}
yield this.changeset.save()
In the form, highlight ``changeset`` and *server side* errors::
.. tip:: To return server side errors, check out the ``_deleted_comment`` code
from ``ScheduledWorkflowUserViewSet`` (``work/api.py``).
08/04/2021, Not sure if this works with serializer errors or our
``custom_exception_handler`` (``api/models.py``).
Notifications
=============
Use the ``KbMessages`` service:
https://gitlab.com/kb/kb-base-ember-addons/-/blob/tailwind-2-update-ember/addon/services/kb-messages.js
::
import { inject as service } from "@ember/service"
@service kbMessages
try {
// do something
} catch (e) {
this.kbMessages.addError("Cannot delete the workflow process", e)
}
Page
====
::
import { inject as service } from "@ember/service"
@service kbPage
export default class WorkflowRoute extends Route {
beforeModel(transition) {
this.kbPage.setTitle("Workflow")
}
.. _dev-ember-patterns-pagination:
Pagination (JSON API)
=====================
Example ``pagination`` (``meta``) returned from a JSON API view::
{page: 5, pages: 191, count: 3817}
Pagination
==========
Configure ``KbRestPagination`` as the ``pagination_class`` for the viewset::
from api.api_utils import SoftDeleteViewSet
class IssueViewSet(SoftDeleteViewSet):
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,)
serializer_class = IssueSerializer
In your controller::
queryParams = ["page"]
@tracked page = 1
get recordsPerPage() {
/**
* Number of records per page (``perPage``).
*
* This is a fixed value in Django and Ember code.
*/
return 20
}
@action
setPage(page) {
this.page = page
}
In your route, refresh the ``page`` and add ``perPage`` / ``totalPagesParam``
parameters::
queryParams = {
page: {
refreshModel: true,
},
sort: {
refreshModel: true,
},
company_name: {
refreshModel: true,
},
};
contactTask = task(async (params) => {
let filter = {};
if (params.company_name) {
filter = { company_name: params.company_name };
}
try {
let contact = await this.store.query('contact', {
page: {
number: params.page,
},
sort: params.sort,
filter: filter,
});
return await contact;
} catch (e) {
this.kbMessages.addError('Cannot load contact', e);
}
});
Add the ``KbPagination`` component in your template (just before the table)::
{{#if @model.tickets.isRunning}}{{else}}
{{/if}}
.. tip:: If the ``KbPagination`` is inside a ``SlideOver``,
then add ``@isSlideOver={{true}}``.
Slide Over
==========
::
{{#if this.slideOverVisible}}
// Content of Slide-over...
{{/if}}
.. _dev-ember-patterns-tables-data:
Tables / Data
=============
Checklist
1. Add ``reload: true`` to all ``findRecord`` and ``findAll`` methods
For details, see :ref:`ember-error-handling`
2. Add a ``try``, ``catch`` to all ``store`` methods.
Use ``kbMessages.addError`` in the ``catch`` (see example below).
3. Test the ``store`` methods with an exception on the server (500 error).
4. Check the user is notified if a ``store`` method returns no data.
Route::
import { inject as service } from "@ember/service"
@service kbMessages
model(params) {
return {
processes: this.processesTask.perform(params)
}
}
@task *processesTask(params) {
try {
let processes = yield this.store.query("process", params)
return yield processes
} catch (e) {
this.kbMessages.addError("Cannot load workflow processes", e)
}
}
The components for tables can be found here :ref:`dev-ember-addons-kb-table`.
To add a spinner and *nothing found* to your table::
{{#if @model.processes.isRunning}}
{{else}}
{{#each @model.processes.value as |process|}}
{{else}}
{{#if this.workflow}}
No workflow processes found ...
{{else}}
Please select a workflow...
{{/if}}
{{/each}}
{{/if}}
.. tip:: For pagination, see :ref:`dev-ember-patterns-pagination`.