У меня есть угловой вид, который имеет таблицу строк, состоящую из списка выбора и текстового поля. Когда индекс списка выбора изменяется, мне нужно обновить соответствующее текстовое поле в той же строке с помощью значения поиска из базы данных. Я использую ng-Change в списке выбора для вызова функции $ scope, которая использует $ http.get для вызова через ActionMethod. Я пробовал это в миллион способов и, наконец, смог извлечь значение из функции $ http.get, назначив его переменной области видимости, но я только когда-либо получаю значение предыдущего поиска, вызванного выбранным изменением индекса, а не текущий. Как я могу получить значение в режиме реального времени? Я понимаю, что это асинхронно, поэтому я знаю характер проблемы. Как мне обойти это? Текущее состояние моего.js:
$scope.EntityId = null;
$scope.EntityNameChanged = function (item, block) {
for (var i = 0; i < block.length; i++)
{
if (item.Value == block[i].Name.Value) {
$scope.GetEntityId(item.Value);
block[i].Id = $scope.EntityId;
}
}
}
$scope.GetEntityId = function(name) {
$http.get("EntityId", { params: { EntityName: name } }).then(function success(response) {
$scope.EntityId = response.data[0].Value;
});
};
Функция GetEntityID
должна вернуть обещание
function GetEntityId(name) {
//save httpPromise
var p = $http.get("EntityId", { params: { EntityName: name } });
//return derived promise
return p.then(function onSuccess(response) {
//return chained data
return response.data[0].Value;
});
};
Затем используйте IIFE в цикле for
.
$scope.EntityNameChanged = function (item, block) {
for (var i = 0; i < block.length; i++) {
//USE IIFE to hold value of i
(function IIFE(i) {
if (item.Value == block[i].Name.Value) {
//save promise
var p = GetEntityId(item.Value);
//extract value from promise
p.then(function onSuccess(Value) {
block[i].Id = Value;
});
}
})(i);
}
}
Поскольку функция onSuccess
запускается асинхронно после завершения цикла for
, закрытие IIFE необходимо для сохранения значения i
до тех пор, пока данные не будут возвращены с сервера.
Функция GetEntityId
не является асинхронной, даже если она выполняет асинхронный запрос. к тому времени, когда он устанавливает $scope.EntityId
, цикл for уже вышел.
Вы не можете на самом деле очереди асинхронных вызовов, например, потому что каждый из них пытается поделиться значением вне цикла, которое может быть установлено любой другой итерацией, поэтому один элемент в цикле может получить другое возвращаемое значение элемента.
Вместо этого вы должны вернуть обещание обратно в цикл и выполнить ваш. .then
в цикле. Что-то вроде следующего:
$scope.EntityNameChanged = function(item, block) {
for (var i = 0; i < block.length; i++) {
if (item.Value == block[i].Name.Value) {
$scope.GetEntityId(item.Value)
.then(function success(response) {
block[i].Id = response.data[0].Value;
});
}
}
}
$scope.GetEntityId = function(name) {
return $http.get("EntityId", {
params: {
EntityName: name
}
});
};
(обратите внимание, что это не проверено, но должно делать то, что вы ожидаете).
block
определенно должен быть доступен в .then
, если .then
находится внутри цикла; Возможно, я смогу создать тестируемый пример позже.
Чтобы заставить Angular обновить значение области в цикле $ watch, вызовите $scope.apply()
после назначения. Это должно привести к последнему значению.
EDIT: Этот ответ был неправильным. Это запрос $ http get, который уже использует $ apply. Что вам нужно сделать, это поместить запрос на завод и вернуть обещание. Требовать фабрику в контроллере.
app.factory('getData', function ($http, $q){
this.getlist = function(){
return $http.get('mylink', options)
.then(function(response) {
return response.data.itemsToReturn;
});
}
return this;
});
app.controller('myCtrl', function ($scope, getData){
app.getData()
.then(function(bar){
$scope.foo = bar;
});
});