23

監視可能な変数を持つオブジェクトのobservableArrayを持つviewModelがあります。

私のテンプレートは、表示要素を非表示にし、値がバインドされた入力要素を表示する編集ボタンでデータを表示します。データの編集を開始してから、キャンセルするオプションがあります。このキャンセルを変更されていないバージョンのオブジェクトに戻したいのですが。

私は次のようなことをしてオブジェクトのクローンを作成しようとしました:

viewModel.tempContact = jQuery.extend({}, contact);

また

viewModel.tempContact = jQuery.extend(true, {}, contact);

ただし、viewModel.tempContactは、連絡先が変更されるとすぐに変更されます。

この種の状況を処理するためにKnockoutJSに組み込まれているものはありますか、それともまったく同じ詳細で新しい連絡先を作成し、キャンセル時に変更された連絡先を新しい連絡先に置き換えるのが最善ですか?

アドバイスをいただければ幸いです。ありがとう!

4

5 に答える 5

16

このようなものを処理する方法はいくつかあります。現在のオブジェクトと同じ値で新しいオブジェクトを作成し、キャンセル時に破棄することができます。オブザーバブルを追加して編集フィールドにバインドし、acceptで永続化するか、この投稿を参照して、この機能を再利用可能なタイプにカプセル化する方法を確認できます(これが私の推奨される方法です)。

于 2011-05-03T20:08:13.830 に答える
3

私は同様の問題を解決しようとしているときにこの投稿に出くわし、次の人のために私のアプローチと解決策を投稿すると思いました。

私はあなたの考え方に沿って進みました-オブジェクトのクローンを作成し、「元に戻る」で古いデータを再入力します。

1)データオブジェクトを新しいページ変数( "_initData")にコピーします。2)元のサーバーオブジェクトからObservableを作成します。3)変更されていないデータ( "_initData")でオブザーバブルを「元に戻す」リロードします。

簡略化されたJS:var _viewModel; var _initData = {};

$(function () {
    //on initial load
    $.post("/loadMeUp", {}, function (data) {
        $.extend(_initData , data);
        _viewModel = ko.mapping.fromJS(data);
    });

    //to rollback changes
    $("#undo").live("click", function (){
        var data = {};
        $.extend(data, _initData );
        ko.mapping.fromJS(data, {}, _viewModel);
    });

    //when updating whole object from server
    $("#updateFromServer).live("click", function(){
        $.post("/loadMeUp", {}, function (data) {
            $.extend(_initData , data);
            ko.mapping.fromJS(data, {}, _viewModel);
        });
    });

    //to just load a single item within the observable (for instance, nested objects)
    $("#updateSpecificItemFromServer).live("click", function(){
        $.post("/loadMeUpSpecificItem", {}, function (data) {
            $.extend(_initData.SpecificItem, data);
            ko.mapping.fromJS(data, {}, _viewModel.SpecificItem);
        });
    });

    //updating subItems from both lists
    $(".removeSpecificItem").live("click", function(){
        //object id = "element_" + id
        var id = this.id.split("_")[1];
        $.post("/deleteSpecificItem", { itemID: id }, function(data){
            //Table of items with the row elements id = "tr_" + id
            $("#tr_" + id).remove();
            $.each(_viewModel.SpecificItem.Members, function(index, value){
                if(value.ID == id)
                    _viewModel.SpecificItem.Members.splice(index, 1);
            });
            $.each(_initData.SpecificItem.Members, function(index, value){
                if(value.ID == id)
                    _initData.SpecificItem.Members.splice(index, 1);
            });
        });
    });
});

個々のプロパティごとにハンドラーを追加したくないほど複雑なオブジェクトがありました。

オブジェクトにリアルタイムでいくつかの変更が加えられます。これらの変更は、observableと「_initData」の両方を編集します。

サーバーからデータを取得したら、「_ initData」オブジェクトを更新して、サーバーとの同期を維持しようとします。

于 2014-10-15T21:49:26.820 に答える
2

非常に古い質問ですが、私は非常によく似た方法を実行し、マッピングプラグインを使用してこれを行うための非常にシンプルで迅速かつ効果的な方法を見つけました。

バックグラウンド; を使用してバインドされたKOオブジェクトのリストを編集していforeachます。各オブジェクトは、ラベルまたは入力を表示するようにビューに指示する単純なオブザーバブルを使用して編集モードになるように設定されています。

関数は、各アイテムのclickバインディングで使用されるように設計されています。foreach

次に、編集/保存/キャンセルは単純です。

this.edit = function(model, e)
{
    model.__undo = ko.mapping.toJS(model);
    model._IsEditing(true);
};

this.cancel = function(model, e)
{
    // Assumes you have variable _mapping in scope that contains any 
    // advanced mapping rules (this is optional)
    ko.mapping.fromJS(model.__undo, _mapping, model);
    model._IsEditing(false);
};

this.save = function(model, e)
{
    $.ajax({
        url: YOUR_SAVE_URL,
        dataType: 'json',
        type: 'POST',
        data: ko.mapping.toJSON(model),
        success: 
            function(data, status, jqxhr)
            {
                model._IsEditing(false);
            }
    }); 
};

これは、単純なオブジェクトのリストを編集するときに非常に便利ですが、ほとんどの場合、軽量オブジェクトを含むリストを作成し、実際の編集用に完全な詳細モデルをロードするため、この問題は発生しません。

そのようにプロパティを追加したくない場合は、モデルにsaveUndo/メソッドを追加できますが、個人的には、この方法の方が明確であり、コードがはるかに少なく、明示的な宣言がないモデルでも使用できると思います。restoreUndo__undo

于 2015-06-18T11:42:42.280 に答える
0

これには、 KO-UndoManagerの使用を検討してください。ビューモデルを登録するためのサンプルコードは次のとおりです。

viewModel.undoMgr = ko.undoManager(viewModel, {
  levels: 12,
  undoLabel: "Undo (#COUNT#)",
  redoLabel: "Redo"
});

次に、次のようにHTMLに元に戻す/やり直しボタンを追加できます。

 <div class="row center-block">
    <button class="btn btn-primary" data-bind="
      click: undoMgr.undoCommand.execute, 
      text: undoMgr.undoCommand.name, 
      css: { disabled: !undoMgr.undoCommand.enabled() }">UNDO</button>
    <button class="btn btn-primary" data-bind="
      click: undoMgr.redoCommand.execute, 
      text: undoMgr.redoCommand.name, 
      css: { disabled: !undoMgr.redoCommand.enabled() }">REDO</button>
  </div> 

そして、これが実際の動作を示すPlunkrですundoMgr.undoCommand.executeすべての変更を元に戻すには、すべての変更が元に戻されるまでjavascriptで呼び出しをループする必要があります。

于 2014-12-21T21:16:53.183 に答える
0

似たようなものが必要でしたが、一時的な値を更新するために計算が必要だったため、保護されたオブザーバブルを使用できませんでした。だから私はこのノックアウト拡張機能を書きました:

この拡張機能は、各オブザーバブルのアンダースコアバージョンを作成します。つまり、self.Comments()-> self._Comments()

ko.Underscore = function (data) {
    var obj = data;
    var result = {};
    // Underscore Property Check
    var _isOwnProperty = function (isUnderscore, prop) {
        return (isUnderscore == null || prop.startsWith('_') == isUnderscore) && typeof obj[prop] == 'function' && obj.hasOwnProperty(prop) && ko.isObservable(obj[prop]) && !ko.isComputed(obj[prop])
    }
    // Creation of Underscore Properties
    result.init = function () {
        for (var prop in obj) {
            if (_isOwnProperty(null, prop)) {
                var val = obj[prop]();
                var temp = '_' + prop;
                if (obj[prop].isObservableArray)
                    obj[temp] = ko.observableArray(val);
                else
                    obj[temp] = ko.observable(val);
            }
        }
    };
    // Cancel
    result.Cancel = function () {
        for (var prop in obj) {
            if (_isOwnProperty(false, prop)) {
                var val = obj[prop]();
                var p = '_' + prop;
                obj[p](val);
            }
        }
    }
    // Confirm
    result.Confirm = function () {
        for (var prop in obj) {
            if (_isOwnProperty(true, prop)) {
                var val = obj[prop]();
                var p = prop.replace('_', '');
                obj[p](val);
            }
        }
    }
    // Observables
    result.Properties = function () {
        var obs = [];
        for (var prop in obj) {
            if (typeof obj[prop] == 'function' && obj.hasOwnProperty(prop) && ko.isObservable(obj[prop]) && !ko.isComputed(obj[prop])) {
                var val = obj[prop]();
                obs.push({ 'Name': prop, 'Value': val });
            }
        }
        return obs;
    }

    if (obj != null)
        result.init();

    return result;
}

この拡張機能を使用すると、各オブザーバブルの複製を作成する手間が省け、計算されたものは無視されます。それはこのように動作します:

var BF_BCS = function (data) {
    var self = this;

    self.Score = ko.observable(null);
    self.Comments = ko.observable('');

    self.Underscore = ko.Underscore(self);

    self.new = function () {
        self._Score(null);
        self._Comments('');
        self.Confirm();
    }

    self.Cancel = function () {
        self.Pause();
        self.Underscore.Cancel();
        self.Resume();
    }

    self.Confirm = function () {
        self.Pause();
        self.Underscore.Confirm();
        self.Resume();
    }

    self.Pause = function () {

    }

    self.Resume = function () {

    }

    self.setData = function (data) {
        self.Pause();

        self._Score(data.Score);
        self._Comments(data.Comments);
        self.Confirm();
        self.Resume();
    }

    if (data != null)
        self.setData(data);
    else
        self.new();
};

だからあなたがhtmlにボタンがあるかどうか見ることができるように:

<div class="panel-footer bf-panel-footer">
    <div class="bf-panel-footer-50" data-bind="click: Cancel.bind($data)">
        Cancel
    </div>
    <div class="bf-panel-footer-50" data-bind="click: Confirm.bind($data)">
        Save
    </div>
</div>

キャンセルすると、オブザーバブルが元に戻されて元の状態に戻ります。保存すると、実際の値が1行の一時値で更新されます。

于 2017-07-05T10:52:39.043 に答える