Может ли AngularJS автоматически обновлять представление, если постоянная модель (серверная база данных) изменена внешним приложением?

81

Я только начинаю знакомиться с AngularJS, но я хотел бы создать веб-приложение с представлением, которое автоматически обновляется в режиме реального времени (без обновления) для пользователя, когда что-то меняется в серверной базе данных.

Может ли AngularJS справиться с этим (в основном) автоматически? И если да, то каков основной механизм работы?

Например, вы каким-то образом настраиваете AngularJS для регулярного опроса БД на предмет «модельных» изменений? Или использовать какой-то механизм, похожий на Comet, чтобы уведомить клиентский код AngularJS об изменении модели?

В моем приложении проблема заключается в том, что другое (не веб) серверное программное обеспечение будет время от времени обновлять базу данных. Но этот вопрос в равной степени относится и к чистым веб-приложениям, где у вас может быть несколько клиентов, изменяющих базу данных через веб-клиенты AngularJS, и каждый из них необходимо обновлять, когда один из них вносит изменения в БД (модель).

jpeskin
источник
Я хотел бы добавить, что с тех пор я обнаружил, что Meteor делает все это за вас в рамках, так что на данный момент это мое предпочтительное решение. Возможно, снова попробую Angular в будущем.
jpeskin
Meteor может быть все еще слишком "свежим" - с ним можно поиграть, но в большом производстве он не показал себя (безопасность / масштабируемость / производительность / и т. Д.). Аутентификация была добавлена ​​чуть больше месяца назад. Выглядит неплохо, но подожду.
Алекс Окрушко
@jpeskin Привет. Я примерно знаю, где вы были, когда задали этот вопрос. Чем ты закончил? (Я бы хотел использовать Angular). С уважением, Марк
mark1234

Ответы:

97

У вас есть несколько вариантов ...

  1. Вы можете проводить опрос каждые X миллисекунд, используя $timeoutи $http, или, если данные, которые вы используете, подключены к службе REST, вы можете использовать $resourceвместо $http.

  2. Вы можете создать службу, которая использует некоторую реализацию Websocket и использует scope.$applyдля обработки изменений, внесенных сокетом. Вот пример использования socket.io, библиотеки websocket node.js:

    myApp.factory('Socket', function($rootScope) {
        var socket = io.connect('http://localhost:3000');
    
        //Override socket.on to $apply the changes to angular
        return {
            on: function(eventName, fn) {
                socket.on(eventName, function(data) {
                    $rootScope.$apply(function() {
                        fn(data);
                    });
                });
            },
            emit: socket.emit
        };
    })
    
    function MyCtrl($scope, Socket) {
        Socket.on('content:changed', function(data) {
            $scope.data = data;
        });
        $scope.submitContent = function() {
            socket.emit('content:changed', $scope.data);
        };
    }
    
  3. Вы можете получить действительно высокие технологии и создать реализацию веб-сокета, которая синхронизирует модель Angular с сервером. Когда клиент что-то меняет, это изменение автоматически отправляется на сервер. Или, если сервер меняется, он отправляется клиенту.
    Вот пример этого в старой версии Angular, снова с использованием socket.io: https://github.com/mhevery/angular-node-socketio

РЕДАКТИРОВАТЬ : для № 3 я использовал Firebase для этого.

Эндрю Джослин
источник
Спасибо за столь подробный ответ с несколькими вариантами! С нетерпением жду возможности
разобраться
4
github.com/mhevery/angular-node-socketio - ошибка написания. исправил
Эндрю Джослин
Спасибо за простой для понимания ответ, очень полезный.
mystrdat
Как бы вы продолжили отвязку обработчиков событий, если нужно уничтожить контроллер?
RushPL
У Брайана Форда есть отличный подход, который позволяет вам использовать систему событий и очистку $ scope. И делает действительно чистым в целом. github.com/btford/angular-socket-io . Посмотрите на socket.forward ()
Эндрю Джослин
15

Вот реализация, которая использует причал вместо узла. Часть angularjs основана на приложении angular-seed. Я не уверен, что код angular идиоматичен ... но я проверил, что это работает. HTH -Todd.

TimerWebSocketServlet см.

https://gist.github.com/3047812

controllers.js

// -------------------------------------------------------------
// TimerCtrl
// -------------------------------------------------------------
function TimerCtrl($scope, CurrentTime) {
    $scope.CurrentTime = CurrentTime;
    $scope.CurrentTime.setOnMessageCB(
        function (m) {
            console.log("message invoked in CurrentTimeCB: " + m);
            console.log(m);
            $scope.$apply(function(){
                $scope.currentTime = m.data;
            })
        });
}
TimerCtrl.$inject = ['$scope', 'CurrentTime'];

services.js

angular.module('TimerService', [], function ($provide) {
    $provide.factory('CurrentTime', function () {
        var onOpenCB, onCloseCB, onMessageCB;
        var location = "ws://localhost:8888/api/timer"
        var ws = new WebSocket(location);
        ws.onopen = function () {
            if(onOpenCB !== undefined)
            {
                onOpenCB();
            }
        };
        ws.onclose = function () {
            if(onCloseCB !== undefined)
            {
                onCloseCB();
            }
        };
        ws.onmessage = function (m) {
            console.log(m);
            onMessageCB(m);
        };

        return{
            setOnOpenCB: function(cb){
               onOpenCB = cb;
            },
            setOnCloseCB: function(cb){
                onCloseCB = cb;
            },
            setOnMessageCB: function(cb){
                onMessageCB = cb;
            }
        };
    })});

web.xml

<servlet>
    <servlet-name>TimerServlet</servlet-name>
    <servlet-class>TimerWebSocketServlet</servlet-class>
    <load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>TimerServlet</servlet-name>
    <url-pattern>/api/timer/*</url-pattern>
</servlet-mapping>
toddg
источник
Это блестящий пример. Я только изучаю Angular.js, и мне было интересно, есть ли у вас полное приложение с шаблонами и т. Д., Чтобы учиться?
mac,
0

Согласно книге «Discover Meteor», часы / осциллографы Angular аналогичны вычислениям реактивности Meteor ... но Angular доступен только для клиента и дает менее детальный контроль, чем Meteor.

У меня сложилось впечатление, что использование Angular может лучше подходить для добавления реактивности в существующее приложение, тогда как Meteor взлетает, когда вы используете его для всего. Но у меня пока нет реального опыта работы с Angular (хотя я создал несколько небольших приложений Meteor).

еженедельно
источник
0

Итак, Энди Джослин упомянул лучшее решение в моем мнении в своем ответе, третий вариант, который заключается в двунаправленном поддержании состояния через веб-сокеты или любую другую асинхронную библиотеку, с которой вы имеете дело (это будет API сообщений Chrome для расширений Chrome и Приложения, например), и toddg привел пример того, как этого можно достичь. Однако в своем примере он реализует анти-шаблон в AngularJS: служба вызывает контроллер. Вместо этого модель должна быть размещена внутри службы, а затем на нее будет ссылаться контроллер.

Обратные вызовы сокета службы изменят модель службы, и, поскольку на нее ссылается контроллер, он обновит представление. Будьте осторожны, если вы имеете дело с примитивными типами данных или переменными, которые можно переназначить, для этого потребуется наблюдение на контроллере, чтобы это работало.

Bluehallu
источник