AngularJS Почему эта переменная контроллера не обновляется в пользовательском интерфейсе? - PullRequest
1 голос
/ 01 февраля 2020

У меня есть контроллер, использующий Stomp JS для подписки на URL-адрес (back-end - это Spring Java), который возвращает чередующиеся строки "list" и "box" каждые 5 секунд. Я хочу обновить свой элемент пользовательского интерфейса, когда Stomp JS получает некоторые данные, но мне не удалось обновить элемент пользовательского интерфейса. Я протестировал ту же логику c с $timeout, и пользовательский интерфейс обновляется, поэтому он должен иметь какое-то отношение к тому, как работает функция обратного вызова. Кто-нибудь может понять, по какой причине пользовательский интерфейс не обновляется?

У меня есть следующие простые элементы пользовательского интерфейса:

<input ng-model="ctrl.uniqueId"/>
<input ng-model="test"/>

ctrl.uniqueId, чтобы проверить, обновляется ли фактический экземпляр контроллера. По какой-то причине только один контроллер делает 5 разных подписок каждый раз. Если кто-то может помочь с этим, это тоже было бы здорово, но я сомневаюсь, что вы можете получить много информации, если вы не увидите все мои настройки кода. работать, поэтому я попытался с $ scope.test, чтобы увидеть, если это имеет значение):

self.uniqueId = window.performance.now();
$scope.test = 'list';

// the UI will be updated to dummy after 3 seconds.
$timeout(function() {
    $scope.test="dummy";
}, 3000);

// the UI will not update.
var callBackFn = function(progress) {
    $scope.test = progress;
    console.log(self.uniqueId + ": " + $scope.test);
};

// the server returns alternating data (list and box) every 5 seconds
MyService.subscribeForUpdate('/topic/progressResults', callBackFn);

Это код моей службы для Stomp JS, если это имеет значение:

self.subscribeForUpdate = function(channelUrl, callBackFn) {
    self.socket.stomp.connect({}, function() {
        self.socket.subscription = self.socket.stomp.subscribe(channelUrl, 
            function (result) {
                //return angular.fromJson(result.body);
                callBackFn(result.body);
                return result.body;
            }
        );
    });
};

Это console.log результаты:

1831.255000026431: list
1831.255000026431: box

Дополнительно: возможно ли получить возвращаемые данные без функции обратного вызова, аналогичной Promise?

Ответы [ 2 ]

2 голосов
/ 01 февраля 2020

Обязательно используйте $apply:

app.service("myService", function($rootScope) {
    var self = this;
    self.subscribeForUpdate = function(channelUrl, callBackFn) {
        self.socket.stomp.connect({}, function() {
            self.socket.subscription = self.socket.stomp.subscribe(channelUrl, 
                function (result) {
                    //return angular.fromJson(result.body);
                    $rootScope.$apply(function() {
                        callBackFn(result.body);
                    });
                    return result.body;
                }
            );
        });
    };
})

AngularJS изменяет обычный поток JavaScript, предоставляя собственную обработку событий l oop. Это разбивает JavaScript на классический и AngularJS контекст выполнения. Только операции, которые применяются в контексте выполнения AngularJS, получат выгоду от AngularJS привязки данных, обработки исключений, отслеживания свойств и т. Д. c ... Вы также можете использовать $apply() для входа в AngularJS контекст выполнения из JavaScript.

Имейте в виду, что в большинстве мест (контроллеры, службы) $ apply имеет уже был вызван для вас директивой, которая обрабатывает событие. Явный вызов $ apply требуется только при реализации пользовательских обратных вызовов событий или при работе с сторонними обратными вызовами библиотеки.

Для получения дополнительной информации см.

1 голос
/ 01 февраля 2020

Это очень распространенная проблема, которая возникает, когда сторонняя библиотека (из среды angular) используется с angularjs. В таких случаях вам нужно вручную запустить цикл дайджеста, используя:

$scope.$apply()

После этого все привязки angular будут обновлены. Использование $ timeout (даже без timeValue) имеет тот же результат, что и запускает $apply()

...