xeditable使用函数选择源,使用deffered和本地存储(indexedDB)



我正在为我工作的公司开发一个web应用程序,但我对所需的表单有问题。

我在使用xeditable用来自不同函数的数据填充选择列表时遇到了一些问题。

问题是,即使我使用的是deffered,为填充选择框而执行的代码也不会等待其他函数从本地存储中获取数据并返回(我不确定我是否正确使用了deffered/resolve功能)。

这是我的代码:

<a id="TypeID" data-type="select" data-pk="1966_TypeID" data-original-title="Please Select" data-pid="36" class="editable editable-click">3609</a>

jquery:

function popSelectBox(PID) {
    var rtn = [];
    $.indexedDB('testDatabase').objectStore('Lookup').index('PID').each(function (i) {
        var source = {};
        source.value = i.value.ID;
        source.text = i.value.Name;
        rtn.push(source);
    }, PID).done(function (r, e) {
        console.log(rtn);
        console.log('popSelectBox function (I expect to see this first) - This section should complete before the makeEditable function');
        return rtn;
    });
}
function makeEditable() {
    $('.editable').editable({
        validate: function (value) {
            if ($.trim(value) === '') {
                return 'This field is required';
            }
            return false;
        },
        success: function (response, newValue) {
            console.log($(this).data('pk'), newValue);
            //$(this).parent().css('background-color', 'green');
        },
        /**** this is the problem section of this function ****/
        source: function () {
            //if the type is a select list then we need to populate it, this is done here
            if ($(this).data('type') === 'select') {
                var d = $.Deferred();
                $.when(d).done(function (v) {
                    console.log(v);
                    return v;
                });
                d.resolve(popSelectBox($(this).data('pid').toString()));
                console.log('makeEditable function (I expect to see this last) - This section should wait for the popSelectBox function to finish');
            }
        }
    });
}

我这里还有一把小提琴http://jsfiddle.net/f8otrayn/3/显示了以上内容。这个fiddle中包括一个我正在使用的本地存储设置示例,用于设置的函数已经存在,但是我已经注释掉了函数调用,如果你愿意,你可以检查代码并取消注释。

我正在寻找一种方法,等待popSelectBox函数完成并返回数据,这样我就可以使用这些数据来填充选择框,我真的不想使用setTimeout,因为本地存储中有很多条目,所以等待特定的时间段可能在所有情况下都不起作用。

有人有什么想法吗

感谢

最后,我们不得不采用不同的方法,而不是在最初构建表单时添加功能,而是将功能添加到点击事件中

x-editable仍然无法从函数中填充源,因此按照建议运行代码(在范围内)以从IndexedDB中获得正确的值,并添加结果数组作为源

以下代码供参考

$( document ).on('click', '.editable-select', function(){
    var arr = [];
    $.indexedDB( 'testDatabase' ).objectStore( 'Lookup' ).index( 'PID' ).each( function( i ) {
        if (i.value.Act === '1') {
            arr.push({
                value: i.value.ID,
                text:i.value.Name
            });
        }
    },$(this).data( 'pid' ).toString()).done( function( r, e ){
        //
    });
    /** setting the options has changed **/
    $(this).editable('option', 'source', arr);
    $(this).editable('option', 'success', function(response, newValue) {
        console.log($(this).data('pk'), newValue);
    });
});

您会注意到,设置可编辑选项已经更改,以这种方式设置源:

$('.editable').editable({
    validate: function() {...}),
    success: function() {...}),
    source: function() {
        return arr;
    }
});

由于某些原因不起作用

从jquery indexeddb文档中,我发现它的promise有.done().fail().progress()方法,但令人惊讶的是,没有.then()方法。

这意味着jquery indexeddb的promise没有.then()提供的过滤能力,并且(除非indexeddb有一些深不可测的特性)不可能返回所需数组的promise。因此,我们必须编写通常被归类为"延迟反模式"的内容。

popSelectBox()将是这样的:

function popSelectBox(PID) {
    var arr = [],
        dfrd = jQuery.Deferred();
    $.indexedDB('testDatabase').objectStore('Lookup').index('PID').each(function(i) {
        arr.push({
            value: i.value.ID,
            text: i.value.Name
        });
    }, PID).done(function() { // not too sure about `PID` here
        dfrd.resolve(arr);
    }).fail(dfrd.reject);
    return dfrd.promise();
}

.editable(...)插件中,如果source选项是一个函数,那么它必须返回popSelectBox()承诺的值(数组),但重要的是,它不能返回承诺本身。因此,在makeEditable()中寻求的模式的基本特征是(对于选择元素)首先调用popSelectBox(),然后调用.editable(...)以响应返回的promise的解析。

这有效地将makeEditable()中的当前代码从内向外翻转,具有:

  • 最外层:测试每个元素是否是<select>,并在适当的时候调用popSelectBox()
  • 最内层:对.editable()的调用

代码可以用多种方式编写,其中最简单的(IMHO)是这样的:

function makeEditable() {
    var promises = $('.editable').map(function() {
        var $that = $(this),
            promise;
        if ($that.data('type') === 'select') {
            promise = popSelectBox($that.data('pid').toString());
        } else {
            promise = $.when(); //dummy, ready-resolved promise.
        }
        return promise.then(function(arr) {
            $('.editable').editable({
                validate: function() {...}),
                success: function() {...}),
                source: function() {
                    return arr || null; //assume it's safe to return null here for elements that are not selects.
                }
            });
        });
    });
    return $.when.apply(null, promises); //return a promise that will be resolved when all '.editable' elements have been initialized.
}

通过返回完成承诺,调用makeEditable()的函数可以在必要时在所有元素都可编辑时执行某些操作。