codebykyle / calculated-field

A Server Side Calculated Field for Laravel Nova
46 stars 21 forks source link

Multiple Listeners on the same event #4

Open tanthammar opened 4 years ago

tanthammar commented 4 years ago

Is it not possible to have multiple listeners on the same event?

Each of these listeners work on their own but if I add them all, only the last is updated

BroadcasterField::make(__('Gross'),  'gross')
                ->broadcastTo('discount')
                ->hideFromIndex(),
BroadcasterField::make(__('Disc Percent'),  'disc_percent')
                ->broadcastTo('discount')
                ->hideFromIndex(),
BroadcasterField::make(__('Disc Amount'),  'disc_amount')
                ->broadcastTo('discount')
                ->hideFromIndex(),

ListenerField::make(__('Disc Sum'),  'disc_sum')
                ->listensTo('discount')
                ->hideFromIndex()
                ->calculateWith(function (Collection $values) {
                    // some calculations;
                    return $disc_sum;
                }),
ListenerField::make(__('Disc Sum Percent'),  'disc_sum_percent')
                ->listensTo('discount')
                ->hideFromIndex()
                ->calculateWith(function (Collection $values) {
                   // some calculations;
                    return $disc_sum_percent;
                }),
ListenerField::make(__('Discounted Gross'),  'discounted_gross')
                ->listensTo('discount')
                ->hideFromIndex()
                ->calculateWith(function (Collection $values) {
                    // some calculations;
                    return $disc_gross;
}),
pauldstar commented 4 years ago

In the listener field, at "calculated-field/resources/js/components/listener-field/FormField.vue" the following code causes the event to only affect one listener component at a time.

calculateValue: _.debounce(function() {
      this.calculating = true;

      Nova.request()
        .post(
          `/codebykyle/calculated-field/calculate/${this.resourceName}/${this.field.attribute}`,
          this.field_values
        )
        .then(response => {
          this.value = response.data.value;
          this.calculating = false;
        })
        .catch(() => {
          this.calculating = false;
        });
    }, 500),

Removing the _.debounce() function, and replacing the above code with this solved it for me:

calculateValue: function() {
    this.calculating = true;

    Nova.request()
        .post(
            `/fusion/calculated-field/calculate/${this.resourceName}/${this.field.attribute}`,
            this.fieldValues
        )
        .then(response => {
            this.broadcastHandler(response);
            this.calculating = false;
        })
        .catch(() => {
            this.calculating = false;
        });
},

Of course, it's not ideal to modify vendor/package code. So I basically followed @codebykyle instructions here, and created my own custom package, to fix this issue myself.

jappiewent commented 2 years ago

@pauldstar @codebykyle

This issue can be fixed while keeping the debounce in place! This is a very useful article I used helping debug this part.

Rewrite calculate value function:

    calculateValue: function () {
      this.calculating = true;
      Nova.request()
          .post(
              `/jappiewent/calculated-field-improved/calculate/${this.resourceName}/${this.field.attribute}`,
              this.field_values
          )
          .then(response => {
            this.value = response.data.value;
            this.calculating = false;
          })
          .catch(() => {
            this.calculating = false;
          });
    },

And add the debounce to the mounted part of your component:

  mounted: function () {
    this.calculateValue = _.debounce(this.calculateValue, 500).bind(this);
    this.calculateValue();
  },