Magento 2 – Syncing Backend and Frontend State/Cache

javascriptlocal-storagemagento2PHPsession

Does Magento 2 have any systems or abstractions for managing state between the backend and the local storage on the frontend?

I'm working on porting a feature for restoring a user's abandoned cart via a redirect URL. In simplified form, a URL like

http://magento.example.com/restore/the/cart?identifier=sdkfjh48v237g5

will load a quote into the current user's cart based on an encoded quote_id in the identifier.

In Magento 1, this was relatively simple — you just needed to update a user's Checkout session information with the correct quote ID. However, Magento 2 adds in the wrinkle of local storage.

The Magento 2 frontend javascript application(s?) seems to cache information in the browser's local storage databases. This includes information for building the mini-cart. What this means is even if an end-user-programmer (me) manages to change the session Session ID in the backend, the mini-cart will still display the old cart data.

The is just one example of an issue that stems from not knowing (or having?) a single API for managing application state across the backend and frontend. For my specific problem I've had my endpoint rendering an HTML page that includes some javascript the manually clears the local storage and then redirects the user to another page — but this feels like a gross hack.

Is there an API in Magento 2 for managing data between the frontend and backend?

The there a standard way of signaling the entire system that, during backend processing, you've done something that makes it necessary it invalidate the frontend local storage cache?

Is there a technique for injecting a new RequireJS module into the page that runs automatically and can manipulate local storage before the rest of the javascript application(s?) accesses it?

Best Answer

I had a similar problem: I wanted the mini-cart component to refresh after I sent an Ajax request to add an item the cart.

It actually works quite nicely if you just remember some points:

  • Declare which page sections need to be updated after an Ajax call, in etc/frontend/sections.xml of your module.
  • Use jQuery.post() to send your Ajax request. It may be a POST or a PUT request, just not GET.
  • And it must be through jQuery, not Prototype or vanilla JS, because it is jQuery's 'ajaxComplete' event that plays an essential role.
  • prepend the Ajax url with a base-url (do not just start with /)

Here is my sections.xml (xyz is the name of our customer):

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Customer:etc/sections.xsd">
    <action name="xyz-ajax/cart/add">
        <section name="cart"/>
    </action>
</config>

Here, 'xyz-ajax/cart/add' is according to the format '[frontName]/[ActionPath]/[ActionName]'. The xml tells Magento to update 'cart' after ajax call "xyz-ajax/cart/add" has completed.

This is my template (.phtml) code:

<script type="text/javascript">
    require(['jquery', 'BigBridge_XYZ/option_selector'], function($, optionSelect) {
        optionSelect.create(<?= json_encode($componentData) ?>, $);
    })
</script>

and this is the JS code that sends the Ajax request:

function requestComplete(responseData) { }

$.post(baseUrl + 'xyz-ajax/cart/add/cf/' + configurableProductId + '/simple/' + item.simpleProductId + '/amount/' + item.amount, requestComplete);

What happens in the process?

Every time your script sends an Ajax POST (or PUT) request to the server via jQuery, and it returns, jQuery sends an 'ajaxComplete' event. This event is handled by a handler in module-customer/view/frontend/web/js/customer-data.js. This handler checks which page-sections depend on the Ajax call (from your sections.xml) and invalidates them. These will be updated.

Sources: