Magento 2: Syncing Backend and Frontend State/Cache
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.
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:
- How to trigger a minicart update after adding to cart
- Magento 2: how do customer sections / sections.xml work?
- https://alankent.me/2014/12/09/magento-2-caching-overview/
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