Home > other >  How to sort object by key value in javascript?
How to sort object by key value in javascript?

Time:07-30

I'm making a code to fetch content from contentful using AJAX. I've success retrieve data and display it, but something is not quite what I want. Because the content that I get is not in the same order as the contentful cms, so I add another field called sequence. So in my code I added a sort() and Object.keys() function before forEach(), but there is no error and data not appears ,does anyone know why data not appears?

If you want to try debugging, you can look at This Codepen.

function renderContentBySection(sectionName, appendElement, numberOfSkeleton, elementAttribute, elementClass){
  $.ajax({
    url : 'https://cdn.contentful.com/spaces/r5mgd95bqsb5/environments/master/entries/1bI13SpZBBvgOgIk4GhYEg?access_token=CVel_r57GUqeTeaLyIsseXEAM1z1f-spXNKR-a2-huA',
    type: 'GET',
    success: function(data){
      const getData = data.fields

      if(getData[sectionName]) {
        if(getData[sectionName] && getData[sectionName].length) {
          getData[sectionName].forEach((item, index) => {
            getSingleEntry(item.sys.id)
          });
        }
      }
    }
  });
}

function getSingleEntry(contentId){
  $.ajax({
    url : `https://cdn.contentful.com/spaces/r5mgd95bqsb5/environments/master/entries/${contentId}?access_token=CVel_r57GUqeTeaLyIsseXEAM1z1f-spXNKR-a2-huA`,
    type: 'GET',
    success: function(dataKat){
    
      getAssetData(dataKat.fields.image.sys.id, dataKat.fields.sequence)

      $('.data-banner').append(JSON.stringify(dataKat.fields, null, 4))
      $('.data-banner').append('<br>');
    }
  });
}

function getAssetData(assetsId, sequenceId){
  $.ajax({
    url : `https://cdn.contentful.com/spaces/r5mgd95bqsb5/environments/master/assets/${assetsId}?access_token=CVel_r57GUqeTeaLyIsseXEAM1z1f-spXNKR-a2-huA`,
    type: 'GET',
    success: function(getAssetsData){
      
      $('.data-image').append(JSON.stringify(getAssetsData.fields, null, 4))
      $('.data-image').append('<br>');
    }
  });
}

$(document).ready(function(){
  renderContentBySection('mainBannerImage', '#carousel-inner', 1, 'banner', 'main-banner-item');
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<pre >
  <h4>Get Data Main Banner:</h4>
</pre>
<br>
<pre >
  <h4>Get Data for Each Image in Main Banner:</h4>
</pre>

CodePudding user response:

Because your data is loaded asyncronously, you will need to create a queue of your requests, and listen for them to all finish.

I have commented my code below so you can understand how it works.

First, you need to use the spread operator a lot ..., to work with an unknown number of array elements. (https://stackoverflow.com/a/35169449/1410567)

Second, you need to use $.when(...array).done(function(...results) { to know when the requests have finished. (https://blog.kevinchisholm.com/javascript/jquery/using-jquery-deferred-to-manage-multiple-ajax-calls/)

Third, you need to use Array.sort() to sort the array of objects, comparing their sequence, and returning 1 or -1 to sort them. (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)

//create an empty array to hold the queue:
let allImageRequests = [];

function listenForImages() {
  //set up a listener for when all requests have finished, using "spread operator" (...) to send all requests as parameters to when():
  $.when(...allImageRequests).done(
    //done:
    function (...arrAllImagesResp) {
      let arrAllImages = [];
      console.log("arrAllImagesResp", arrAllImagesResp);

      arrAllImagesResp.forEach((e) => { 
        console.log(e);
        arrAllImages.push(e[0].fields);
      });;

      //all images loaded, sort:
      arrAllImages.sort((a, b) => (a.sequence < b.sequence ? -1 : 1));

      console.log("done", arrAllImages);

      //sorting done, display results:
      $('.data-image').append("\n\n<strong>All Images Sorted:</strong> \n\n"   JSON.stringify(arrAllImages, null, 4));
    }
  );
}

$.ajax({
    url: 'https://cdn.contentful.com/spaces/r5mgd95bqsb5/environments/master/entries/1bI13SpZBBvgOgIk4GhYEg?access_token=CVel_r57GUqeTeaLyIsseXEAM1z1f-spXNKR-a2-huA',
    type: 'GET',
    success: function (data) {
    console.log("got data", data);
    
        const getData = data.fields.mainBannerImage

        $('.data-banner').append(JSON.stringify(getData, null, 4))
        $('.data-banner').append('<br>');

        getData.forEach((item, index) => {
            //add requests to our queue:
            allImageRequests.push(getImageAssets(item.sys.id));
        });
    
        listenForImages();
    }
})

function getImageAssets(assetId) {
    //I added a return here, so the XHR objects will be push()'d to the allImageRequests queue array:
    return $.ajax({
        url: `https://cdn.contentful.com/spaces/r5mgd95bqsb5/environments/master/entries/${assetId}?access_token=CVel_r57GUqeTeaLyIsseXEAM1z1f-spXNKR-a2-huA`,
        type: 'GET',
        success: function (assetsData) {
            const getAssetsData = assetsData.fields

            $('.data-image').append(JSON.stringify(getAssetsData, null, 4))
            $('.data-image').append('<br>');
        }
    })
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<pre >
  <h4>Get Data Main Banner:</h4>
</pre>
<br>
<pre >
  <h4>Get Data for Each Image in Main Banner:</h4>
</pre>

CodePudding user response:

Because you completely changed the criteria, I will provide an answer for your second ask. I do expect you to vote up both answers and accept this one.

function listenForEntries(arrAllEntryRequests) {
    //set up a listener for when all requests have finished, using "spread operator" (...) to send all requests as parameters to when():
    $.when(...arrAllEntryRequests).done(
        //done:
        function (...arrAllEntryResponses) {
            let arrAllEntries = [];
            console.log("arrAllEntryResponses", arrAllEntryResponses);

            arrAllEntryResponses.forEach((e) => {
                console.log(e)
                arrAllEntries.push(e[0].fields);
            });;

            //all images loaded, sort:
            arrAllEntries.sort((a, b) => (a.sequence < b.sequence ? -1 : 1));

            console.log("done", arrAllEntries);

            //sorting done, get asset data for each. This is also asyncronous so you need to do the same thing as above:    
            let arrAllAssetRequests = [];

            arrAllEntries.forEach((entryData) => {
                console.log("entryData", entryData);

                $('.data-sequence').append(`
                <ul>
                  <li>
                    Sequence ID: ${entryData.sequence}<br>
                    Title Banner: ${entryData.title}
                  </li>
                </ul>`)
                
                let assetReqObj = getAssetData(entryData.image.sys.id, entryData.sequence);
                arrAllAssetRequests.push(assetReqObj);

            });

            listenForAssets(arrAllAssetRequests);
        }
    );
}

function listenForAssets(arrAllAssetRequests) {
    $.when(...arrAllAssetRequests).done(
        //done:
        function (...arrAllAssetResponses) {
            //all assets loaded, sort:
            arrAllAssetResponses.sort((a, b) => (a[2].sequence < b[2].sequence ? -1 : 1));

            arrAllAssetResponses.forEach((assetData) => {
                console.log("assetData", assetData);

                if(assetData.length > 0) {
                    $('.data-assets').append(`
                    <ul>
                    <li>
                        Sequence ID: ${assetData[2].sequence}<br>
                        Title Banner: ${assetData[0].fields.title}<br>
                        <img  src="${assetData[0].fields.file.url}">
                    </li>
                    </ul>`);
                } else {
                    console.error("Something wrong with assetData", assetData);
                }
            });
        }
    );
}

function renderContentBySection(sectionName, appendElement, numberOfSkeleton, elementAttribute, elementClass) {
    $.ajax({
        url: 'https://cdn.contentful.com/spaces/r5mgd95bqsb5/environments/master/entries/1bI13SpZBBvgOgIk4GhYEg?access_token=CVel_r57GUqeTeaLyIsseXEAM1z1f-spXNKR-a2-huA',
        type: 'GET',
        success: function (data) {
            const getData = data.fields

            //move array to inside this function as it's the only place it will be used:
            let arrAllEntryRequests = [];

            if (getData[sectionName]) {
                if (getData[sectionName] && getData[sectionName].length) {
                    getData[sectionName].forEach((item, index) => {
                        arrAllEntryRequests.push(getSingleEntry(item.sys.id));
                    });

                    //once array of requests is created, listen for it to finish:
                    listenForEntries(arrAllEntryRequests);
                }
            }
        }
    });
}

function getSingleEntry(contentId) {
    return $.ajax({
        url: `https://cdn.contentful.com/spaces/r5mgd95bqsb5/environments/master/entries/${contentId}?access_token=CVel_r57GUqeTeaLyIsseXEAM1z1f-spXNKR-a2-huA`,
        type: 'GET',
        success: function (dataKat) {
            //do nothing            
        }
    });
}

function getAssetData(assetsId, sequenceId) {
    let $xhr = $.ajax({
        url: `https://cdn.contentful.com/spaces/r5mgd95bqsb5/environments/master/assets/${assetsId}?access_token=CVel_r57GUqeTeaLyIsseXEAM1z1f-spXNKR-a2-huA`,
        type: 'GET',
        success: function (assetData) {
            //do nothing
        }
    });

    $xhr.sequence = sequenceId; //store the sequence for later

    return $xhr;
}

$(document).ready(function () {
    renderContentBySection('mainBannerImage', '#carousel-inner', 1, 'banner', 'main-banner-item');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div >
  <div >
    <div >
      <div >
        <span> This is sequence data:</span>
      </div>
    </div>
    <div >
      <div >
        <span> This is assets data:</span>
      </div>
    </div>
  </div>
</div>

  • Related