35

Knockout.jsをMVVMライブラリとして使用して、データをいくつかのページにバインドしています。現在、WebサービスへのREST呼び出しを行うためのライブラリを構築しています。私のRESTfulWebサービスは、単純な構造を返します。

{
    id : 1,
    details: {
        name: "Johnny",
        surname: "Boy"
    }
}

私には観察可能な主な親がいmyObjectます。私がする時

myObject(ko.mapping.fromJS(data))

のオブザーバブルは次のmyObjectとおりです。

  • id
  • name
  • surname

どうすればdetails(そして理論的には構造内の任意のオブジェクトを観察可能にすることができますか)?この動作が必要なのは、詳細に計算されたオブザーバブルを設定し、内部データのいずれかが変更されるとすぐに通知されるようにするためです。

トリックを実行する基本的な再帰関数を設定しました。もちろん、それはmyObject.details観察可能にはなりません。

// Makes every object in the tree an observable.
var makeAllObservables = function () {
    makeChildrenObservables(myObject);
};
var makeChildrenObservables = function (object) {
    // Make the parent an observable if it's not already
    if (!ko.isObservable(object)) {
        if ($.isArray(object))
            object = ko.observableArray(object);
        else
            object = ko.observable(object);
    }
    // Loop through its children
    for (var child in object()) {
        makeChildrenObservables(object()[child]);
    }
};

間違った参照に関するものだと確信していますが、どうすればこれを解決できますか?ありがとうございました。

4

6 に答える 6

23

ノックアウトマッピングプラグインを使用します。

var jsonData = {
    id : 1,
    details: {
        name: "Johnny",
        surname: "Boy"
    }
}

var yourMapping = {
    'details': {
        create: function(options) {
            return Details(options.data);
        }
    }
}

function Details(data) {
    ko.mapping.fromJS(data, {}, this);
}

function YourObjectName() {
    ko.mapping.fromJS(jsonData, yourMapping, this);
}

これにより、すべての子を監視対象としてオブジェクト階層が作成されます。

于 2012-05-11T18:54:37.393 に答える
14

ノックアウトには、子要素の変更を監視する方法が組み込まれているとは思いません。私があなたの質問を理解しているなら、誰かが名前を変更したとき、あなたはエンティティとしての詳細への変更が通知されることを望みます。これをどのように使用するかについて具体的な例を挙げていただけますか?何らかのアクションを実行するために、観察可能な詳細へのサブスクリプションを使用しますか?

コードで詳細が観察可能にならない理由は、JavaScriptが値で渡されるためです。したがって、関数で「object」引数の値を変更しても、渡した実際の値は変更されず、内部の引数の値のみが変更されます。働き。

編集

変更自動的に親に伝播する場合、これによりすべての子が観察可能になるはずですが、最初に通過するルートはすでに観察可能である必要があります。

// object should already be observable
var makeChildrenObservables = function (object) {
    if(!ko.isObservable(object)) return;

    // Loop through its children
    for (var child in object()) {
        if (!ko.isObservable(object()[child])) {
            object()[child] = ko.observable(object()[child]);
        }
        makeChildrenObservables(object()[child]);
    }
};
于 2012-05-12T06:47:47.220 に答える
3

私が経験したことから、ko.mapping.fromJSはオブジェクトからオブザーバブルを作成しません。

このViewModelコンストラクターがあるとしましょう:

var VM = function(payload) {
  ko.mapping.fromJS(payload, {}, this);
}

およびこのデータオブジェクト:

var data1 = {
  name: 'Bob',
  class: {
    name: 'CompSci 101',
    room: 112
  }

}

data1を使用してVM1を作成します。

var VM1 = new VM(data1);

その場合、VM1.classはko.observableではなく、プレーンなjavascriptオブジェクトです。

次に、nullクラスメンバーを持つデータオブジェクトを使用して別のビューモデルを作成すると、次のようになります。

var data2 = {
  name: 'Bob',
  class: null
}
var VM2 = new VM(data2);

その場合、VM2.classはko.observableです。

次に実行する場合:

ko.mapping(data1, {}, VM2)

その場合、VM2.classはko.observableのままです。

したがって、オブジェクトメンバーがnullであるシードデータオブジェクトからViewModelを作成し、それらにデータが入力されたデータオブジェクトをポップアップ表示すると、監視可能なクラスメンバーが作成されます。

オブジェクトメンバーが監視可能である場合とそうでない場合があるため、これは問題につながります。フォームバインディングはVM1で機能し、VM2では機能しません。ko.mapping.fromJSが常にすべてをko.observableにして、一貫性があるといいのですが?

于 2014-02-27T03:23:40.867 に答える
3

Knockout-Pluginを使用することで、子要素を監視可能にすることができます。データを監視可能にする方法を管理するためのオプションがたくさんあります。

サンプルコードは次のとおりです。

var data = {
    people: [
        {
            id: 1,
            age: 25,
            child : [
                {id : 1,childname : "Alice"},
                {id : 2,childname : "Wonderland"}
            ]
        }, 
        {id: 2, age: 35}
    ],
    Address:[
        {
            AddressID : 1,
            City : "NewYork",
            cities : [
                {
                    cityId : 1,
                    cityName : "NewYork"
                },
                {
                    cityId :2,
                    cityName : "California"
                }
            ]
        },
        {
            AddressID : 2,
            City : "California",
            cities : [
                {
                    cityId :1,
                    cityName : "NewYork"
                },
                {
                    cityId :2,
                    cityName : "California"
                }
            ]
        }
    ],
    isSelected : true,
    dataID : 6
};
var mappingOptions = {
    people: {
        create: function(options) {
            console.log(options);
            return ko.mapping.fromJS(options.data, childmappingOptions);
        }
    },
    Address: {
        create: function(options) {
            console.log(options);
            return ko.mapping.fromJS(options.data, childmappingOptions);
        }
    }
};
var childmappingOptions = {
    child: {
        create: function(options) {
            return ko.mapping.fromJS(options.data, { observe: ["id","childname"]});
        }
    },
    cities :{
        create: function(options) {
            return ko.mapping.fromJS(options.data, { observe: ["cityId","cityName"]});
        }
    }
};
var r = ko.mapping.fromJS(data, mappingOptions);

動作するフィドルを添付しました:http://jsfiddle.net/wmqTx/5/

于 2014-07-10T07:30:54.247 に答える
2

Paolo del Mundoの答え(現時点では簡単に最良かつ唯一の解決策になると思います)を私の例の解決策で拡張します。

frapontilloの元のオブジェクトを考えてみましょう。

{
    id : 1,
    details: {
        name: "Johnny",
        surname: "Boy"
    }
}

プロパティ自体はオブジェクトであるため、details監視することはできません。以下の例のプロパティについても同じことが言えUserます。これもオブジェクトです。これらの2つのオブジェクトは監視可能にすることはできませんが、それらのLEAFプロパティは監視可能にすることができます

データツリー/モデルのすべてのリーフプロパティを観察できます。これを実現する最も簡単な方法は、マッピングプラグインにパラメータとして渡す前に、マッピングモデルを適切に定義することです。

以下の私の例を参照してください。

例:

グリッド上にユーザーのリストがあるhtmlページ/ビューを表示する必要があるとしましょう。ユーザーグリッドの横に、グリッドから選択したユーザーを編集するためのフォームが表示されます。

ステップ1:モデルの定義

function UsersEdit() {
    this.User = new User();                    // model for the selected user      
    this.ShowUsersGrid = ko.observable(false); // defines the grid's visibility (false by default)
    this.ShowEditForm = ko.observable(false);  // defines the selected user form's visibility (false by default)      
    this.AllGroups = [];                       // NOT AN OBSERVABLE - when editing a user in the user's form beside the grid a multiselect of all available GROUPS is shown (to place the user in one or multiple groups)
    this.AllRoles = [];                        // NOT AN OBSERVABLE - when editing a user in the user's form beside the grid a multiselect of all available ROLES is shown (to assign the user one or multiple roles)
}

function User() {
    this.Id = ko.observable();
    this.Name = ko.observable();
    this.Surname = ko.observable();
    this.Username = ko.observable();
    this.GroupIds = ko.observableArray(); // the ids of the GROUPS that this user belongs to
    this.RoleIds = ko.observableArray();  // the ids of the ROLES that this user has
}

ステップ2:マッピング(ネストされたオブザーバブルを取得するため)

これが、マッピングしたいデータを含む生のJSONモデルであり、ネストされたオブザーバブルを含むKOモデルを取得するとします。

var model = {
    User: {
        Id: 1,
        Name: "Johnny",            
        Surname = "Boy",
        Username = "JohhnyBoy",
        GroupIds = [1, 3, 4],
        RoleIds = [1, 2, 5]
    }
};

これですべてが定義されたので、次のマップを作成できます。

var observableUserEditModel = ko.mapping.fromJS(model, new UsersEdit());

そして、あなたは完了です!:)

observableUserEditModelは、ネストされたものも含め、すべてのオブザーバブルを保持します。observableUserEditModelこれをテストするために注意する必要があるのは、オブジェクトをHTMLにバインドすることだけです。ヒント:バインディングを使用して、HTMLビューにこれを挿入する監視可能なデータ構造withをテストします。observableUserEditModel

<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>
于 2015-04-04T13:59:42.297 に答える
1

将来のバージョンでは、ko.mapping.fromJSが常にオブザーバブルを作成するようにする構成オプションが存在する可能性があります。これは、新しいプロジェクトに対して、または既存のプロジェクトのバインディングを更新した後に有効にすることができます。

この問題を防ぐために私が行うことは、モデルシードにすべてのレベルで常にObjectsメンバープロパティが設定されていることを確認することです。このように、すべてのオブジェクトプロパティはPOJO(Plain Old Javascript Objects)としてマップされるため、ViewModelはそれらをko.observablesとして初期化しません。これにより、「観察可能な場合とそうでない場合がある」という問題が回避されます。

よろしく、マイク

于 2014-02-28T03:32:42.073 に答える