如何从ko.js数组中的父函数访问调用子元素?

时间:2019-05-02 12:43:46

标签: knockout.js

我正在使用kickout.js foreach循环创建复选框列表。我有一个可观察的数组,其中包含复选框的值,但是当我调用该函数检查其值时,ia元素引用父元素,即viewModel。如何访问与单击的元素相关的数组元素?

我尝试从以下代码中删除warehousein引用,但这引发了此错误:oa

这是创建复选框的foreach循环:

warehouseout

这些是ko视图模型中定义的功能:

this

并且sampleList的格式为:

$parent

预期结果:更改数组中给定项目的isChecked的值时,应调用函数Message: getSampleValue is not defined,并且应该更新UI上的值。从该函数返回的isChecked值应该是数组中正确的元素,而不是父元素。

实际结果:该函数被调用,但似乎仅在创建复选框时才被调用,而不是在<!-- ko foreach: sampleList --> <div data-bind="css: { hasValue: $parent.getSampleValue() }"> <span data-bind="click: $parent.sampleClick, text: name"></span> <div data-bind="click: $parent.sampleClick" class="spot fa fa-square"></div> </div> <!-- /ko --> 值被更新时才被调用,并且函数内的sampleViewModel = function (data) { var self = this; self.sampleList = ko.observableArray(data.sampleList); self.sampleClick = function () { this.isChecked = !this.isChecked; } self.getSampleValue = function () { return this.isChecked; } } 是其父元素。呼叫者,因此没有{ { "name": "name1", "isChecked": false }, { "name": "name2", "isChecked": true } } 值。

对此有任何帮助,深表感谢。

编辑: 因此,更改此行:

getSampleValue

对此:

isChecked

似乎在加载时显示正确的值,但是即使可观察数组的值已更改,它们也不会在UI上更新。

2 个答案:

答案 0 :(得分:2)

视图模型中的函数已绑定this到视图模型本身。您可以使用处理程序函数的第一个参数访问当前元素:

sampleViewModel = function (data) {
    var self = this;
    self.sampleList = ko.observableArray(data.sampleList);

    self.sampleClick = function (element) {
       element.isChecked = !element.isChecked;
    }

    self.getSampleValue = function (element) {
       return element.isChecked;
    }
}

请参见The "click" binding

  

调用处理程序时,Knockout将提供当前模型值作为第一个参数。如果您要为集合中的每个项目渲染一些UI,并且需要知道单击了哪个项目的UI,则此功能特别有用。


此外,要正确绑定到getSampleValue,您应该删除括号。

<div data-bind="css: { hasValue: $parent.getSampleValue }">

或者-您已经发现-由于该函数返回值而不修改它,因此您可以绑定到值本身:

<div data-bind="css: { hasValue: isChecked }">

答案 1 :(得分:0)

您使用错误的淘汰赛方法。不要将属于某个项目的方法放在该项目的父项中。让项目负责自己的状态。

考虑以下示例:

  • SampleItem类跟踪其自己的名称和其“已检查”状态。它还提供了一种切换“已检查”状态的方法。
  • SampleApplication类仅保留项目列表。它将用作页面的$root视图模型。
  • 该视图使用isChecked来确定Font Awesome的CSS类,并透明地将click事件链接到正确的接收者。
  • 整个视图模型图是通过单个函数调用构建的,该模型构造了嵌套的视图模型并将数据映射到过程中的可观察对象。
  • 不需要从子级到$parent的交叉引用。

function SampleItem(data) {
  var self = this;
  
  self.name = ko.observable(data.name);
  self.isChecked = ko.observable(data.isChecked);
  
  self.toggleChecked = function () {
    self.isChecked(!self.isChecked());
  };
}

function SampleApplication(data) {
  var self = this;
  
  self.sampleList = ko.observableArray();
  
  // viewmodel init (i.e. data mapping)
  data.sampleList.forEach(function (itemData) {
    self.sampleList.push( new SampleItem(itemData) );
  });
}

// -------------------------------------------------------
var rawModelData = {
  sampleList: [{
    name: "name1",
    isChecked: false
  }, {
    name: "name2",
    isChecked: true
  }]
};

var vm = new SampleApplication(rawModelData);
ko.applyBindings(vm);
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<!-- ko foreach: sampleList -->
<div data-bind="click: toggleChecked">
  <span data-bind="text: name"></span>
  <div class="spot fa-square" data-bind="css: {far: !isChecked(), fas: isChecked()}"></div>
</div>
<!-- /ko -->

<hr>
<pre data-bind="text: ko.toJSON($root, null, 2)">


使用mapping plugin创建嵌套视图模型并使它们与服务器数据保持最新的过程变得更加容易,尤其是当有大量数据要映射到可观察对象并且视图模型嵌套结构变得更加复杂时。

>

简单调用ko.mapping.fromJS(inputObj, options, target)即可处理所有细节。

function SampleItem(data) {
  var self = this;

  self.name = ko.observable("");
  self.isChecked = ko.observable(false);

  // viewmodel init (i.e. data mapping)
  ko.mapping.fromJS(data, {}, self);
  
  self.toggleChecked = function () {
    self.isChecked(!self.isChecked());
  };
}

function SampleApplication(data) {
  var self = this;
  
  self.sampleList = ko.observableArray();
  
  // viewmodel init (i.e. data mapping)
  ko.mapping.fromJS(data, SampleApplication.mapping, self);
}
SampleApplication.mapping = {
  sampleList: {
    create: options => new SampleItem(options.data)
  }
};
// -------------------------------------------------------
var rawModelData = {
  sampleList: [{
    name: "name1",
    isChecked: false
  }, {
    name: "name2",
    isChecked: true
  }]
};

var vm = new SampleApplication(rawModelData);
ko.applyBindings(vm);
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>

<!-- ko foreach: sampleList -->
<div data-bind="click: toggleChecked">
  <span data-bind="text: name"></span>
  <div class="spot fa-square" data-bind="css: {far: !isChecked(), fas: isChecked()}"></div>
</div>
<!-- /ko -->

<hr>
<pre data-bind="text: ko.toJSON(ko.mapping.toJS($root), null, 2)">

请注意,在此变体中,“ unmapping”(通过ko.mapping.toJS())对于删除映射插件添加的用于跟踪事物的所有属性是必需的。