Вложенные циклы и новые дочерние элементы [дубликаты]

0

Я пишу простое приложение погоды и застрял с петлями. Идея состоит в том, чтобы получить погоду для небольшого массива местоположений и загрузить прогноз для каждого в свой собственный div. Здесь код пока:

$(function () {
    var z = ["location ID1", "location ID2", etc.];
    var n = ["location name1", "location name2", etc];
    for (j = 0; j<z.length; j++) {
        weatherQuery = 'SELECT * FROM rss WHERE url="http://xml.weather.yahoo.com/forecastrss/' + z[j] + '_c.xml"';
        $('#weatherData').append($('<div/>', {id: 'c' + j}));
        $('#c' + j + '').append('' + n[j] + '');
        var weatherUrl = 'http://query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent(weatherQuery) + '&format=json';
        $.getJSON(weatherUrl + '&callback=?', function (data) {
            var weatherForecasts = data.query.results.item.forecast;
            for (i=0; i<weatherForecasts.length; i++) {
                var code = weatherForecasts[i].code;
                $('#c' + j + '').append('<table style = border:none><tr><td class = weather-date>' + weatherForecasts[i].day + '</td><td class = weather-icon style = background-position:-' + (61 * code ) + 'px 0px></td><td class = weather-min>' + weatherForecasts[i].low + '°</td><td class = weather-max>' + weatherForecasts[i].high + '°</td></tr></table>');              
            } 
        });
    }
});

Насколько я могу сказать из Firebug, первая часть работает - восстанавливаются правильные данные о погоде, и новые divs создаются в родительском div. Правильные имена мест также добавляются к каждому из новых div. Если он падает, это добавление данных о погоде в каждый div. Каков правильный способ идентифицировать дочерний div во втором (последнем) заявлении append, чтобы была одна итерация цикла синтаксического анализа погодных данных для каждого div? Благодарю.

Теги:
for-loop
nested-loops

1 ответ

1
Лучший ответ
for (j = 0; j<z.length; j++) {
    $.getJSON(..., function (data) {
        $('#c' + j + '').append(...

Цикл выполняет z.length раз, запуская z.length AJAX-запросы и заканчивая с j, равным z.length завершающему цикл.

Затем, намного позже (потому что "A в AJAX означает" асинхронный "), запросы завершаются, и каждая из функций обратного вызова вызывается. Они используют j чтобы выбрать, к какому div добавить свои результаты. Но j все еще z.length поскольку он вернулся, когда цикл закончен. Создание функции с закрытием по переменной не означает, что значение переменной запоминается с точки, в которой была создана функция; каждая функция имеет ссылку на тот же j.

(На самом деле у вас нет закрытия вообще, потому что переменные цикла j и i не объявлены var, поэтому они являются случайными глобальными переменными.)

Вы можете вспомнить значение локальной переменной при создании функции, обернув ее в отдельную функцию с этой переменной в (или используя function.bind в ECMAScript 5). Простым способом сделать это является использование цикла на основе обратного вызова, а не for:

var places = [
    {id: 'location1', name: 'Location One'},
    ...
];

$.each(places, function(place_i, place) {
    var yql = 'SELECT * FROM rss WHERE url="http://xml.weather.yahoo.com/forecastrss/' + encodeURIComponent(place.id) + '_c.xml"';
    var div = $('<div/>').attr('id', 'c'+place_i)).text(place.name);
    $('#weatherData').append(div);

    $.ajax({
        url: 'http://query.yahooapis.com/v1/public/yql',
        data: {q: yql, format: 'json'},
        dataType: 'jsonp'
    ).done(function(json) {
        var forecasts = data.query.results.item.forecast;
        var table = $('<table style="border: none">'); // prefer class/stylesheet
        $.each(forecasts, function(forecast_i, forecast) {
            table.append($('<tr>').append(
                $('<td class="weather-date">').text(forecast.day)
            ).append(
                $('<td class="weather-icon">').css('background-position', forecast.code*-61 + 'px 0')
            ).append(
                $('<td class="weather-min">').text(forecast.low+'°')
            ).append(
                $('<td class="weather-max">').text(forecast.high+'°')
            ));
        });
        div.html(table);
    });
});

заметки:

  • используйте автоматическое преобразование параметров данных jQuery, чтобы избежать необходимости называть encodeURIComponent вручную по URL-адресу JSON.

  • избегайте склеивания содержимого HTML из строковых переменных. Он не подходит для специальных символов HTML и может создавать проблемы безопасности (XSS). Для настройки текстового содержимого используйте jQuery text().

  • вам, вероятно, вообще не нужно указывать элемент id если вы сохраните ссылку на него в переменной JS, как это.

  • 0
    Спасибо! Это работает (и является ценным уроком) - мне просто нужно было сделать 2 изменения: 1. Добавить a } в конце функции ajax и переключить div.html(table) на div.append(table) чтобы избежать имена удаляются при загрузке данных json.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню