如何通过索引将 observableArray 绑定到元素
How to bind observableArray by index to the element
我一直在开发一个 Web 应用程序,它将显示 table 包含候选人列表。我想将候选集合(从服务器获取)显示到 table,但要显示固定的行数,比方说 5 行。因此,如果集合只有 2 个候选人,table 将有 5 行,只有前 2 行包含数据,其余 3 行是空行。
我无法使用 foreach 绑定来解决这个问题,所以我尝试了 this post。
因为 post observableArray 中的对象是不可观察的,所以我试图让它们可观察并且它仍然有效。但是当我在我的代码中尝试时,它在我的 js 中抛出错误:
Unable to process binding "text: function (){return Candidates[0]().CandidateNumber }"
Message: AssignedCandidates[0] is not a function
我仍然不确定我错过了什么。请帮忙。
这是我的 js 文件:
var CandidateViewModel = function (data) {
var self = this;
self.CandidateId = ko.observable();
self.CandidateNumber = ko.observable();
self.Name = ko.observable();
self.Status = ko.observable()
ko.mapping.fromJS(data, {}, self);
}
var mappingCandidateList = {
Candidates: {
create: function (options) {
return new CandidateViewModel(options.data);
}
}
}
var CandidateListViewModel = function (data) {
var self = this;
self.Candidates = ko.observableArray();
self.AssignedCount = ko.observable();
self.ProcessingCount = ko.observable();
self.RejectingCount = ko.observable();
self.PassedCount = ko.observable();
self.FailedCount = ko.observable();
self.PagingInfo = ko.observable();
var getData = function (param) {
$.ajax({
url: api("Candidate/GetCandidates"),
data: param,
type: 'GET',
dataType: 'JSON'
}).done(function (data) {
ko.mapping.fromJS(data, mappingCandidateList, self);
});
}
}
ko.applyBindings(new CandidateListViewModel (), document.getElementById('candidate-container'));
这是 html
<table>
<thead>
<tr>
<th>number</th>
<th>name</th>
<th>status</th>
</tr>
</thead>
<tbody>
<tr>
<td data-bind="text: Candidates()[0].CandidateNumber"></td>
<td data-bind="text: Candidates()[0].Name"></td>
<td data-bind="text: Candidates()[0].Status"></td>
</tr>
</tbody>
</table>
您 可以 使用 foreach
绑定来获得保证的 5 行,您只需要一个计算的 属性 来确保5.
例如:
- 定义固定行数(
NR_OF_ROWS
)
- 创建一个
pureComputed
并使用 foreach
绑定到它
- 使
pureComputed
return 成为一个长度为 NR_OF_ROWS
的数组
- 循环这个数组并为每个有可用索引的索引注入一个
candidate
- 如果没有更多候选项,则注入一个空候选项,告诉您的视图要呈现什么。
var VM = function() {
const NR_OF_ROWS = 5;
this.candidates = ko.observableArray([
{ id: 1, firstName: "Jane", lastName: "Doe" },
{ id: 2, firstName: "John", lastName: "Doe" }
]);
this.displayRows = ko.pureComputed(function() {
const emptyCandidate = { id: "-", firstName: "-", lastName: "-", empty: true };
const candidates = this.candidates();
const rows = [];
for (let i = 0; i < NR_OF_ROWS; i += 1) {
rows.push(candidates[i] || emptyCandidate);
}
return rows;
}, this);
// For demo
this.newCandidate = {
firstName: ko.observable(""),
lastName: ko.observable(""),
add: function() {
this.candidates.push({
firstName: this.newCandidate.firstName(),
lastName: this.newCandidate.lastName(),
id: this.candidates().length + 1
})
}.bind(this)
}
}
ko.applyBindings(new VM());
tr:nth-child(even) { background: #efefef; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table>
<thead>
<tr>
<th>ID</th>
<th>First Name</th>
<th>Last Name</th>
</tr>
</thead>
<tbody data-bind="foreach: displayRows">
<td data-bind="text: id"></td>
<td data-bind="text: firstName"></td>
<td data-bind="text: lastName"></td>
</tbody>
</table>
<div data-bind="with: newCandidate">
<input type="text" placeholder="first name" data-bind="textInput: firstName">
<input type="text" placeholder="last name" data-bind="textInput: lastName">
<button data-bind="click: add">add</button>
</div>
编辑: 如果您更愿意为空行使用特殊视图,而不是特殊视图模型,您可以使用模板:
var VM = function() {
const NR_OF_ROWS = 5;
this.candidates = ko.observableArray([
{ id: 1, firstName: "Jane", lastName: "Doe" },
{ id: 2, firstName: "John", lastName: "Doe" }
]);
this.displayRows = ko.pureComputed(function() {
const candidates = this.candidates();
const rows = [];
for (let i = 0; i < NR_OF_ROWS; i += 1) {
rows.push(candidates[i] || emptyCandidate);
}
return rows;
}, this);
// For demo
this.newCandidate = {
firstName: ko.observable(""),
lastName: ko.observable(""),
add: function() {
this.candidates.push({
firstName: this.newCandidate.firstName(),
lastName: this.newCandidate.lastName(),
id: this.candidates().length + 1
})
}.bind(this)
}
}
ko.applyBindings(new VM());
tr:nth-child(even) { background: #efefef; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table>
<thead>
<tr>
<th>ID</th>
<th>First Name</th>
<th>Last Name</th>
</tr>
</thead>
<tbody data-bind="foreach: displayRows">
<td data-bind="text: id"></td>
<td data-bind="text: firstName"></td>
<td data-bind="text: lastName"></td>
</tbody>
</table>
<div data-bind="with: newCandidate">
<input type="text" placeholder="first name" data-bind="textInput: firstName">
<input type="text" placeholder="last name" data-bind="textInput: lastName">
<button data-bind="click: add">add</button>
</div>
我一直在开发一个 Web 应用程序,它将显示 table 包含候选人列表。我想将候选集合(从服务器获取)显示到 table,但要显示固定的行数,比方说 5 行。因此,如果集合只有 2 个候选人,table 将有 5 行,只有前 2 行包含数据,其余 3 行是空行。
我无法使用 foreach 绑定来解决这个问题,所以我尝试了 this post。
因为 post observableArray 中的对象是不可观察的,所以我试图让它们可观察并且它仍然有效。但是当我在我的代码中尝试时,它在我的 js 中抛出错误:
Unable to process binding "text: function (){return Candidates[0]().CandidateNumber }"
Message: AssignedCandidates[0] is not a function
我仍然不确定我错过了什么。请帮忙。
这是我的 js 文件:
var CandidateViewModel = function (data) {
var self = this;
self.CandidateId = ko.observable();
self.CandidateNumber = ko.observable();
self.Name = ko.observable();
self.Status = ko.observable()
ko.mapping.fromJS(data, {}, self);
}
var mappingCandidateList = {
Candidates: {
create: function (options) {
return new CandidateViewModel(options.data);
}
}
}
var CandidateListViewModel = function (data) {
var self = this;
self.Candidates = ko.observableArray();
self.AssignedCount = ko.observable();
self.ProcessingCount = ko.observable();
self.RejectingCount = ko.observable();
self.PassedCount = ko.observable();
self.FailedCount = ko.observable();
self.PagingInfo = ko.observable();
var getData = function (param) {
$.ajax({
url: api("Candidate/GetCandidates"),
data: param,
type: 'GET',
dataType: 'JSON'
}).done(function (data) {
ko.mapping.fromJS(data, mappingCandidateList, self);
});
}
}
ko.applyBindings(new CandidateListViewModel (), document.getElementById('candidate-container'));
这是 html
<table>
<thead>
<tr>
<th>number</th>
<th>name</th>
<th>status</th>
</tr>
</thead>
<tbody>
<tr>
<td data-bind="text: Candidates()[0].CandidateNumber"></td>
<td data-bind="text: Candidates()[0].Name"></td>
<td data-bind="text: Candidates()[0].Status"></td>
</tr>
</tbody>
</table>
您 可以 使用 foreach
绑定来获得保证的 5 行,您只需要一个计算的 属性 来确保5.
例如:
- 定义固定行数(
NR_OF_ROWS
) - 创建一个
pureComputed
并使用foreach
绑定到它
- 使
pureComputed
return 成为一个长度为NR_OF_ROWS
的数组
- 循环这个数组并为每个有可用索引的索引注入一个
candidate
- 如果没有更多候选项,则注入一个空候选项,告诉您的视图要呈现什么。
var VM = function() {
const NR_OF_ROWS = 5;
this.candidates = ko.observableArray([
{ id: 1, firstName: "Jane", lastName: "Doe" },
{ id: 2, firstName: "John", lastName: "Doe" }
]);
this.displayRows = ko.pureComputed(function() {
const emptyCandidate = { id: "-", firstName: "-", lastName: "-", empty: true };
const candidates = this.candidates();
const rows = [];
for (let i = 0; i < NR_OF_ROWS; i += 1) {
rows.push(candidates[i] || emptyCandidate);
}
return rows;
}, this);
// For demo
this.newCandidate = {
firstName: ko.observable(""),
lastName: ko.observable(""),
add: function() {
this.candidates.push({
firstName: this.newCandidate.firstName(),
lastName: this.newCandidate.lastName(),
id: this.candidates().length + 1
})
}.bind(this)
}
}
ko.applyBindings(new VM());
tr:nth-child(even) { background: #efefef; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table>
<thead>
<tr>
<th>ID</th>
<th>First Name</th>
<th>Last Name</th>
</tr>
</thead>
<tbody data-bind="foreach: displayRows">
<td data-bind="text: id"></td>
<td data-bind="text: firstName"></td>
<td data-bind="text: lastName"></td>
</tbody>
</table>
<div data-bind="with: newCandidate">
<input type="text" placeholder="first name" data-bind="textInput: firstName">
<input type="text" placeholder="last name" data-bind="textInput: lastName">
<button data-bind="click: add">add</button>
</div>
编辑: 如果您更愿意为空行使用特殊视图,而不是特殊视图模型,您可以使用模板:
var VM = function() {
const NR_OF_ROWS = 5;
this.candidates = ko.observableArray([
{ id: 1, firstName: "Jane", lastName: "Doe" },
{ id: 2, firstName: "John", lastName: "Doe" }
]);
this.displayRows = ko.pureComputed(function() {
const candidates = this.candidates();
const rows = [];
for (let i = 0; i < NR_OF_ROWS; i += 1) {
rows.push(candidates[i] || emptyCandidate);
}
return rows;
}, this);
// For demo
this.newCandidate = {
firstName: ko.observable(""),
lastName: ko.observable(""),
add: function() {
this.candidates.push({
firstName: this.newCandidate.firstName(),
lastName: this.newCandidate.lastName(),
id: this.candidates().length + 1
})
}.bind(this)
}
}
ko.applyBindings(new VM());
tr:nth-child(even) { background: #efefef; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table>
<thead>
<tr>
<th>ID</th>
<th>First Name</th>
<th>Last Name</th>
</tr>
</thead>
<tbody data-bind="foreach: displayRows">
<td data-bind="text: id"></td>
<td data-bind="text: firstName"></td>
<td data-bind="text: lastName"></td>
</tbody>
</table>
<div data-bind="with: newCandidate">
<input type="text" placeholder="first name" data-bind="textInput: firstName">
<input type="text" placeholder="last name" data-bind="textInput: lastName">
<button data-bind="click: add">add</button>
</div>