Reputation: 31732
The example is taken from knockout tutorials - working with lists and collections.
<table>
<thead>
<tr>
<th>Passenger name</th>
<th>Meal</th>
<th>Surcharge</th>
<th></th>
</tr>
</thead>
<!-- Todo: Generate table body -->
<tbody data-bind="foreach: seats">
<tr>
<td>
<input data-bind="value: name" />
</td>
<td>
<select data-bind="options: $root.availableMeals, value: meal, optionsText: 'mealName'"></select>
</td>
<td data-bind="text: formattedPrice"></td>
</td>
</tr>
</tbody>
</table>
<button data-bind="click: addSeat">Reserve another seat</button>
ReservationsViewModel()
adds a row of elements dynamically to a static table
on button (Reserve another seat) click that is bound to addSeat
with click
event listener.
function ReservationsViewModel() {
var self = this;
...
self.addSeat = function () {
self.seats.push(new SeatReservation("", self.availableMeals[0]));
}
...
}
by calling SeatReservation()
function SeatReservation(name, initialMeal) {
var self = this;
self.name = name;
self.meal = ko.observable(initialMeal);
}
How can I retrieve the added elements from DOM (not the clicked element) from within SeatReservation()
.
Edit: As far as I understand knockout's foreach
binding, it repeats child elements. What I'm trying to achieve is, have access to those elements once they are added into DOM.
Upvotes: 0
Views: 131
Reputation: 8053
With this binding handler:
ko.bindingHandlers.selectmenu = {
init: function (element, valueAccessor, allBindings, viewModel, context) {
$(element).parent().trigger("create");
//you can customize the code depending on valueAccessor and allBindings
//here
}
}
Used like this:
<select data-bind="selectmenu: {option1: optFromModel1, option2: optFromModel2},
options: $root.availableMeals,
value: meal,
optionsText: 'mealName'"></select>
It works (and you can replace the pagebeforecreate
with ready
)
Source for the select menu update: https://forum.jquery.com/topic/no-style-to-dynamic-select-element
Upvotes: 1
Reputation: 46476
You can use a post-processing property such as afterRender
in the foreach
binding.
See Note 7 on http://knockoutjs.com/documentation/foreach-binding.html
The afterRender
callback will need to be defined on your main view model, but since it is passed the current data item as a parameter, you can use this to call a function on SeatReservation
and pass the DOM elements in.
<tbody data-bind="foreach: { data: seats, afterRender: afterSeatRender }">
function SeatReservation(name, initialMeal) {
// ...
self.afterRender = function (elements) {
$(elements).css('background-color', 'green');
};
}
function ReservationsViewModel() {
// ...
self.afterSeatRender = function (elements, seat) {
seat.afterRender(elements);
};
}
Here is an updated fiddle: http://jsfiddle.net/4J3Pf/2/
Having said that, the whole point of Knockout is to use data binding instead of manipulating the DOM directly. The Knockout documentation makes it clear that this is not a normal use case:
These callbacks are only intended for triggering animations related to changes in a list.
In particular, manipulating the DOM within your SeatReservation
view model is the wrong design. Try to keep your view models and your view rendering code separate.
Upvotes: 2