Source: management-system/src/frontend/components/processes/processForm/OnSubmitProviderMixin.vue

<script>
/**
 * Class representing a list of callbacks ordered following a provided priority
 *
 * Ordering is from highest to lowest priority
 */
class PriorityCallbackList {
  constructor() {
    this.callbacks = [];
  }

  /**
   * Inserts a new callback into the callbacks list
   *
   * @param {Number} priority defines the priority with which this callback should be executed (higher is better
   * @param {Function} callback the callback that should be inserted
   */
  insert(priority, callback) {
    // search for the index where the new element should be inserted
    let firstLowerIndex = this.callbacks.findIndex((entry) => entry.priority < priority);
    firstLowerIndex = firstLowerIndex === -1 ? this.callbacks.length : firstLowerIndex;

    // will enter the new entry at the previously found index
    this.callbacks.splice(firstLowerIndex, 0, { callback, priority });
  }

  /**
   * Removed a callback from the list
   *
   * @param {Function} callback the callback to remove
   */
  remove(callback) {
    this.callbacks = this.callbacks.filter((entry) => entry.callback !== callback);
  }

  /**
   * Allows iteration over this class
   * Implementation from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterator_protocol
   */
  [Symbol.iterator]() {
    let index = 0;

    return {
      next: () => {
        if (index < this.callbacks.length) {
          return { value: this.callbacks[index++], done: false };
        } else {
          return { done: true };
        }
      },
    };
  }
}

/**
 * @module components
 */
/**
 * @memberof module:components
 * @module processes
 */
/**
 * This mixin provides a way for nested components inside the component using it to register callbacks that will be called by the component
 *
 * @memberof module:components.module:processes
 * @module Vue:OnSubmitProviderMixin
 *
 */
export default {
  data() {
    return {
      /**
       * Callbacks set by other components that should be called to check if the data inside the form is valid and can be submitted
       */
      beforeSubmitValidatorCallbacks: new PriorityCallbackList(),
      /**
       * Callbacks set by other components that should be called before the data is submitted to the store
       */
      beforeSubmitCallbacks: new PriorityCallbackList(),
      /**
       * Callbacks set by other components that should be called after the data is submitted to the store
       */
      afterSubmitCallbacks: new PriorityCallbackList(),
    };
  },
  provide() {
    return {
      onBeforeSubmitValidation: this.registerBeforeSubmitValidator,
      offBeforeSubmitValidation: this.unregisterBeforeSubmitValidator,
      onBeforeSubmit: this.registerBeforeSubmit,
      offBeforeSubmit: this.unregisterBeforeSubmit,
      onAfterSubmit: this.registerAfterSubmit,
      offAfterSubmit: this.unregisterAfterSubmit,
    };
  },
  methods: {
    registerBeforeSubmitValidator({ callback, priority }) {
      this.beforeSubmitValidatorCallbacks.insert(priority, callback);
    },
    unregisterBeforeSubmitValidator(callback) {
      this.beforeSubmitValidatorCallbacks.remove(callback);
    },
    registerBeforeSubmit({ callback, priority }) {
      this.beforeSubmitCallbacks.insert(priority, callback);
    },
    unregisterBeforeSubmit(callback) {
      this.beforeSubmitCallbacks.remove(callback);
    },
    registerAfterSubmit({ callback, priority }) {
      this.afterSubmitCallbacks.insert(priority, callback);
    },
    unregisterAfterSubmit(callback) {
      this.afterSubmitCallbacks.remove(callback);
    },

    async executeValidatorCallbacks(...params) {
      for (const { callback } of this.beforeSubmitValidatorCallbacks) {
        await callback(...params);
      }
    },

    async executeBeforeSubmitCallbacks(...params) {
      for (const { callback } of this.beforeSubmitCallbacks) {
        await callback(...params);
      }
    },

    async executeAfterSubmitCallbacks(...params) {
      try {
        for (let { callback } of this.afterSubmitCallbacks) {
          await callback(...params);
        }
      } catch (err) {
        this.$logger.debug(err);
      }
    },
  },
};
</script>