Mixin stuff with magento
Mixin stuff with magento
Oct 21, 2022 12:00 AM (5 months ago)

# Mixin stuff with magento

Recently I was tasked to make magento product gallery "sticky", but it had to be sticky to some point, after it gets to product details it has to stop. Ease right 😃 shoud be, so I decided to not spend to much time for this and just use what's already there in magento. So I used magento widget "sticky" for this, but there was one problem, it doesn't have this functionality out of the box. So I decided to extend upon what's already there, and create mixin functionality.

Some steps I folowed: Since this was specifically for one custom theme, I created requirejs-config.js in theme root with following content.

var config = {
  config: {
    mixins: {
      "mage/sticky": {
        "js/sticky-mixin": true,
      },
    },
  },
};

Then it's time to create mixin file under src/app/design/frontend/[Vendor name]/[Theme name]/web/js/sticky-mixin.js

And we will override just the method that we need to change _stick and since we are adding new setting for sticky we will add two new options as well

 options: {
            /**
             * Extending sticky by adding additional option for scrolling STOP
             */
            scrollToEl: '',

            /**
             * Turn on/off on mobile view
             */
            activOnMobile: ''
        }

activOnMobile is another option that we will add to turn on/off this new "functionality" on mobile view ...so finally our mixin file should look something like this

define(["jquery"], function ($) {
  "use strict";

  var stickyMixin = {
    options: {
      /**
       * Extending sticky by adding additional option for scrolling STOP
       */
      scrollToEl: "",

      /**
       * Turn on/off on mobile view
       */
      activOnMobile: "",
    },

    /**
     * float Block on windowScroll
     * @private
     *
     * this.options.scrollToEl - is CONTROLLING if STOP functionality is active
     */

    _stick: function () {
      var offset, isStatic, stuck, stickAfter;

      isStatic = this.element.css("position") === "static";

      if (!isStatic && this.element.is(":visible")) {
        offset =
          $(document).scrollTop() -
          this.parentOffset +
          this._getOptionValue("spacingTop");

        offset = Math.max(0, Math.min(offset, this.maxOffset));

        stuck = this.element.hasClass(this.options.stickyClass);
        stickAfter = this._getOptionValue("stickAfter");

        if (offset && !stuck && offset < stickAfter) {
          offset = 0;
        }

        if (this.options.activOnMobile && this._checkScreenSize() < 1024) {
          return;
        }

        if (this.options.scrollToEl) {
          var stopElement = $(this.options.scrollToEl).offset(),
            stopCalculation =
              stopElement.top -
              (this.element.outerHeight() + 20) -
              this.parentOffset;

          if (offset < stopCalculation) {
            console.log(offset);
            this.element
              .toggleClass(this.options.stickyClass, offset > 0)
              .css("top", offset);
          }
        } else {
          this.element
            .toggleClass(this.options.stickyClass, offset > 0)
            .css("top", offset);
        }
      }
    },
    _checkScreenSize: function () {
      var width =
        window.innerWidth ||
        document.documentElement.clientWidth ||
        document.body.clientWidth;

      return width;
    },
  };

  return function (targetWidget) {
    $.widget("mage.sticky", targetWidget, stickyMixin);
    return $.mage.sticky;
  };
});

I have some explaining here to do: activOnMobile with help of method _checkScreenSize will be used to check if the screen size is mobile, and if it this function need to be turned off.

stopCalculation =
  stopElement.top - (this.element.outerHeight() + 20) - this.parentOffset;

stopCalculation is place where correct offset of stopElement is calculated

# Final result of the modification