我有一个问题,我花了两天时间试图弄明白,我会尽量把所有内容都放在这里解释背景而没有不必要的信息,但请问我会提供信息。
问题
过程是,用户选择他们想要添加到竞赛中的团队,点击添加,然后选择的团队将从主teams
列表中删除,并添加到competition.teams
名单。要删除团队,用户可以从选项框中选择团队,然后点击删除。这将从competition.teams
数组中删除该团队,并重新添加到teams
数组中。
期望的结果
我希望代码能够如上所述工作,由于我对knockout / javascript的了解有限,我可能过度设计了解决方案。我对其他解决方案持开放态度,我还没有进入将其提交回服务器的阶段,我预测这不会像普通表单提交那么容易!
例外
Chrome控制台中的错误是:
未捕获的TypeError:无法读取未定义的属性“name” at eval(eval at parseBindingsString(knockout-min.3.4.2.js:68),:3:151) at f(knockout-min.3.4.2.js:94) 在knockout-min.3.4.2.js:96 at a.B.i(knockout-min.3.4.2.js:118) 在Function.Uc(knockout-min.3.4.2.js:52) 在Function.Vc(knockout-min.3.4.2.js:51) 在Function.U(knockout-min.3.4.2.js:51) 在Function.ec(knockout-min.3.4.2.js:50) 在Function.notifySubscribers(knockout-min.3.4.2.js:37) 在Function.ha(knockout-min.3.4.2.js:41)
守则
屏幕截图的HTML:
<div class="form-group">
<div class="col-md-3">
<label for="selectedTeams" class="col-md-12">Select your Teams</label>
<button type="button" data-bind="enable:$root.teams().length>0,click:$root.addTeam.bind($root)"
class="btn btn-default col-md-12">Add Team</button>
<button type="button" data-bind="enable:competition().teams().length>0,click:$root.removeTeam.bind($root)"
class="btn btn-default col-md-12">Remove Team</button>
<a data-bind="attr:{href:'/teams/create?returnUrl='+window.location.pathname+'/'+competition().id()}"class="btn btn-default">Create a new Team</a>
</div>
<div class="col-md-9">
<select id="teamSelectDropDown" data-bind="options:$root.teams(),optionsText:'name',value:teamToAdd,optionsCaption:'Select a Team to Add..'"
class="dropdown form-control"></select>
<select id="selectedTeams" name="Teams" class="form-control" size="5"
data-bind="options:competition().teams(),optionsText:function(item){return item().name;},value:teamToRemove">
</select>
</div>
</div>
addTeam
按钮点击代码:
self.addTeam = function () {
if ((self.teamToAdd() !== null) && (self.competition().teams().indexOf(self.teamToAdd()) < 0)){// Prevent blanks and duplicates
self.competition().teams().push(self.teamToAdd);
self.competition().teams.valueHasMutated();
}
self.teams.remove(self.teamToAdd());
self.teamToAdd(null);
};
removeTeam
按钮点击代码:
self.removeTeam = function () {
self.teams.push(self.teamToRemove());
self.competition().teams.remove(self.teamToRemove());
self.competition().teams.valueHasMutated();
self.teamToRemove(null);
};
Competition
对象(为简洁起见,删除了一些属性):
function Competition(data) {
var self = this;
self.id = ko.observable(data.id);
self.name = ko.observable(data.name);
self.teams = ko.observableArray(
ko.utils.arrayMap(data.teams, function (team) {
return ko.observable(new Team(team));
}));
};
team
对象:
function Team(data) {
var self = this;
self.id = ko.observable(data.id);
self.name = ko.observable(data.name);
}
有什么遗漏或不清楚?请询问,我将在问题上添加材料。
正如@ user3297291
所建议的那样问题在于,添加到competition.teams
的对象在某些地方是可观察到的,而在其他地方则无法观察到。这在一些地方会导致绑定错误,它会尝试访问observable对象中的observable属性。
更改竞争对象
function Competition(data) {
var self = this;
self.id = ko.observable(data.id);
self.name = ko.observable(data.name);
self.teams = ko.observableArray(
ko.utils.arrayMap(data.teams, function (team) {
return new Team(team);
}));
};
修改了HTML绑定(仅简化了optionsText
绑定)
<div class="form-group">
<div class="col-md-3">
<label for="selectedTeams" class="col-md-12">Select your Teams</label>
<button type="button" data-bind="enable:$root.teams().length>0,click:$root.addTeam.bind($root)"
class="btn btn-default col-md-12">Add Team</button>
<button type="button" data-bind="enable:competition().teams().length>0,click:$root.removeTeam.bind($root)"
class="btn btn-default col-md-12">Remove Team</button>
<a data-bind="attr:{href:'/teams/create?returnUrl='+window.location.pathname+'/'+competition().id()}"class="btn btn-default">Create a new Team</a>
</div>
<div class="col-md-9">
<select id="teamSelectDropDown" data-bind="options:$root.teams(),optionsText:'name',value:teamToAdd,optionsCaption:'Select a Team to Add..'"
class="dropdown form-control"></select>
<select id="selectedTeams" name="Teams" class="form-control" size="5"
data-bind="options:competition().teams(),optionsText:'name',value:teamToRemove">
</select>
</div>
</div>
修订添加团队功能
self.addTeam = function () {
if ((self.teamToAdd() !== null) && (self.competition().teams().indexOf(self.teamToAdd()) < 0)){
self.competition().teams().push(self.teamToAdd());
self.competition().teams.valueHasMutated();
}
self.teams.remove(self.teamToAdd());
self.teamToAdd(null);
};
修订删除团队功能
非常确定我不再需要valueHasMutated()
来电,但至少它有效..
self.removeTeam = function () {
self.teams.push(self.teamToRemove());
self.competition().teams.remove(self.teamToRemove());
self.competition().teams.valueHasMutated();
self.teamToRemove(null);
};
答案 0 :(得分:1)
您正在填充observableArray
个observable
个实例。这通常应该不做:
// Don't do this:
self.teams = ko.observableArray(
ko.utils.arrayMap(data.teams, function(team) {
return ko.observable(new Team(team));
})
);
相反,请包含Team
个实例而不包装它们:
// Do this instead:
self.teams = ko.observableArray(
ko.utils.arrayMap(data.teams, function(team) {
return new Team(team);
})
);
现在,您可以使用“简单”optionsText
绑定,就像您之前所做的那样:
data-bind="optionsText: 'name', /* ... */"
个人偏好:当我们在每个浏览器中都有utils.arrayMap
时,您不需要.map
帮助器。我个人写道:
Team.fromData = data => new Team(data);
// ...
self.teams = ko.observableArray(data.teams.map(Team.fromData));