Вычисляемый наблюдаемый без обновления пользовательского интерфейса

У меня проблема с вычисляемой переменной в моей нокаутирующей сети. Вот мой код:

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>

Другие вопросы по тегам