0

コード量が多くて申し訳ありませんが、これは実際には 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;
        }
    }
}
4

2 に答える 2

1

私はあなたがこれをすでに回答済みとしてマークしていることを知っていますが....実際にはライブラリの問題ではないかもしれません。@Joel Anair が記事を投稿した投稿にあなたを誘導できますか?

JavaScript クロージャーはどのように機能しますか?

基本的に for ループでは、それらはすべて同じ参照に設定されているiため、event_indexすべて同じ値/参照になります。(これは、なぜそれらがすべて同じであるかを説明しています)。

于 2013-09-10T08:11:10.017 に答える
1

さて、あなたの問題はevent_index、関数内でプライベート変数を宣言していて、内部のグローバル変数にcheck_inアクセスしてその値を解決しようとしているようです。event_indexonLocationFound

代わりにできることは次のとおりです。

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

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

編集:

check_in 内で宣言されています...

そうです、どういうわけかそれを完全に見逃していました。その場合、内のevent_index変数が 内の変数onLocationFoundと同じではない可能性はほとんどありませんcheck_inconsole.log(event_index)内部を行うonLocationFoundと、同じはずです。それが異なる可能性がある唯一の方法は、ハンドラーが呼び出される前にローカル変数を変更するか、またはgetCurrentPosition最初のハンドラーを何らかの方法で保存し、後続のハンドラーを無視する場合ですが、この API は意味がありません。 .

編集2:

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

于 2013-09-10T02:02:19.577 に答える