Pages - Menu

Demandware - Ajax Fetch Form Post in React

Scope

Previously, we did a mini project for Demandware - Converting Multi-steps Checkout to One Page Checkout

Ajax post was done by using jQuery as that is the standard javascript framework in Demandware. As we are migrating from jQuery to React, we no longer have the luxury to use $.ajax().


Technical

In our ES6/Javascript, we will use fetch to perform our form post. In React/Redux, we will do this in our action.

By not using jQuery framework, we also no longer be able to use the .serialize() to serialize the Form object. This will need to be done by Vanilla JS and I have found a library just do exactly that. :)

Code


import serialize from 'form-serialize'

export const postFormAjax = (actionUrl) => {
 
 var myForm = document.getElementById('my-form')
 var data = serialize(myForm)
 
 return dispatch => {
 
  var init = {
   credentials: 'same-origin',
   method: 'POST',
   headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
   body: data
  }

  return fetch(actionUrl, init)
   .then(response => console.log(response))
 }
}

Note

  • In the above code, I passed in the actionUrl to my javascript from my Demandware isml by URLUtils.continueURL().toString().
  • We need to manually set the content-type header, otherwise pdict.CurrentHttpParameterMap will be empty.
  • I was trying to use FormData, but I couldn't get it to work with latest Chrome and Demandware. I ended up with bunch of WebKitFormBoundary string that was not usable.



Result

I implemented the above in React and I am able to parse form data correctly in Demandware.



In our checkout page, I can dispatch actions to disable/enable the correct panels while performing ajax post back in the background.


Fetch then Promise by Google Geocoder Example

Scope

Our store locator supports searching by post code or suburb names.


However, our Demandware instance only have stores information by post code. In order to retrieve store information by suburbs, firstly we make an ajax call to the Google Maps Geocoding API to find out the post code by suburb. Then, use this information to search for stores.

All of the above are javascript driven by React dispatches. In our console log, we found that the code is fetching the getStoreUrl before the Google API callback our site which is incorrect. The timeline looks like this.


Technical

The Goal: After we called geoCoder(), we need to wait for Google API callback() before calling getStoreUrl().

To achieve this, we will wrap the Google API call within a Promise object. For simplicity, I stripped out some of our custom logic and our code looks like this.

export const geoCoderPromise = (address) => {
 console.log ('geoCoderPromise() called.')
 
 var geocoder = new google.maps.Geocoder();
 
 return new Promise(function(resolve, reject) {
  
   geocoder.geocode({'address': address}, function(results, status) {
      console.log ('geoCoderPromise Callback() called', results)
      
      if (status == google.maps.GeocoderStatus.OK && results[0]) {
       resolve(results[0]);
      } else {
       reject(status);
      }
   })
 })
}

We use 'then' to chain up the Promise objects chronologically.

export export const fetchStores = () => {
  console.log('dispatch action - fetchStores')
   
  return dispatch => {
    return geoCoderPromise(address)
      .then(result => fetch(getStoreUrl(result)))
      .then(response => console.log(response.text()))
  }
}

Looking at the console log, the execution sequence is now correct. Firstly we ask Google what is the post code for Paddington, then we past 2021 as a parameter to our getStoreUrl to generate the url and then dispatch a fetch().