0

I creating my first application using Business Catalyst API to GET, POST, PUT, DELETE requests using AJAX, the problem I have is that sometimes I need to grab data from different GET calls to generate new requests and apparently I am a bit lost on how to efficiently do it.

Let's say I have a block of ajax calls getting the API data in JSON format like so:

function createOrderStatuses(){
  var access_token = BCAPI.Helper.Site.getAccessToken();
  $.ajax({
      url: "/webresources/api/v3/sites/current/orderstatuses",
      type: "GET",
      connection: "keep-alive",    
      contentType: "application/json",
      headers: APIauthorization,
      success: function (status) {
      console.log(status);
       $.each(status.items, function(items, statuses){
         var statusTemplate = '<ul class="large-12 columns margin-distributed statusClass" id="'+ statuses.id +'"><h4 class="lato-bold">' + statuses.label  + '</h4></ul>';
         var changeSelection = '<select class="orderCurrentStatus"><option selected value="'+statuses.id+'">'+status.label+'</option></select>';
        if (statuses.label !== "EXCHANGE FEE PAID"){
         $("#ordersContainer").append(statusTemplate);
         $("#ordersContainer li span.changeStatus[id="+statuses.id+"]").append(changeSelection);
        }
       });
   }
  });

Then I am creating my orders like so:

function getOrders(){  
  var dateFrom = appSettings.dateFrom+"T00:00:00";
  var dateTo =  appSettings.dateTo+"T00:00:00";
   var orderData;
   $.ajax({
      url: '/webresources/api/v3/sites/current/orders?fields=id,entityId,categoryId,statusTypeId,discountCodeId,paymentMethodTypeId,taxCodeId,giftVoucherId,assignedUserId,name,countryCode,shippingPrice,shippingTaxRate,discountRate,giftVoucherAmount,totalPrice,shippingDescription,shippingAttention,shippingInstructions,quote,invoiced,invoiceNumber,invoiceDate,createDate,lastUpdateDate,destinationAddressIsResidential,isIntermediate,shippingRateKey,status,discountCode,workflow,customer,company,taxCode,assignedUser&skip=0&limit=500&order=-invoiceNumber&where={"createDate":{"$gte":"'+dateFrom+'"},"invoiceDate":{"$lte":"'+dateTo+'"}}',
      type: "GET",
      connection: "keep-alive",    
      contentType: "application/json",
      headers: APIauthorization,
      success: function (orders) {
      console.log(orders);
         orderData = orders;
      
       $.each(orders.items, function(order){
        
        var createDate = new Date(order.invoiceDate);
        var orderTemplate = 
             '<li class="f-16 expanded callout medium-collapse mid-gray-bg ordersList"><span class="large-4 medium-4 small-12 columns ordername"><i class="fa fa-file-text-o"></i> <a class="gray" href="https://bestkilts.worldsecuresystems.com/CRM/OrderDetailsv2.aspx?EntityID='+order.entityId+'&EntityType=1001&OrderID='+order.id+'"> '+ order.name+"/"+order.countryCode+'</a></span><span class="large-2 medium-2 small-4 columns date center">'+ createDate.getFullYear() + "-" + ("0" + (createDate.getMonth() + 1)).slice(-2) + "-" + ("0" + createDate.getDate()).slice(-2) +'</span><span class="large-1 medium-2 small-4 columns amount center">£'+order.totalPrice+'</span><span class="large-1 medium-1 small-4 columns invoice center">'+order.invoiceNumber+'</span><span class="large-2 medium-2 small-6 columns action center f-12">'+order.lastUpdateDate+'</span><span class="large-2 medium-3 small-6 columns action center changeStatus" id="'+order.statusTypeId+'"></span></li>';   
        if(orders){
         $("#ordersContainer .statusClass[id="+order.statusTypeId+"]").append(orderTemplate);
         var invoicesCounter = $('.ordersList').length;
         $("#ordersCount").text(invoicesCounter);
        }
         return "order";
       });
   }
  });// getOrders retrieve

But if I want to get a value/data from getOrders();, e.g. order.id passed into a new function getCustomers() and use to compile the whole thing as one result I can't get about doing it!?

function getCustomers(order){
    var orderInfo = getOrders();
    $.ajax({
            url: '/webresources/api/v3/sites/current/orders/'+orderInfo.id+'?fields=status,discountCode,workflow,customer,taxCode', //NEED THE ID FROM ORDERS HERE
            type: "GET",
            connection: "keep-alive",    
            contentType: "application/json",
            headers: APIauthorization,
            success: function (customer) {
            console.log(customer);
              var orderCustomer = "" ;
             $.each(customer.items, function(customer){
              orderCustomer = customer;  
            $("#ordersContainer").prepend('<span> class="customer">"'+orderCustomer.name+'"</span>');
                 });
             }
            });// get customer name for order       
}
getCustomers();

Conclusion collecting the information from different requests and try to use them in one single result is getting anywhere, I need a solution where I can get all the data from the 3 functions/calls or more if comes to happen! And create an orderDeployment() function combining all the data from the 3 into the ordersContainer.

How can I do this?

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Ricardo Alves
  • 561
  • 1
  • 5
  • 21

1 Answers1

2

$.ajax() returns a jqXHR (jQuery superset of XMLHttpRequest) object which implements the jQuery Promise interface (see Deferred object for more information).

I don't know if you are familiar with the concept of Promise, but even if jQuery has its own implementation of Promise, the definition from MDN documentation is also valid for jQuery implementation:

The Promise object is used for asynchronous computations. A Promise represents a value which may be available now, or in the future, or never.

So you can use:

  • .then() to chain asynchronous operations
  • $.when() if you need to wait for the result of multiple asynchronous operations before proceeding, eg.
$.when($.ajax('/page1.php'), $.ajax('/page2.php')).done(function(a1, a2){
    // eg. Perform another $.ajax call based on the results a1 and a2
});

Simple example, where a list of users is loaded first, then the posts of each user are retrieved based on the user id:

var root = 'https://jsonplaceholder.typicode.com';
   
// Returns 10 users
function getUsers() {
  return $.ajax({
    url: root + '/users',
    method: 'GET'
  });
}

// Returns posts based on user id
function getUserPosts(userId) {
  return $.ajax({
    url: root + '/posts?userId=' + userId,
    method: 'GET'
  });
}

// Once users list is retrieved, we can fetch posts for each users 
getUsers().then(function(users) {
  console.log('Users retrieved from API:', users);
  $.each(users, function(i, user) {
    getUserPosts(user.id).then(function(posts) {
      console.log('Posts fetched for user', user.name, posts);
    });
  });
});
<script
  src="https://code.jquery.com/jquery-3.1.1.min.js"
  integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
  crossorigin="anonymous"></script>
rd3n
  • 4,440
  • 1
  • 33
  • 45
  • Promises are definitely the way to go, but jQuery's implementation [has serious and inherent problems](http://stackoverflow.com/a/23744774/2014893) (prior to jQuery 3.0, at least.) Very easy to be caught out, especially for those new to Promises. – Robert K. Bell Feb 13 '17 at 11:29
  • 1
    Thanks for your comment @RobertK.Bell, I updated the code snippet to use at least latest jQuery version. I totally agree that using native Promise is the way to go when possible, but as OP was using jQuery I provided a jQuery oriented answer. But of course, all of this can be achieved with ES6 fetch and Promises. – rd3n Feb 13 '17 at 13:13
  • Is this the best practice when calling different parts of a system API to be used/combined across the script? I was trying to use var orderDetails =""; $.ajax({url:/api/orders, type:GET, success: function (orders) { orderDetails = orders;} }); then I could use orderDetails.apidata quite everywhere but I am still not able to combine things properly would you say $.when and .then() still works better? – Ricardo Alves Feb 14 '17 at 00:23
  • I thought you were asking for a way to get data from multiple async operations, possibly needing the result of previous one(s) to get another, that's why $.Deferred and $.when are suitable. If you want a way to re-use the fetched data from the API, you can store them in memory in an object or use a persistent caching mecanism (sessionStorage, localStorage etc.). There is no obvious answer and depends on many factors (project structure, framework etc. you use) – rd3n Feb 14 '17 at 22:02