我一直在开发一个Web应用程序,它将显示一个包含候选列表的表。我想将候选集合(从服务器获取)显示到表中,但是要显示固定行数,假设有5行。因此,如果集合只有2个候选者,那么表格将有5行,前2行只包含数据,其余3行是空行。
我无法使用foreach绑定来解决这个问题,所以我尝试了this 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>
答案 0 :(得分:0)
你可以使用foreach
绑定来获得保证的5行,你只需要一个计算属性来确保5的确切长度。
例如:
NR_OF_ROWS
)pureComputed
并使用foreach
pureComputed
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>
public class LinearLayoutManagerWithSmoothScroller extends LinearLayoutManager {
public LinearLayoutManagerWithSmoothScroller(Context context) {
super(context, HORIZONTAL, false);
}
@Override
public int findFirstVisibleItemPosition() {
return super.findFirstVisibleItemPosition();
}
@Override
public int findLastVisibleItemPosition() {
return super.findLastVisibleItemPosition();
}
public LinearLayoutManagerWithSmoothScroller(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
int position) {
RecyclerView.SmoothScroller smoothScroller = new TopSnappedSmoothScroller(recyclerView.getContext());
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
private class TopSnappedSmoothScroller extends LinearSmoothScroller {
public TopSnappedSmoothScroller(Context context) {
super(context);
}
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return LinearLayoutManagerWithSmoothScroller.this
.computeScrollVectorForPosition(targetPosition);
}
@Override
protected int getVerticalSnapPreference() {
return SNAP_TO_START;
}
}
}