Prevent smart action submit from reloading the records inside Smart Views

We have a smart view that loads up a collection where each item in the list has various actions. The way it’s presented is very much like this example from Forest Doc Examples: Create a custom tinder-like validation view - Woodshop.

The issue is that when the actions submit, it will reload the collection, and cause the selected record to reset it back to the first in the list. I’ve tried adding @async={{false}} to the buttons as an option, but the same result occurs. In addition, I’d prefer to not us the <Button::BetaButton>, and instead pass my list of actions to the template like so:

<ul class="actions__list">
  {{#each lane.actions as |actionItem|}}
    <li class="actions__item">
      <a
        href="#"
        {{on "click" (fn actionItem.actionName talent)}}
      >
        {{actionItem.actionLabel}}
      </a>
    </li>
  {{/each}}
</ul>

This works just fine, but this doesn’t stop the reload from occurring either as I don’t see a way to pass in a async false option to a triggerSmartAction.

Any ideas?

Thanks in advance!

Hey @David_Panzarella,

I did a little fix to be able to do it (this will be live in the afternoon).
You will be able to do so with the following code:

  const actions = await this.args.collection.customActions;
  const action = actions.findBy('name', actionName);

  // skipRefresh is what interest you in this case
  return this.triggerSmartAction(this.args.colletion, 'myActionName', records, undefined, values, skipRefresh);

1 Like

Amazing! Thanks so much for doing this, and shoot me an update when it’s live so I can test for you on my end.

So it looks like its live:

However, it still refreshes the list on my end. Thoughts?

Any updates here? Its still refreshing the page.

Just bumping on this again. Any updates on this?

Hi @David_Panzarella ,

Really sorry to keep you waiting :sweat_smile:. I had an emergency the same day and then I was in holidays the week after :disappointed:.
I’m back on it, should be fast. I’ll keep you informed :wink:

Should be live now. Let me know if it works :pray:

1 Like

Woot! Works like a charm! Thanks again for doing this, and no worries about the delay. I hope you had a great holiday!

1 Like

@vince so I discovered one issue with this:

Upon the success of the smart action, the data will doesn’t get refetched. I think this was your intention with not reloading the page, however, the data that sits within the cards on our Smart View also doesn’t update. Is there a workaround for maybe only reloading the currently selected record after the smart action submits? I’m happy to dm directly to show you what we’re trying to do if that will make help?

thanks again!

const myCallback = (result) => {
  await result;
  // refresh here
}
return this.triggerSmartAction(this.args.collection, 'myActionName', records, myCallback, values, skipRefresh);

Thanks, @vince! Definitely getting closer. I was able to trigger the callback and be able to select the current record so we’re no longer losing that signal. The issue though is that we still need to reload the whole promise for that currently selected record; which has many nested promises from DS.PromiseArray.

From doing some googling, it looks like I should conceptually be able to update the record that was updated from the action doing something like this:

this.store.findRecord('forest-TalentQueuexUser', refetchUser.id).then(newTalentQueuexUser => {
  return newTalentQueuexUser;
});

But even if this is possible, I’d still need to move the details for that record into an object that’s getting returned by the current record promise. I’m sure that sounds confusing without being able to see the entire structure of the component! :laughing:

If it helps, I essentially have a large promise that gathers up 2 people lists and combines them into a normalized list. I then take that list, parse it based on some booleans like hasUser, and then divide it into lanes based on who is missing a user or other similar data. When an Action is triggered, it will change the data and thus the lane it belongs to. So (and sorry for the long-winded explanation) I’m trying to avoid having to re-fetch all the data for 1 record update, while also updating the normalized list that the updated record is in.

The promise looks like this:

      // fetch all non-users and users
      return DS.PromiseArray.create({
        promise: this.loadNonUsersAndUsers(nonParams, userParams)
          .then(([
            nonUsers, users
          ]) => {
            // merge nonUsers and users as standardized talent
            const talent = [];

            nonUsers.map(nonUser => { 
                talent.push({ firstName, hasUser, etc});
            });

            users.map(user => { 
                talent.push({ firstName, hasUser, etc});
            });

            // place talent into their respective lanes
            this.currentRecord.lanes = [
              {
                key: 'missingUser',
                talent: talent.filter(talent => !talent.hasUser),
              }

Not sure if there is any way of injecting the updated data into this talent object, but that’s is ultimately what I’m trying to accomplish after the action is taken.

Thanks, @vince for your help and reading through.

Wow @David_Panzarella, really sorry for the delay. I did got notifications for a while, I don’t know why :confused:

So I’m not sure I understood your problem :sweat_smile:.
But when you do want a custom object that you use inside your template your should use class with tracked properties.
So in your case

class talent {
  @tracked _nonUser;
  @tracked _user;

  constructor({ nonUser, user }) {
    this._nonUser = nonUser;
    this._user = user;
  }

  get firstName() { return this._nonUser.firstName || this._user.firstName; }
  // etc.. for hasUser and others...
}

Like that as soon as you do

this.store.findRecord('forest-TalentQueuexUser', refetchUser.id).then(newTalentQueuexUser => {
  return newTalentQueuexUser;
});

This will refresh the talent linked