Ember

Salt

If your Django site has an Ember front end, then add ember: True to your sites file:

# sites/my.sls
sites:
  www.hatherleigh.info:
    package: hatherleigh_info
    profile: django
    ember: True

The default path for your Django app will be /back/ and the default path for your Ember app will be /. If you want to override this, then you can set the ember_path and django_path as follows:

# sites/my.sls
sites:
  www.hatherleigh.info:
    package: hatherleigh_info
    profile: django
    ember: True
    ember_path: front
    django_path: back

Note

Don’t append or prepend a / to the ember_path or django_path. The Salt state files will take care of the /.

If you set an ember_path (other than /), set the rootURL in the production environment (config/environment.js):

if (environment === "production") {
  ENV.rootURL = "/front/"
}

Installation

Prerequisites

Using volta:

curl https://get.volta.sh | bash
# open a new terminal
# to install the latest LTS release
volta install node

Using nodesource To install node and npm (from https://github.com/nodesource/distributions):

curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
sudo apt install -y nodejs

Installing Ember-cli

npm install -g ember-cli

Creating a project

Run the following commands to create a project e.g. ember-first:

ember new ember-first --lang en
cd ember-first
ember serve
# or...
npm start

Cloning an existing project

To clone an existing project e.g. ember-first:

git clone git@gitlab.com:proj-owner/ember-first.git
cd ember-first
npm install
bower install
ember server

Components

The following input attributes must be passed as arguments (i.e. do prepend @) to the <Input> component:

@checked
@type
@value

From https://guides.emberjs.com/release/components/built-in-components/

Error Handling

Configuration

Django REST framework exception handler (from the api app):

REST_FRAMEWORK = {"EXCEPTION_HANDLER": "api.models.custom_exception_handler"}

Exceptions and Responses

For Ember to understand and handle an exception, we need to be using the custom_exception_handler (see above).

e.g. if a user does not have permission to data, then raise PermissionDenied (from rest_framework.exceptions import PermissionDenied)

Warning

Do not return an HttpResponseForbidden response as Ember will have no idea what happened.

Tip

For an example, search for PermissionDenied in work/api.py

To catch the forbidden error code in Ember:

try {
  let process = yield this.store.findRecord("process", params.workflow_id, {
    reload: true
  })
  return yield process
} catch (e) {
  if (e.errors.firstObject.status === "403") {
    return yield undefined
  } else {
    this.kbMessages.addError("Cannot load workflow processes", e)
  }
}

Learn

Tip

We have two projects which can be used together to explore Ember data:

  1. https://gitlab.com/kb/contact/ (on the 2292-dramatiq branch)

  2. https://github.com/pkimber/ember-data-error

Background

From Force Ember Data to reload data from backend API

Ember Data’s default strategy for requesting data records (either findRecord or findAll):

  • If it is not loaded, load it

  • If it is already loaded, don’t reload it. Instead, backgroundReload it

What does this mean?

  • reload queries for new data pre-emptively, that is, it waits until the promise with new data resolves

  • backgroundReload returns the local (cached) record, and then queries for new data

This has a big impact on error handling because returning the local (cached) copy of a record will probably succeed (so no exception thrown). If the backgroundReload query fails, then this is happening at a later date, away from your error handling code and the exception will not be caught.

There is still an open issue for this: https://github.com/emberjs/data/issues/3809 For more information, search Ember Discord for backgroundReload.

Solution

To solve this issue, add the reload option to findRecord and findAll e.g:

let contact = yield this.store.findRecord("contact", 22, { reload: true })

Then we can catch any errors …

Ember Concurrency

@task *doStuff() {
  try {
    let contact = yield this.store.findRecord("contact", 22, { reload: true })
    this.manager = contact
  } catch(e) {
    console.log("catch, doStuff .........................................")
    console.log(e)
  }
}

Ember (without Concurrency)

If you are not using Ember concurrency, then the error handler in a Route, should catch any errors e.g:

@action
error(error, transition) {
  console.log("Before, contacts.js ...................................")
  console.log(error)
  console.log(transition)
  console.log("After, contacts.js ....................................")
  return false
}

Ember Data

Our adapter (extends the DRFAdapter) can be found in app/adapters/application.js for our projects.

Note

I tried moving the adapter to @kb/ember-addon, but the project doesn’t seem to find it.

Packages

To update one package (e.g kb-base-ember-addons):

npm i @kbsoftware/kb-base-ember-addons@latest

Use ncu (npm-check-updates) to finalise versions before releasing for deployment. Run all the tests and check it by running on a local server.

https://www.npmjs.com/package/npm-check-updates:

npm i -g npm-check-updates

Then type:

ncu

… inside a folder with a package.json.

This shows you what is out of date. And typing:

ncu -u

… will update all the versions in the package.json file.

So you then run:

npm i

… which will upgrade as per the new package.json

Testing

Note

We don’t need to define Mirage models, Auto-discovery of Ember Data models