Получить заголовок из JSON

Я застрял!.. У меня есть сценарий jQuery, в котором я заполняю галерею изображений из файла JSON, это что-то вроде лайтбокса. Но я хочу иметь название для своих изображений, поэтому я создал второй файл JSON, в котором я просто сохраняю имя изображения и заголовок. Я хочу в цикле проверить второй JSON, есть ли там имя изображения, и если да, вернуть текст, который является заголовком...

Это 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"}
]

Что я хочу сделать, так это просмотреть все изображения, заполнить галерею и в то же время, ЕСЛИ имя изображения присутствует в titles.json, поместить этот заголовок в цикл.

Это jQuery, который заполняет галерею. он вызывает функцию с именем GetTitle(имя изображения,папка)

   //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.info('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>');
                });
            });
        });

Это функция, которая должна сопоставлять имя изображения из цикла и возвращать заголовок.

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.info(zTitle)
    return zTitle
});
}

Как бы я ни старался, я не могу сделать это правильно. Я почти решил проблему, когда поместил код внутри функции в цикл, но затем он повторил его и вместо этого создал дубли изображений в галерее.

Этот вопрос похож на: Как вернуть значение из функции, которая вызывает $.getJSON?. Если вы считаете, что это другое, отредактируйте вопрос, поясните, чем он отличается и/или как ответы на этот вопрос не помогают решить вашу проблему.

JoSSte 29.06.2024 18:05
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
1
136
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Кажется, на Stackoverflow уже есть ответ на вашу проблему. Вы можете использовать обратный вызов (вы передаете функцию в качестве параметра своей функции и вызываете функцию обратного вызова с параметром заголовка вместо возврата заголовка). В противном случае вы можете использовать обещание, но вам нужно будет использовать асинхронность.

Пример обратного вызова:

function GetTitle(a, z, callback) {
  $.getJSON("BKND/Galleries/" + z + "/titles.json", (adata) => {
    // Handle the JSON data here
    let zTitle = " ";
    $.each(adata, function (_, value) {
      if (value.Img == a) {
        zTitle = value.title;
      }
    });

    callback(zTitle);
  });
}

И как его использовать:

GetTitle(element.imageName, zGallery, (title) => {
    console.info(title)
})
Ответ принят как подходящий

(Это серьезное переписывание моего ответа — предыдущие версии этого поста вы можете найти здесь.)

Ваша первоначальная попытка включала бы частые вызовы $.getJSON('BKND/Galleries/'+z+'/titles.json) (по крайней мере, один вызов для каждого изображения в вашей галерее), чтобы получить заголовки. Лучшим подходом было бы получить информацию один раз и сохранить ее в словаре. Ниже я подготовил небольшую демонстрацию, основанную на общедоступных данных, имитирующую очень простую галерею:

$.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>

Обновление в ответ на сообщение «ответ» ОП:

Вы можете использовать опцию async:false в вызове Ajax, но это создаст негативный пользовательский опыт. Браузер фактически зависает во время получения данных.

Тем не менее, я взял ваш код и кое-где подправил его, чтобы он работал. В демо-версии в качестве общедоступного источника данных используется https://dummyjson.com.

(( Я бы по-прежнему рекомендовал вам использовать конструкцию $.when(...).then(), как показано в моем фрагменте выше. ))

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.info(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>

Помимо отказа от использования async:false, я бы также рекомендовал вам заменить частые .append() звонки одним .html() звонком. Таким образом, полная уценка HTML будет анализироваться и отображаться браузером только один раз, вместо повторной обработки страницы для каждого отдельного изображения.

Я не удержался и написал версию async с $.when(...).then(), см. ниже:

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>

Да!! На самом деле это были мои мысли, когда я пытался решить эту проблему... зачем мне снова и снова обращаться ко второму JSON, это не казалось хорошей идеей. Я сделал именно то, что вы предложили. Вместо этого я сохранил JSON в переменной. и пытаются получить доступ к этой переменной, когда я перебираю изображения.. НО!. как мне получить доступ к другой части переменной... я проверил ее, и это действительно массив JSON... но я просто хочу сравнить имя изображения, а затем извлечь заголовок -

Wyrm 30.06.2024 15:02

Я действительно очень близок..... !!! Мне пришлось изменить ваш ответ, но я получаю все имена изображений в качестве ключей. там просто написано, что все неизвестны,,,

Wyrm 30.06.2024 22:44

посмотрите мой вставленный код здесь: Pastecode.dev/s/n53rrgqd

Wyrm 30.06.2024 22:47

В getTitle() вы совершаете классическую ошибку, возвращая (и используя) переменную cArray до того, как она получит свое содержимое в обратном вызове вашего $.ajax() вызова. У меня была причина использовать конструкцию $.when(...).then()! 😉

Carsten Massmann 30.06.2024 23:08

Только сейчас я заметил, что вы установили свойство async: никогда не рекомендуется использовать async:false в вызове $.ajax(), так как это фактически заморозит браузер для ваших пользователей.

Carsten Massmann 30.06.2024 23:21

Причина, по которой ваш скрипт в Pastecode.dev не работает, заключается в том, что вы определяете переменную и ссылаетесь на нее Img, но никогда не инициализируете ее. И: пожалуйста, всегда публикуйте весь свой код во фрагменте кода в своем вопросе в Stackoveflow!

Carsten Massmann 30.06.2024 23:52

Спасибо @Carsten. Извините, я обычно не публикую много сообщений о переполнении стека, я просто использую его для чтения. Я постараюсь добавить ответ, включающий больше кода. Если бы вы могли посмотреть на это и увидеть, где я ошибаюсь. я отказался от доступа к файлу JSON для каждого изображения, чтобы загрузить его в переменную и работать с ней, так что я продвинулся гораздо дольше, чем когда начал.

Wyrm 01.07.2024 09:58

Спасибо, Карстен, теперь у меня все заработало. Я внес некоторые изменения после ваших заметок и снова изменил async на false, потому что, когда я проверял объект ttls, он был пуст. Я знаю, что async:false — это нехорошо, но, честно говоря, единственное, что происходит, — это то, что он читает JSON и помещает его в переменную, прежде чем перейти к циклу. Я постараюсь улучшить код, но мне нужно узнать больше о $.when.() $.then() еще раз спасибо.. теперь он работает именно так, как я и предполагал.

Wyrm 01.07.2024 16:10

Хорошо. Итак, вот как далеко я зашел.

function GetTitle(galleryFolder){

    // Handle the JSON data here  
       var cArray = []
        $.ajax({
            'async': false,
            'global': true,
            'url': 'BKND/Galleries/'+galleryFolder+'/titles.json',
            'dataType': "json",
            'success': function (data) {
                cArray = data
            }
        });

        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
        var Img //initilase Img?
        var ttls=Object.fromEntries(titlesArray.map(e=>[e.Img,e.title])); //convert JSON array to an object
        $.getJSON('JSON/Gallerys/'+zGallery+'.json', { get_param: 'value' }, (data)=>{  //Get the JSON with all the imagenames from backend
            $.each(data, function(index, element) { //loop through each imgagename and build the htmls structure inside the gallery div
                var Titles =`Title: ${element.imageName} is ${ttls[Img]?`"${ttls[Img]}"`:'unfortunately unknown'}.`
                                    
                $('.galpop-info').galpop();
                $("#dc_preload_image").preloader();    
                $('#dc_preload_image').append('<li><a class = "galpop-info" data-galpop-group = "info"  title = "'+Titles+'" 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>');
            });
        });
    });

Теперь все работает так, как я предполагал, я не бомбардирую файл JSON (вероятно, ускоряя процесс), а вместо этого работаю с ним как с объектом. все изображения обработаны (я проверил с помощью console.info), но я думаю, что с этой строкой что-то не так

$.each(data, function(index, element) { //loop through each imgagename and build the htmls structure inside the gallery div
            var Titles =`Title: ${element.imageName} is ${ttls[Img]?`"${ttls[Img]}"`:'unfortunately unknown'}.`

потому что все изображения возвращаются со строкой «к сожалению, неизвестно» Есть ли лучший способ сделать это, подскажите, пожалуйста, неосведомленному :)

Другие вопросы по теме