Вычисляемый наблюдаемый без обновления пользовательского интерфейса
У меня проблема с вычисляемой переменной в моей нокаутирующей сети. Вот мой код:
function ViewModel() {
var self = this;
self.seatsRaw = ko.observableArray([]);
self.selectedSeatId = ko.observable();
self.session = ko.observable();
self.seats = ko.computed(function(){
var seatsComplete= self.seatsRaw().slice(0);
for (var i = 0; i < seatsComplete.length; i++) {
if (self.selectedSeatId()) {
seatsComplete[i].selected = seatsComplete[i].id == self.selectedSeatId();
} else if (self.session () && Number(self.session ().seat) > 0) {
seatsComplete[i].selected = seatsComplete[i].id == self.sesion().seat;
} else {
seatsComplete[i].selected = false;
}
}
return seatsComplete;
});
self.selectSeat = function(data,event) {
self.selectedSeatId($(this).id);
};
}
Итак, я просто получаю массив с местами и хочу добавить поле для каждого объекта в массиве, чтобы оно отображалось в пользовательском интерфейсе как "выбранный".
Я читаю из ajax информацию для сессии и сырых мест, и когда я обновляю их, я не вижу никаких изменений в своем пользовательском интерфейсе.
Почему происходит? И затем, что мне нужно сделать, чтобы обновить мой интерфейс?
Спасибо!
РЕДАКТИРОВАТЬ
<ul class="seats" data-bind="foreach: seats">
<li data-bind="css: {selected: selected, 'non-selected': !selected}, click: $root.selectSeat">
<a href="#" data-bind="attr: {id: id}">
<img data-bind="attr: {src: baseUrl + 'img/seats/' + image}" />
<p data-bind="text: name"></p>
</a>
</li>
</ul>
Seat не ViewModel... это должно быть?
1 ответ
Спасибо за предоставление дополнительного контекста. Я постараюсь объяснить немного лучше, что я имел в виду в комментариях.
Seat не ViewModel... это должно быть?
Даже когда Seat
это просто простой объект, это тоже вид модели представления... Вот что происходит в вашем коде (насколько я могу судить):
Когда вы создаете новый массив в ваших вычислениях, он заполняется теми же объектами, что и предыдущий массив. Нокаут-рендеринг не видит причин для повторного рендеринга элементов списка.
Проверьте этот пример. Из логов вы видите, что все "работает правильно", но нокаут не будет обновляться. После этого примера я покажу, что произойдет, если мы сделаем selected
наблюдаемым.
var seats =[
{ id: 1, selected: false },
{ id: 2, selected: true },
{ id: 3, selected: false }
];
var ViewModel = function() {
var self = this;
this.rawSeats = ko.observableArray(seats);
this.selectedSeatId = ko.observable(2);
this.selectSeat = function(data, event) {
self.selectedSeatId(data.id)
}
this.seats = ko.computed(function() {
var selectedId = self.selectedSeatId();
self.rawSeats().forEach(function(seat) {
seat.selected = seat.id === selectedId;
})
console.log(self.rawSeats());
return self.rawSeats();
});
}
ko.applyBindings(new ViewModel());
.selected { background: yellow }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<ul data-bind="foreach: seats">
<li data-bind="css: { selected: selected },
text: id,
click: $root.selectSeat"></li>
</ul>
Теперь с наблюдаемыми свойствами:
var seats =[
{ id: 1, selected: ko.observable(false) },
{ id: 2, selected: ko.observable(true) },
{ id: 3, selected: ko.observable(false) }
];
var ViewModel = function() {
var self = this;
this.rawSeats = ko.observableArray(seats);
this.selectedSeatId = ko.observable(2);
this.selectSeat = function(data, event) {
self.selectedSeatId(data.id)
}
this.seats = ko.computed(function() {
var selectedId = self.selectedSeatId();
self.rawSeats().forEach(function(seat) {
seat.selected(seat.id === selectedId);
})
return self.rawSeats();
});
}
ko.applyBindings(new ViewModel());
.selected { background: yellow }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<ul data-bind="foreach: seats">
<li data-bind="css: { selected: selected },
text: id,
click: $root.selectSeat"></li>
</ul>