KnockoutJS - Разочарование с помощью ko.computed и запроса AJAX
Я просто пытаюсь вытащить некоторые данные из запроса ajax. Работает вызов ajax - я знаю, что данные извлекаются. Но это просто не устанавливает значение ko.computed...
function viewModel() {
this.Id = ko.observable("@Model.Identity()");
this.Points = ko.computed({
read: function () {
$.ajax({
url: '/skills/points',
data: { id: this.Id },
type: 'get',
success: function (data) {
return data;
}
});
},
owner: this
});
}
Итак, вызов вроде...
<span data-bind="text: Points"></span>
Просто не работает. Может ли кто-нибудь помочь мне разобраться, что я делаю неправильно?
Update
Я использую следующий код, следуя предложению RPN, и я просто не могу заставить его функционировать вообще. Он не будет смотреть на контроллер, он не вернет данные... он просто ничего не делает. Я пробовал все три примера без успеха.
<script type="text/javascript">
//an observable that retrieves its value when first bound
ko.onDemandObservable = function (callback, target) {
var _value = ko.observable(); //private observable
var result = ko.computed({
read: function () {
//if it has not been loaded, execute the supplied function
if (!result.loaded()) {
callback.call(target);
}
//always return the current value
return _value();
},
write: function (newValue) {
//indicate that the value is now loaded and set it
result.loaded(true);
_value(newValue);
},
deferEvaluation: true //do not evaluate immediately when created
});
//expose the current state, which can be bound against
result.loaded = ko.observable();
//load it again
result.refresh = function () {
result.loaded(false);
};
return result;
};
$(document).ready(function () {
function User(id, name) {
this.Id = ko.observable(id);
this.Name = ko.observable(name);
}
function viewModel() {
var self = this;
this.User = ko.onDemandObservable(this.Update, this);
this.Update = function () {
return $.ajax({
url: '/home/user/',
data: { id: 1 },
dataType: 'json'
}).pipe(function (data) {
return new User(data.Id, data.Name);
});
};
};
var model = new viewModel();
ko.applyBindings(model);
model.User();
});
</script>
<span data-bind="text: User.Name"></span>
Обновление (2)
Следуя дальнейшим инструкциям, я сузил часть проблемы. Определение callback
как функции на viewModel, похоже, не работает (я не уверен, почему), но объявление встроенной функции дает... что-то другое. Тем не менее, все еще не работает. Вот обновление.
<script type="text/javascript">
//an observable that retrieves its value when first bound
ko.onDemandObservable = function (callback, target) {
var _value = ko.observable(); //private observable
var result = ko.computed({
read: function () {
//if it has not been loaded, execute the supplied function
if (!result.loaded()) {
callback.call(target);
}
//always return the current value
return _value();
},
write: function (newValue) {
//indicate that the value is now loaded and set it
result.loaded(true);
_value(newValue);
},
deferEvaluation: true //do not evaluate immediately when created
});
//expose the current state, which can be bound against
result.loaded = ko.observable();
//load it again
result.refresh = function () {
result.loaded(false);
};
return result;
};
$(document).ready(function () {
function User(id, name) {
this.Id = ko.observable(id);
this.Name = ko.observable(name);
}
function viewModel() {
var self = this;
this.User = ko.onDemandObservable(function(){
$.ajax({
url: '/home/user/',
data: { id: 1 },
dataType: 'json',
success: function (data) {
self.User(new User(data.Id, data.Name));
}
});
}, this);
//this.Update = function () {
// $.ajax({
// url: '/home/user/',
// data: { id: 1 },
// dataType: 'json',
// success: function (data) {
// self.User(new User(data.Id, data.Name));
// }
// });
//};
};
var model = new viewModel();
ko.applyBindings(model);
model.User();
});
</script>
И затем попытка отобразить любую из полученных данных все еще не удается.
<span data-bind="text: User.Name"></span>
Обновление (3)
Немного прорыва! Если я изменяю декларативное привязку, чтобы выглядеть так.
<span data-bind="with: User">
<span data-bind="text: Id"></span>
<span data-bind="text: Name"></span>
</span>
Затем я начинаю видеть результаты. Я думаю, что я почти добираюсь туда...
Ответы
Ответ 1
Как отметил СЛАКС, вы не можете сделать это так, потому что вызов выполняется асинхронно, то есть функция "читать" возвращается до получения ответа. Я бы рекомендовал что-то вроде этого:
function viewModel() {
var self = this;
this.Id = ko.observable("@Model.Identity()");
this.Points = ko.observable(0);
var refreshPoints = function() {
$.ajax({
url: '/skills/points',
data: { id: self.Id() }, // <-- you need () here!
type: 'get',
success: function (data) {
self.Points(data);
}
});
};
// Now subscribe to the ID observable to update the points whenever the
// ID gets changed:
this.Id.subscribe(refreshPoints);
}
Ответ 2
Просто привяжите наблюдаемую переменную к переменной html и обновите это поле в поле ko.put. Не привязывайте поле ko.computed к переменной html напрямую.
self.htmlUserName = ko.observable();
self.computedUserName = ko.computed(function () {
$.ajax(
....
success: function (result) {
self.htmlUserName(result);
}
}
Ответ 3
Связывание нокаутом не поддерживает асинхронные вычисления.
Вместо этого вы должны использовать регулярное свойство и установить его на результат запроса AJAX.
Вы можете сделать это наблюдаемым, повторно отправив запрос AJAX в обработчик изменений для зависимого свойства.
Вы также можете использовать отдельное значение-заполнитель, чтобы добавить индикатор загрузки в ваш связанный интерфейс.