Async action state in item components


#1

We have a list of items in our app. Those items each have a delete action. Here’s a simple example:

title           date          actions
Second post    2015-08-12    [delete]
First post     2015-06-06    [delete]

When the user hits delete, we want to show the pending delete to the user, and notify them if it fails. What is the best approach?

The problem is that if we just trigger the action, it will bubble up and be handled, but the component that triggered it doesn’t have any way of seeing whether it completed successfully or not.

One solution is to add an editState field to the model, because the model is what drives the list display, so we know its state will be visible to the item’s component:

  1. When the user hits the “delete” button, mark the model’s editState as PENDING_DELETE and display a loading indicator in the component.
  2. If it fails mark the model’s editState as FAILED_DELETE (and remove the loading indicator when that reaches the component).
  3. If it succeeds, let the item be removed from the list.

But that seems like we’ve basically implemented “actions down” over the “data down” channel. Is that reasonable?

What we really want to be able to do is send an action from the component, and watch for a promise to be resolved with success or failure. Is there a way to do that now?

Part of the problem is that these parts of the page are not routable, because many items exist on the same page, so as far as I know we can’t use a loading substate. It’s also harder to deliver state to the component, because the Controller and Route are responsible for many items. Much of the built-in niceness of Ember seems to be unavailable for non-routable items.

Any suggestions? We’re especially interested in using an approach that is most compatible with Ember 2.0 and beyond.


#2

I don’t know if it’s the best from Ember perspective but why not doing something like:

delete: function(item) {
    this.showLoader();
    YourModel.deleteItem(item)
        .then(...)
        .catch(...)
        .finally(this.hideLoader());
}

The only thing you need to do is to have a static method inside your model which would remove passed item from it.


#3

Could you use the model’s isDeleted property?

Since Ember Data 2.0.0-beta1, “In Ember Data 2.0 a record will no longer be removed from hasMany relationships or RecordArrays until the delete has been acknowledged by the adapter.”. More here.


#4

I don’t want to call model methods in the component. That doesn’t seem to be the correct separation of concerns.


#5

That might work, but it’s a little disconnected. I’m not sure how it would address a failed delete (e.g. due to a network drop). It is also a little too targeted to the delete use case. I’m more concerned with this as a design pattern, which we’ve run into in many places besides deletion.


#6

Absolutely! I get that this is a more profound design issue.

Re: separation of concerns, is it “wrong” to access model properties from a component? I’d think in your (specific) use-case accessing store-related data in the model is acceptable. Perhaps it warrants accessing the store directly from the component?

If this contributes to the answer you’re looking for, I recently wrote about this design question: http://emberigniter.com/should-components-load-data/