1

Durandal JS 2.0 で構築されたアプリケーションがあり、John Papa による CodeCamper SPA からインスピレーションを得たパーツを使用しています。フォームの 1 つで、日付と時刻のピッカーを使用したいので、見栄えがよく、私のニーズを満たすhttp://www.malot.fr/bootstrap-datetimepickerを見つけました。これは、Knockout JS とカスタム バインディング ハンドラーを使用してデータ レイヤーに接続され、そのように初期化されます。

コントロールは視覚的にもデータも問題なく機能し、見栄えも良いことに注意してください。データモデルと基礎となるデータベースを問題なく更新します。このdatetimepickerを除いて、他のすべての標準コントロールは正常に機能します。

私の問題は、durandal フォームが構成され、datetimepicker が DOM double に挿入されたときに発生します。フォームを開くたびに、ピッカーが再び挿入されます。DOM に膨大な量の datetimepicker が挿入されているため、しばらくするとアプリケーション全体の速度が低下し始めます。

これがどこで発生するかを追跡しようとしましたが、オブザーバブルを初期化または再初期化するたびに発生するようです。これは、フォームがアクティブ化されたとき、およびデータが取得されたときに発生します。これにより 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を使用して、データベースから読み取った日時形式を変換します-オブザーバブルが正しい形式の場合、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 に答える