Attachments with Ember Octane

Hello, thanks for an awesome framework. Ember is really nice pice of art!

Sidenote: I started a little project to evaluate Ember against React. I like that Ember is rather ridgit about the rules. In React everything maybe possible but that isn’t always a good option to have. So I really want to do things the Ember way while using good programming practices in general at the same time.

Question: What is the right way to deal with attachments in Ember?

Background: Im using couchdb for the backend and have a record that is storing receipts. Each receipt has metadata and the reciept images. (My question is not regarding pouch or anything like that)

Current approach: The attachements are simple property object that I augment with actual attachments bites during the routes model() method. I do that because I want to enable offline use and can’t directly link to the server for the same reason. In order to handle the upload and display I created two components. One to display the attachment, using the bytes and converting them using URL.createObjectURL, the src of an img tag is fetched this way. The other to upload the attachment using the file reader API, will set the attachments on the model.

Problem: Everything works fine except that the display component doesn’t update when I upload a new picture. I have to call model.save() and rerender the page in order to trigger an update. As there are almost no hooks left in Octane I’m not sure how to trigger the rerendering of the other component. I feel it should be possible with computed properties or tracking or something like that. Such that

<img src={{this.src}}>

// display
get src() {
   blob = someLogic(model.get('attachments'))
   return URL.createObjectURL(blob)
}

would be updated by the upload controller

// upload
@action
upload() {
  // filereader stuff
  let blob = readAllTheBytes()
  let model = this.model.get('attachments');
  attachments['picture'].data = blob;
  this.model.set('attachments', attachments);
}

Thanks for your time.

set is optimized for object equality, so if you’re doing this:

let attachments = this.model.get('attachments');
attachments['picture'] = blob;
this.model.set('attachments', attachments);

It won’t rerender because the old and new values of attachments are ===.

You can switch to something that results in a new value instead:

let attachments = this.model.get('attachments');
this.model.set('attachments', { ...attachments, picture: blob });
1 Like

But also, you should be able to do this all with a tracked property instead of get and set, and then this problem goes away.

I will check that out, thanks.

I found a small workaround, using a manual update function, as described here: https://guides.emberjs.com/release/components/component-state-and-actions/#toc_combining-arguments-and-actions

But that requires me to hardwire the dependencies in the handlebars template, that feels ugly.

Will report back.

That fixes my problem, thanks. Is this something I overlooked in the guides?

Maybe, but as far as I know the guides don’t tell people to use set at all, which protects them from this whole area of potential complexity. set is legacy technology, new code should use tracked properties.