Search code examples
javascriptjqueryjson

get title from JSON


I am stuck!.. I have a jQuery script where i am populating a gallery of images from a JSON file, its like a lightbox type of thing. But i want to have a title to my images, so i have created a second JSON file where i just keep, image name, and title. I want to, in the loop, check the second JSON if the image name is there, and if it is, return the text that is the title...

This is the titles.json

[
    {"Img" : "fun1_001.jpg", "title" : "Title of image 001"},
    {"Img" : "fun1_002.jpg", "title" : "title of image 002"},
    {"Img" : "fun1_003.jpg", "title" : "title of image 002"}
]

What i want to do is to loop through all images, populate the gallery, and in the same time IF the image name is present in the titles.json, put that title in the loop.

This is the jQuery that populates the gallery. it calls a function named GetTitle(imagename,folder)

   //Load the gallery if you click the dropdown.
        $(document).on('click','#zmenu>div.item', function(){
            $('#dc_preload_image').empty();
            let zGallery=$(this).attr('data-value');
            $.getJSON('JSON/Gallerys/'+zGallery+'.json', { get_param: 'value' }, (data)=>{ 
                $.each(data, function(index, element) {
                console.log('anrop')
                    $('.galpop-info').galpop();
                    $("#dc_preload_image").preloader();    
                    $('#dc_preload_image').append('<li><a class="galpop-info" data-galpop-group="info"  title="'+GetTitle(element.imageName, zGallery)+'" href="BKND/Galleries/'+zGallery+'/pict/'+element.imageName+'"><img src="BKND/Galleries/'+zGallery+'/tmb/'+element.imageName+'" alt="'+element.imageName+'" id="'+element.imageName+'" class="corners" /></a></li>');
                });
            });
        });

This is the function that should match the image name from the loop and return the title.

function GetTitle(a,z){
    $.getJSON('BKND/Galleries/'+z+'/titles.json', (adata) => {
        // Handle the JSON data here  
        let zTitle         
    $.grep(adata, function(value) {
        if(value.Img = a){
            zTitle = value.title;
        }
        else{zTitle = " ";}
    });
    console.log(zTitle)
    return zTitle
});
}

No matter how i try, i cant get it right. i almost solved when i put the code inside function in the loop, but then it iterated through it and created doubles of images in the gallery instead.


Solution

  • (This is a major rewrite of my answer - you can find previous versions of this post here.)

    Your original attempt would involve frequent $.getJSON('BKND/Galleries/'+z+'/titles.json) calls (at least one call for each image in your gallery) to get the titles. A better approach would be to get the information once and store it in a dictionary. Below I prepared a little demo, based on publicly available data, mimicking a very basic gallery:

    $.when(
     $.getJSON("https://dummyjson.com/users/").then(d=>d.users.map(u=>u.username)),
     $.getJSON("https://dummyjson.com/users/").then(d=>Object.fromEntries(d.users.map(u=>[u.username,u.firstName+" "+u.lastName])))
    ).then((usrs,ttls)=>
       // Now we can build the gallery:
          $("#container").html(usrs.map(u=>
            `<img src="https://dummyjson.com/icon/${u}/128" title="${ttls[u]}">${ttls[u]}`
          ).join("<br>"))
    );
    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
    <div id="container"></div>

    Update, in response to OP's "answer" post:

    You can use the async:false option in an Ajax call but that will create a negative user experience. The browser will effectively freeze while it is receiving the data.

    Nonetheless, I have taken your code and tweaked it in some places to make it work. The demo uses https://dummyjson.com as a public data source.

    (( I would still recommend you to use the $.when(...).then() construct as demonstrated in my snippet above. ))

    function GetTitle(galleryFolder){
    // Handle the JSON data here  
       var cArray = []
        $.ajax({
            'async': false,  // **** Attention: this will block your page while the data is being retrieved! *****
            'global': true,
        //  'url': 'BKND/Galleries/'+galleryFolder+'/titles.json',
            'url': 'https://dummyjson.com/'+galleryFolder,
            'dataType': "json",
            'success': function (data) {
                cArray = data[galleryFolder].map(e=>({Img:e.image, title:e.name || e.firstName+" "+e.lastName })); // mimick the titles array ...
            }
        });
        return cArray;
    }
    
    //Ladda in galleriet om man väljer i listrutan.
    $(document).on('click','#zmenu>div.item', function(){ //When you click on dropdown with ID #zmenu
        $('#dc_preload_image').empty(); //initialize preloader
        let zGallery=$(this).attr('data-value'); //Get attr data-value from zmenu, to determine which folder you want to access
        let titlesArray = GetTitle(zGallery); //load JSON array into a variable
        ttls=Object.fromEntries(titlesArray.map(e=>[e.Img,e.title])); //convert JSON array to an object
        // console.log(ttls);return;
    //  $.getJSON('JSON/Gallerys/'+zGallery+'.json', { get_param: 'value' }, (data)=>{  //Get the JSON with all the imagenames from backend
        $.getJSON('https://dummyjson.com/'+zGallery, { get_param: 'value' }, (data)=>{  //Get the JSON with all the imagenames from backend
            // a little adjustment for my dummy data:
            data=data[zGallery];
            
            $.each(data, function(index, element) { //loop through each imgagename and build the htmls structure inside the gallery div
                element.imageName=element.image; // adjustement for my dummy data ... ;-)
                var title =`Title for ${element.imageName} is: ${ttls[element.imageName]?`${ttls[element.imageName]}`:'unfortunately unknown'}.`;
                $('#dc_preload_image').append('<li><a class="galpop-info" data-galpop-group="info"  title="'+title
                +'" href="BKND/Galleries/'+zGallery+'/pict/'+element.imageName+'"><img src="'+element.imageName+'" alt="'+element.imageName+'" id="'+element.imageName+'" class="corners" /></a></li>');
            });
            // the following expressions only need to be executed once - after the $.each() loop!
            //                           ========================================================
            // $('.galpop-info').galpop();
            // $("#dc_preload_image").preloader();    
        });
    });
    div.item { padding: 6px; margin:6px; display: inline-block; background-color: #ddd; 
               border: 1px solid #888; cursor:pointer }
    li img   {height: 100px}
    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
    <div id="zmenu">
    <div class="item" data-value="users">users</div>
    <div class="item" data-value="recipes">recipes</div>
    </div>
    <div id="dc_preload_image"></div>

    Apart from not using async:false I would also recommend you to replace the frequent .append() calls by a single .html() call. This way the complete html markdown will be parsed and rendered only once by the browser instead of the page being re-rendered for each individual image.

    I could not resist and wrote the async version with $.when(...).then(), see below:

    function GetTitle(galleryFolder){ // this function returns a "thenable" ...
      //               'BKND/Galleries/'+galleryFolder+'/titles.json'
      return $.getJSON('https://dummyjson.com/'+galleryFolder        )
              .then(data => data[galleryFolder].map(e=>({Img:e.image, title:e.name || e.firstName+" "+e.lastName }))) // mimick the titles array ...   
    }
    
    //Ladda in galleriet om man väljer i listrutan.
    $(document).on('click','#zmenu>div.item', function(){ // When you click on dropdown with ID #zmenu ...
        let zGallery=$(this).attr('data-value');                 // get gallery name
        $.when( // ***** read both .json files at the same time: *****
          GetTitle(zGallery).then(d=>d.map(e=>[e.Img,e.title])), // get titles and ...
          $.getJSON('https://dummyjson.com/'+zGallery).then(d=>d[zGallery].map(e=>e.image)) // image names. 
        ).then((ttlarr,imgs)=>{ // after the data has arrived in parallel streams, process it:
            const ttls=Object.fromEntries(ttlarr);               // convert array to lookup dictionary
            $("#dc_preload_image").html(imgs.map((img,i)=>       // create whole HTML markdown in one go
              `<li><a class="galpop-info" data-galpop-group="info" 
               title="Title for ${img} is: ${ttls[img]?`${ttls[img]}`:'unfortunately unknown'}"
               href="BKND/Galleries/'+zGallery+'/pict/${img}"><img 
               src="${img}" alt="${img}" id="${img}" class="corners"/></a>${ttls[img]}</li>`
            ).join("\n")); //.preloader() ;
            // $('.galpop-info').galpop();   
        });
    });
    div.item { padding: 6px; margin:6px; display: inline-block; background-color: #ddd; 
               border: 1px solid #888; cursor:pointer }
    li img   {height: 100px}
    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
    <div id="zmenu">
    <div class="item" data-value="users">users</div>
    <div class="item" data-value="recipes">recipes</div>
    </div>
    <div id="dc_preload_image"></div>