14

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?

  • Hey. Dear Alan Store,did you get answer? – Amit Bera Dec 11 '15 at 8:48
  • @AmitBera Not yet. – Alan Storm Dec 28 '15 at 19:01
6

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:

14

Magento 2 uses Customer Data JS API to represent user session data in browser. All JS widgets are supposed to retrieve customer data from Customer Data JS API. Customer Data is split to sections (cart, wishlist, ...). Every segment is observable, so whenever it is modified, the widget that uses it is re-rendered to display the change.

Magento framework is responsible for synchronization of PHP session and JS local storage Customer Data.

Every time a visitor with session ID cookie and empty local storage visits Magento page, an HTTP request to server is made to retrieve customer data (all sections).

Every time the visitior does some state-modifying operation (add to cart, add to wishlit), corresponding section of customer data is invalidated in local storage and another HTTP request is made to retrieve updated sections.

You can use 'sections.xml' to link POST actions to local storage sections that will be invalidated whenever that actions are called. See https://github.com/magento/magento2/blob/develop/app/code/Magento/Checkout/etc/frontend/sections.xml for example.

1

Building on these other answers, if you are updating the cart via API calls in normal Magento require.js files, but you can't rely on the jQuery ajaxComplete method to refresh the minicart (using another AJAX request framework?), you can require the Magento_Customer/js/customer-data object and ask the minicart to refresh this way, as well:

<script>
    require([
        'Magento_Customer/js/customer-data'
    ], function (customerData) {
        var sections = ['cart'];
        customerData.invalidate(sections);
        customerData.reload(sections, true);
    });
</script>

Source: https://github.com/magento/magento2/issues/5621

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.