如何将父函数添加到KnockOut双嵌套映射?

时间:2016-10-10 20:53:58

标签: knockout.js knockout-mapping-plugin

我正在使用KnockOut映射fromJS从JSON对象创建我的View Model,如下所示:

{
    "cats": [{
        "name": "fluffy",
        "color": "brown",
        "kittens": [{
            "name": "spot",
            "color": "brown"
        }, {
            "name": "rascal",
            "color": "grey"
        }, {
            "name": "trouble",
            "color": "white"
        }]
    }, {
        "name": "kitty",
        "color": "red",
        "kittens": [{
            "name": "lady",
            "color": "red"
        }, {
            "name": "skat",
            "color": "striped"
        }]
    }]
}

HTML:

<div data-bind="foreach:cats">
    <span data-bind="text:name"></span>
    <table>
        <tr data-bind="foreach: kittens">
             <td data-bind="text:name"></td>
             <td data-bind="text:color"></td>
             <td><a data-bind="click: $parent:showParentColor" href="#">Parent Color</a></td>
        </tr>
    </table>
</div>

使用Javascript:

var KittenModel = function (data) {
    ko.mapping.fromJS(data, {}, this);

    // ... various computed values added to this
}

var mapping = {
    'kittens': {
        create: function(options) {
            return new KittenModel(options.data);
        }
    },
    'otherItem': {
        create: function(options) {
             return ('otherStuff');
        }
     }
}

var data = { ... }; // the JSON above

var CatsViewModel = ko.mapping.fromJS(data, mapping);

问题:

在哪里以及如何放置showParentColor()函数以便数据绑定在小猫表中工作?例如:

function showParentColor(cat) {
    alert(cat.color);
}

谢谢!

2 个答案:

答案 0 :(得分:3)

您可以根据视图模型层次结构使用以下其中一项:

  • $ root :这指向根上下文中的主视图模型对象。最顶层的父上下文。
  • $ parents array:这是一个包含所有视图模型的数组。

    • $ parents [0]:父视图模型上下文。(也与$parent相同)

    • $ parents [1]:第二个父视图模型上下文。(祖父母)

    • $ parents [2]:第三个父视图模型上下文。 (曾祖父母)

    • 依旧......


更新: 如果要在CatsViewModel级别添加函数,只需将函数添加到创建的模型中。

示例:https://jsfiddle.net/kyr6w2x3/87/

JS:

 CatsViewModel.showParentColor = function(item){
      console.log(item.name());
      console.log(item.color());
    }

查看:

<a data-bind="click: $parents[1].showParentColor">

以下是模型的层次结构

- CatsViewModel 
    - cats : observableArray
        - name : observable
        - color : observable
        - kittens : observableArray
               - name : observable
               - color : observable
    - showParentColor : function

<小时/> 替代方案:您可以自己完成工作并创建模型。根据您的需要,您可以更轻松地进行修改和维护。您还可以在任何您想要的模型中添加click功能。

示例:http://jsfiddle.net/kyr6w2x3/91/

HTML:

<div data-bind="foreach:cats">
    <span data-bind="text:name"></span>
    <table>
    <tbody data-bind="foreach: kittens">
       <tr>
             <td data-bind="text:name"></td>
             <td data-bind="text:color"></td>
             <td><a data-bind="click: $parent.showParentColor" href="#">Parent Color</a></td>
        </tr>
    </tbody>

    </table>
</div>

<强> JS:

 var data = {
    "cats": [{
        "name": "fluffy",
        "color": "brown",
        "kittens": [{
            "name": "spot",
            "color": "brown"
        }, {
            "name": "rascal",
            "color": "grey"
        }, {
            "name": "trouble",
            "color": "white"
        }]
    }, {
        "name": "kitty",
        "color": "red",
        "kittens": [{
            "name": "lady",
            "color": "red"
        }, {
            "name": "skat",
            "color": "striped"
        }]
    }]
}

var CatsViewModel = function (data){ 
  var self = this;
  self.cats = ko.observableArray($.map(data.cats, function (item) {
        return new CatItemViewModel(item);
    }));
}
var CatItemViewModel = function (data){
  var self = this;
  self.name = ko.observable(data.name);
  self.color = ko.observable(data.color);
  self.kittens = ko.observableArray($.map(data.kittens, function (item)     {
   var newData = Object.assign({}, item, { parent: self.name()});
        return new KittenModel(newData);
   }));
   self.showParentColor = function (item){
      console.log("Parent Name: " , self.name());
      console.log("Name: " , item.name());
      console.log("Color: " , item.color());
   }
}
var KittenModel = function (data) {
  var self = this;
  self.name = ko.observable(data.name);
  self.color = ko.observable(data.color);
  self.parent = ko.observable(data.parent);
}
var vm = new CatsViewModel(data);
ko.applyBindings(vm);

答案 1 :(得分:1)

注意:我更喜欢其他答案的方法,但是为了有多种选择,我想提出另一种解决方案。

备选方案1

你可以创建一个&#34;静态&#34; mycpp.dll中记录其已通过的任何猫咪颜色的方法:

KittenModel

现在,因为您的视图可以访问父子结构,所以您可以使用您想要的任何父级调用此方法:

var KittenModel = function (data) {
  ko.mapping.fromJS(data, {}, this);
};

KittenModel.logCatColor = function(cat) {
  console.log(cat.color);
};

一个例子:

&#13;
&#13;
<!-- to log the parent's color -->
<div data-bind="click: logCatColor.bind(null, $parent)"></div>

<!-- knockout automatically passes `$data` as a first argument,
     so you won't need to bind the method to log your own color -->
<div data-bind="click: logCatColor"></div>
&#13;
ko.applyBindings({
  name: "parent",
  child: {
    name: "child",
    logName: function(entity) {
      console.log(entity.name);
    }
  }
});
&#13;
&#13;
&#13;

备选方案2

在您作为选项传递的工厂功能中,您同时拥有<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> <h1 data-bind="text: name"></h1> <div data-bind="with: child" style="border: 1px solid black"> <h2 data-bind="text: name"> </h2> <button data-bind="click: logName"> log my name </button> <button data-bind="click: logName.bind(null, $parent)"> log my parent's name </button> </div>dataparent包含当前正在映射的项目。在这种情况下,options.data将引用父options.parent。我还没有测试过这个,但这可能有用:

cat