我只是尝试填充我使用jquery渲染的几个选择标记。
来自服务器的传入模型:
public class DepthChartsVm
{
public List<DepthChartModel> ReturnDepthCharts {get;set;}
}
public class DepthChartModel
{
public Team Team {get;set;}
public int SportId {get;set;}
}
public class Team
{
// various properties
public List<AthleteInfo> AthleteInfo {get;set;}
public List<positions> BasketBallPositonList {get;set;}
}
public class AthleteInfo
{
// various properties
List<DepthChart> DepthChartPositions {get;set;}
}
public class DepthChart
{
// various properties
prop ...etc
}
public class Positions
{
// various properties
prop ... etc.
}
HTML:
<div class="col-sm-4">
<label for="teamDropDown" class="text-center">Teams</label>
<select id="teamDropDown" data-bind="options: depthVm.ReturnDepthCharts, value: selectedTeam,
optionsText: function(item){return item.Team.FullName},
optionsCaption: 'select'"></select>
<p data-bind="if: selectedTeam">
<strong>Sport: </strong> <span data-bind="text: selectedTeam().Team.Sport"></span><br />
<strong>Season: </strong> <span data-bind="text: selectedTeam().Team.Season"></span>
</p>
</div>
<!--Athletes-->
<div class="col-sm-4">
<div data-bind="if: selectedTeam">
<h3 class="text-center">Athletes</h3>
<div data-bind="foreach: selectedTeam().Team.AthleteInfo">
<p>
<strong>Name: </strong><span data-bind="text: FirstName()
+ ' ' + LastName()"></span>
</p>
<div data-bind="foreach: DepthChartPositions()">
<p>
<input class="hidden" name="InputUpdateDepthChart.RosterId"
data-bind="value: RosterId"/>
Position: <select name="InputUpdateDepthChart.PositionId"
data-bind="options: $root.selectedTeam().Team.BasketBallPostionList,
optionsText: 'Position', value: PositionId, optionsValue: 'Id'"></select>
String: <select name="InputUpdateDepthChart.StringId"
data-bind="options: DepthStrings, optionsText: 'String',
value: StringId, optionsValue: 'Id'"></select>
</p>
<p>
<button data-bind="click: $root.addPosition">Add Position</button>
</p>
</div>
</div>
</div>
</div>
</div>
// script that serializes the model and passes it to knockout
<script>
// json encode incoming model
var depthModelData = @Html.Raw(JsonConvert.SerializeObject(Model))
// update depth chart vM
ko.applyBindings(new UpdateDepthChartVm(depthModelData),
document.getElementById('updateDepthChartForm'));
</script>
查看型号:
var UpdateDepthChartVm = function (model) {
var self = this;
self.depthVm = ko.mapping.fromJS(model);
// selected team
self.selectedTeam = ko.observable();
// add position
self.addPosition = function () {
self.selectedTeam.Team.AthleteInfo.DepthChartPositions.push(new depthChartPosition());
};
function depthChartPosition(values) {
values = values || {};
var model = {
RosterId: ko.observable(values.RosterId),
PositionId: ko.observable(values.PositionId),
StringId: ko.observable(values.StringId),
};
return model;
}
};
基本上我想在用户希望添加其他位置时动态复制第一段。 jquery在使用select标签呈现新段落方面确实有效,但是select字段是空的,因为它们与我的视图模型之间似乎没有绑定。除此之外,我的视图模型正在运行。我在这里缺少什么?
答案 0 :(得分:1)
后续选择元素没有任何选项的原因是因为它们没有绑定。请记住,ko.applyBindings可以让您的HTML变为现实。由于这些项目是在事后添加的,因此它们不会被ko跟踪。
使用knockout的observableArray实际上有更好的方法。它更干净,干燥,可测试。你太近了!
var UpdateDepthChartVm = function (model) {
var self = this;
self.depthVm = ko.mapping.fromJS(model);
self.selectedTeam = ko.observable();
self.addPosition = function () {
self.depthVm.DepthChartPositions.splice(0, 0, new depthChartPosition());
// I used splice because I believe you were wanting the UI element to be added to the
// top of the list. Otherwise you could just use `push(new depthChartPosition())`.
};
// this bit isn't required but it's my preference
function depthChartPosition(values) {
values = values || {};
var model = {
RosterId: ko.observable(values.RosterId),
PositionId: ko.observable(values.PositionId),
StringId: ko.observable(values.StringId),
}
return model;
}
// you also might want to use the above constructor in your mapping. again, just my preference
function mappings() {
return {
DepthChartPositions: {
create: function(options) {
return new depthChartPosition(options.data);
}
}
}
}
请记住,knockout.js是一个MVVM(Model View View-Model)框架。让视图模型数据在不知道UI的同时驱动UI,同时让UI尽可能简单。
修改强>
仔细查看您的视图模型,我发现有两个DepthChartPositions
:一个是self.depthVm
的成员(由于ko.mapping应该是observableArray),另一个是{ {1}}。后者是UI元素绑定的对象。我确实看到你的selectedTeam().Team.AthleteInfo
函数正在修改正确的对象,但我不知道如何创建这个对象。我的猜测是,这不是addPosition
。您可以这样测试:
observableArray
答案 1 :(得分:1)
Knockout Mapping只会在提供的对象的第一级属性中添加可观察的包装器。我假设您正在为ko.mapping.fromJS
方法提供的对象是DepthChartsVm
C#模型的JS表示。因此,只能观察ReturnDepthCharts
属性。简单的答案是提供映射自定义,例如:
var depthChartsVmMapping = {
Team: {
create: function(options) {
return ko.mapping.fromJS(options.data, teamMapping);
}
}
}
var teamMapping = {
AthleteInfo: {
create: function(options) {
return ko.mapping.fromJS(options.data, athleteInfoMapping);
}
}
}
var athleteInfoMapping = {
DeptChartPositions: {
create: function(options) {
return ko.mapping.fromJS(options.data);
}
}
}
var self = this;
self.depthVm = ko.mapping.fromJS(model, depthChartsVmMapping);
是的,我同意这使得映射模块看起来有点麻烦,但考虑到你的模型包含太多级别的可能性。例如,你真的需要加载所有球队,所有运动员和每个运动员的深度图位置吗?更传统的类似REST的实现可能是在需要时异步加载必要的资源。显然,我不知道你的应用程序是如何呈现的,但我知道在这种情况下,你可能会:
您可以使用上面举例说明的自定义设置进行映射,所以如果您没有关注我,请不要担心。但是,如果你想进行一些重构,我会支持这个原因!
希望有所帮助!
var vm = {
Teams: ko.observableArray(),
CurrentTeam: ko.observable(),
}