2013-09-10 4 views
0

Извиняюсь за количество кода, но я думаю, что это действительно проблема с функцией getCurrentLocation AppMobi. В основном, что происходит, я передаю событие крана каждому элементу списка. Затем, когда вы нажимаете на него, он запускает асинхронный getCurrentLocation и обновляет некоторые вещи. Затем при следующем нажатии на другой элемент списка переменные, связанные с обратным вызовом функции getCurrentLocation, относятся только к первому вызову. Почему это не работает?Переменные привязаны к обратному вызову функции getCurrentLocation. Почему это закрытие не работает?

app = { events: [{text: "foo", time: new Date()}, {text: "bar", time: new Date()}] }; 
$(document).ready(refreshEvents); 

function refreshEvents() { 
    for (var index in app.events) { 
     insertEventHTML(app.events[index]); 
    } 
} 

function insertEventHTML(event) { 
    var text = event.text; 
    var time = event.time; 

    var new_element = $('<li class="event_element"></li>'); 
    var new_checkin_element = $('<div class="check_in_button"></div>'); 

    new_checkin_element.bind('tap', function(e) { 
     check_in(e); 
     fade($(this), 1.0); 
    }); 
    new_element.append(new_checkin_element); 

    var text_element = $('<div class="text_element">' + text + '</div>'); 
    new_element.append(text_element); 
    var time_element = $('<div class="time_element">' + time + '</div>'); 
    new_element.append(time_element); 
    $('#your_events').append(new_element); 
} 

function check_in(e) { 
    $(e.target).siblings('.time_element').text('just now'); 
    var time = new Date();     // time and event_index are the trouble variables here 
    var event_index = getEventIndex(e);  // the first time this function runs, event_index is correct 
              // then each subsequent time, it remains the same value as the first 
    if (!app.settings.use_location) { 
     app.events[event_index].times.unshift({time: time, location: null}); 
    } else { 
     AppMobi.geolocation.getCurrentPosition(onLocationFound, errorFunction); 
    } 

    function onLocationFound(response) {  
     var lat = response.coords.latitude; 
     var lon = response.coords.longitude; 
     var last_time = app.events[event_index].times[0]; 

     if (last_time != undefined && last_time.time == time) { 
      // event_index and time here will only ever refer to the first time it was called. WHY??? 
      add_checkin(response, event_index, time);   
     }else{ 
      console.log('onLocationFound was called twice'); 
     } 
    } 

    function errorFunction(error) { 
     $.ui.popup({title: 'geolocation error', message: 'Geolocation error. Turn off location services in settings.'}); 
    } 

    function add_checkin(response, event_index, time) { 
     // and then of course event_index and time are wrong here as well. I don't get it. 
     app.events[event_index].times.unshift(
     { 
      time: time, 
      location: { 
       latitude: response.coords.latitude, 
       longitude: response.coords.longitude 
      } 
     }); 
     AppMobi.cache.setCookie('app', JSON.stringify(app), -1); 
    } 
} 

function getEventIndex(e) { 
    var target = $(e.target).parent(); 
    var siblings = target.parent().children('li'); 
    for (var i = 0; i < siblings.length; i++) { 
     if ($(target)[0].offsetTop == $(siblings[i])[0].offsetTop) { 
      return i; 
     } 
    } 
} 
+0

Какие переменные вы говорите? Я думаю, что совершенно нормально, что вы всегда получаете тот же результат от 'getCurrentPosition', если вы не перемещаете устройство. – plalx

+0

@plalx переменные геолокации одинаковы, да. но element_index нет. это элемент, который был использован. он всегда думает, что это был первый элемент, который был использован. –

+0

, а первым элементом i называется первый, который был использован. это может быть любой из них. –

ответ

1

Ну, ваша проблема, кажется, что вы объявляете приватную переменную event_index внутри функции check_in и попытаться решить его значение путем доступа к глобальной переменной внутри event_indexonLocationFound.

Вот то, что вы могли бы сделать вместо:

AppMobi.geolocation.getCurrentPosition(function (response) { 
    onLocationFound(response, event_index); 
}, errorFunction); 

function onLocationFound(response, event_index) { //... } 

EDIT:

он объявлен в check_in ...

Вы правы, я полностью пропустил что-то. В этом случае маловероятно, что переменная event_index внутри onLocationFound не такая же, как в check_in. Сделайте console.log(event_index) внутри onLocationFound, и он должен быть таким же. Единственный способ, которым это может быть другим, - это изменить локальную переменную до вызова обработчика, что вам кажется неэффективным, или если getCurrentPosition каким-то образом сохраняет первый обработчик и игнорирует последующие обработчики, но этот API не будет делать никаких смысл.

EDIT 2:

Как мы подозреваем, что обработчик не может быть правильно зарегистрирован во второй раз, я хотел бы предложить, чтобы проверить этот путь:

function check_in() { 
    if (!check_in.called) { 
     check_in.called = true; 
     check_in.onLocationFound = onLocationFound; 
    } 

    //... 

    function onLocationFound() { 
     console.log(arguments.callee === check_in.onLocationFound); 
    } 
} 

Вы можете также просто сделать onLocationFound.version = new Date() и проверить arguments.callee.version на посмотрите, останется ли он прежним.

+0

. Он не имеет доступа к глобальному, хотя он обращается к event_index, который перечитывается в check_in каждый раз. правильно? Ваш код создает ту же проблему :( –

+0

@ ThePuma Как функция 'onLocationFound' будет обращаться к частной переменной, объявленной в' check_in'? Это просто невозможно. Функция 'onLocationFound' должна быть объявлена ​​в' check_in' для создания закрытия это то, что мой ответ делает, это создает промежуточную функцию обработчика в 'check_in', так что в обработчике доступно' event_index' и передает значение 'event_index' в' onLocationFound'. – plalx

+0

объявляется в check_in. .. –

1

Я знаю, что вы уже ответили на это, но ... это может быть не проблема с библиотекой. Могу ли я направить вас к сообщению @Joel анаир, где он разместил статью и пример номер пять, кажется, в «Гоча», который может иметь Гоча;)

How do JavaScript closures work?

В основном в течение цикла они все установлены на одну и ту же ссылку i, так что event_index будет одинаковым значением/ссылкой. (что объясняет, почему они все одинаковые).

+0

Вы правы. Я не могу поверить, что мне потребовалось много времени, чтобы заставить его работать правильно. Функция обратного вызова была установлена ​​на исходные переменные. Очень сложно. –

+0

@ ThePuma, вы уверены, что он прав? Это кажется неправильным. Я очень хорошо понимаю закрытие и, если я не пропустил что-то в вашем коде, я действительно не вижу, где это может быть проблемой. – plalx

+0

@plalx я думаю, что он есть. Мне показалось, что я тоже хорошо разбираюсь в закрытии, но, видимо, это нас подтолкнуло. Я смог изменить свой код, чтобы он работал без использования семафора. Функция обратного вызова для getCurrentPosition определяется с исходной переменной, с которой она вызывается. Мне пришлось сделать функцию обратного вызова, чтобы она вернулась в область новых переменных. –

 Смежные вопросы

  • Нет связанных вопросов^_^