1

我有一个基于 Durandal JS 2.0 构建的应用程序,并使用了 John Papa 的 CodeCamper SPA 中的灵感部分。在其中一种形式中,我想要一个日期和时间选择器,所以我发现http://www.malot.fr/bootstrap-datetimepicker看起来不错并且满足我的需求。它使用带有自定义绑定处理程序的 Knockout JS 连接到数据层,并且也这样初始化。

请注意,控件在视觉上和数据工作得很好,而且看起来也不错。它更新数据模型和底层数据库就好了。除此 datetimepicker 外,所有其他标准控件都可以正常工作。

我的问题发生在组成 durandal 表单时,将 datetimepicker 插入到 DOM double 中。每次我打开表单时,选择器都会再次插入,加倍。过了一会儿,整个应用程序开始变慢,因为我在 DOM 中插入了大量的日期时间选择器。

我试图追踪发生这种情况的位置,并且每次初始化或重新初始化可观察对象时似乎都会发生这种情况。这发生在激活表单和检索数据时。这会触发 bindinghandler 运行并插入选择器的另一个实例。

我已经尝试了不同的方法来防止选择器被创建,但似乎没有任何效果。我试图对选取器进行 HTML 初始化,但是绑定处理程序在找到控件时遇到了问题。

因此,我一直认为问题在于我初始化底层可观察到的淘汰赛的方式,或者无法使用淘汰赛绑定处理程序初始化选择器。

对此的任何想法都将受到欢迎。

这是我的应用程序中的一些选定代码:

<div class="row-fluid ui-row">
    <div class="span2 ui-form-label">
        Start:
    </div>
    <div class="span3">
        <form class="form-inline">
            <div id="actystartdate" class="controls input-append date">
                <input class="ui-input ui-edit input-small" type="text" data-bind='datetimepicker: startTime, datetimepickerOptions: { language: "sv", pickerPosition: "bottom-left", format: "yyyy-mm-dd", weekStart: 1, todayBtn: 1, autoclose: 1, todayHighlight: 1, startView: 2, minView: 2 }' disabled readonly><span class="add-on ui-input ui-edit ui-nonedit"><i class="icon-calendar"></i></span>
            </div>
            <div id="actystarttime" class="controls input-append date">
                <input class="ui-input ui-edit input-mini" type="text" data-bind='datetimepicker: startTime, datetimepickerOptions: { language: "sv", pickerPosition: "bottom-left", format: "hh:ii", autoclose: 1, startView: 1, minView: 0, maxView: 1, minuteStep: 15 }' disabled readonly><span class="add-on ui-input ui-edit ui-nonedit"><i class="icon-time"></i></span>
            </div>
        </form>
    </div>
</div>

淘汰赛绑定处理程序:

    ko.bindingHandlers.datetimepicker = {
        init: function (element, valueAccessor, allBindingsAccessor) {
            var options = allBindingsAccessor().datetimepickerOptions || {};
            $('#' + element.parentNode.id).datetimepicker(options);

            //when a user changes the date, update the view model
            ko.utils.registerEventHandler(element, "change", function () {
                var value = valueAccessor();
                if (ko.isObservable(value)) {
                    // Separate and merge date and time portions
                    if (Date.parse(element.value)) {
                        // We have an incoming date, merge with stored time and update
                        var incDate = new Date(element.value);
                        var dateTimeString = new Date(
                                incDate.getFullYear() + '-' + (incDate.getMonth() + 1 ) + '-' + incDate.getDate() + ' ' +
                                (value().getHours() < 10 ? "0" + value().getHours() : value().getHours()).toString() + ':' +
                                (value().getMinutes() < 10 ? "0" + value().getMinutes() : value().getMinutes()).toString() + ':00'
                        );
                        value(dateTimeString);
                    } else {
                        // We have an incoming time, merge with stored date and update
                        var incTime = new Date('1970-01-01 '+element.value);
                        var timeDateString = new Date(
                                value().getFullYear() + '-' + (value().getMonth() + 1 )+ '-' + value().getDate() + ' ' +
                                (incTime.getHours() < 10 ? "0" + incTime.getHours() : incTime.getHours()).toString() + ':' +
                                (incTime.getMinutes() < 10 ? "0" + incTime.getMinutes() : incTime.getMinutes()).toString() + ':00'
                        );
                        value(timeDateString);
                    }
                }
            });
        },
        update: function (element, valueAccessor) {
            var widget = $('#' + element.parentNode.id).data("datetimepicker");
            if (widget) {
                widget.update(ko.utils.unwrapObservable(valueAccessor()));
                widget.setValue();
            }
        }
    };

部分取自映射从 Amplify JS 检索并映射到数据模型的数据的数据层:

    mapToContext = function (dtoList, items, results, mapper, filter, sortFunction) {
        var id, existingItem;
            id = mapper.getDtoId(dtoList);
            existingItem = items[id];
            items[id] = mapper.fromDto(dtoList, existingItem);
            results(items[id]);     <---------- Here the bindingHandler is again triggered
            return items[id];
    }
4

1 回答 1

0

确保在“附加”函数中初始化 datetimepicker,并确保在视图模型中公开“附加”函数。

此外,我设法将值绑定到它,如下所示(使用 MomentJS 转换从数据库读取的日期时间格式 - 如果您的 observable 格式正确,则不需要使用 MomentJS):

function attached(view){
    $('#datetimepicker_id').datetimepicker({
        format: 'dd/MM/yyyy hh:mm',
        pickSeconds: false
    });

    // placing inital value, reading from observable and formatting it with momentjs
    $('#datetimepicker_id')[0].childNodes[1].value = moment(myObservable()).format('DD/MM/YYYY HH:mm'); 

    // and now to subscribe to change event and place new value to my observable
    $('#datetimepicker_id').on('changeDate', function(e){
        myObservable(moment(e.date).toDate());
    });
}
于 2013-10-16T13:55:54.233 回答