I'm having some issues with a drop-down list where I need to pass the initial value to the view model so, the drop-down list will be populated with an already-selected value.
This is as far as I got (see this fiddle):
var additionalTravellersDetails = [
{ id: 1, firstName: "George", middleName: "", lastName: "Washington ", AcNum: "12345678" },
{ id: 2, firstName: "Abraham ", middleName: "", lastName: "Lincoln", AcNum: "23758383" },
// etc
];
function Traveller(id, AcNum) {
this.id = ko.observable(id);
this.categoryId = ko.observable();
}
Traveller.prototype.getUniqueCategories = function () {
var thisCategoryId = parseInt(this.categoryId(), 10);
return ko.utils.arrayFilter(additionalTravellersDetails, function (additionalTravellersDetails) {
return (additionalTravellersDetails.id === thisCategoryId) || !viewModel.usedCategoryIndex()[additionalTravellersDetails.id];
});
}
var viewModel = {
TravRows: ko.observableArray([]),
addTravRow: function () {
this.TravRows.push(new Traveller());
},
removeTravRow: function (Traveller) {
this.TravRows.remove(Traveller);
},
noOfTrav: ko.observableArray(['1', '2', '3', '4',开发者_如何学编程 '5', '6', '7', '8', '9']),
SelectedNo: ko.observable('1')
};
viewModel.usedCategoryIndex = ko.dependentObservable(function () {
var result = {};
ko.utils.arrayForEach(this.TravRows(), function (Traveller) {
var cat = Traveller.categoryId();
if (cat) {
result[cat] = 1;
}
});
return result;
}, viewModel);
viewModel.TravRows.push(new Traveller());
ko.applyBindings(viewModel);
// On Num of Trav Select index change
$("#nrTravelers").change(function () {
var len = viewModel.noOfTrav().length;
for (var i = 0; i < len; i++) {
viewModel.removeTravRow(viewModel.TravRows()[0]);
}
for (var i = 0; i < $(this).val(); i++) {
viewModel.addTravRow();
}
});
And this is the corresponding view:
<p>Number of travellers:
<select id="nrTravelers" data-bind="options: noOfTrav, selectedOptions: SelectedNo"></select>
</p>
<table data-bind="template: {name:'AdditionalTravelersTemplate', foreach: TravRows}"></table>
<script id="AdditionalTravelersTemplate" type="text/html">
<tr>
<th>Traveler<span>1</span></th> //TODO: replace 1 with the auto num
</tr>
<tr>
<td>
<select data-bind="options: getUniqueCategories(),
optionsText: function(item) {
return item.lastName+ ' , ' + item.firstName+ ' - '+ item.AcNum },
optionsValue: 'id',
optionsCaption: 'choose one...',
value: categoryId"></select >
</td>
</tr >
</script>
The following are the things I need in the above code:
- I want to pre populate all the drop-down lists with already selected values
- When the list does not contain any more travelers, I want to display some text in the drop down list
- I want to add a number after "Traveler" text for each drop-down list
The 2nd requirement I have solved, two more to go.
PS. I have hard coded some part for the first requirement, please tell me if the approach is OK?
Any suggestions/ideas please?
Here are a couple of ideas here: http://jsfiddle.net/rniemeyer/P6aDk/
For the index, you could either use {{each}}
from jQuery template's or an easy way to still get the benefits of KO's foreach
is to create a manual subscription to your observableArray and update/create a property to hold the position. This would be like:
viewModel.TravRows.subscribe(function(currentValue) {
for (var i = 0, j = currentValue.length; i < j; i++) {
var row = currentValue[i];
if (!row.position) {
row.position = ko.observable(i+1);
} else {
row.position(i+1);
}
}
});
Now, each row will have a "position" observable that you can bind against and they will stay updated as the array changes.
For, adding/removing rows, you could add a subscription against the SelectedNo
observable and when it changes you can reconcile the actual number of rows. Like:
viewModel.SelectedNo.subscribe(function(newValue) {
var actualLen = viewModel.TravRows().length,
expectedLen = parseInt(newValue, 10);
if (actualLen < expectedLen) {
for (var i = actualLen; i < expectedLen; i++) {
viewModel.addTravRow();
}
} else {
for (var i = actualLen; i > expectedLen; i--) {
viewModel.removeTravRow(viewModel.TravRows()[i]);
}
}
});
For setting existing data, I changed the value
binding on the dropdown for each row to bind against the id
. Then, I set the initial data to include two Travellers with their ids. You could switch this to account number or whatever is appropriate.
精彩评论