81 votes

Angular.js peut-il mettre à jour automatiquement une vue si un modèle persistant (base de données du serveur) est modifié par une application externe ?

Je commence tout juste à me familiariser avec Angular.js, mais j'aimerais créer une application Web comportant une vue qui s'actualise automatiquement en temps réel (sans rafraîchissement) pour l'utilisateur lorsque quelque chose change dans la base de données côté serveur.

Angular peut-il s'en charger (en grande partie) automatiquement pour moi ? Et si oui, quel est le mécanisme de base en jeu ?

Par exemple, configurez-vous Angular pour qu'il interroge régulièrement la base de données afin de détecter les modifications du "modèle" ? Ou utilisez-vous une sorte de mécanisme de type Comet pour notifier au code Angular côté client que le modèle a changé ?

Dans mon application, le problème est que d'autres logiciels (non web) côté serveur mettent parfois à jour la base de données. Mais cette question s'applique également aux applications purement web où vous pouvez avoir plusieurs clients qui modifient la base de données par le biais de clients web Angular, et ils doivent tous être mis à jour lorsque l'un d'entre eux apporte une modification à la base de données (modèle).

97voto

Andy Joslin Points 23231

Vous avez quelques choix...

  1. Vous pourriez effectuer une interrogation toutes les X millisecondes en utilisant $timeout et $http ou si les données que vous utilisez sont reliées à un service REST, vous pouvez utiliser la fonction $resource au lieu de $http .

  2. Vous pourriez créer un service qui utilise une implémentation de Websocket et qui utilise scope.$apply pour gérer les changements qui sont poussés par le socket. Voici un exemple utilisant socket.io, une bibliothèque 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. Vous pouvez aller très loin et créer une implémentation websocket qui synchronise un modèle Angular avec le serveur. Lorsque le client modifie quelque chose, cette modification est automatiquement envoyée au serveur. Ou si le serveur change, il est envoyé au client.
    Voici un exemple de cela dans une ancienne version d'Angular, en utilisant à nouveau socket.io : https://github.com/mhevery/angular-node-socketio

EDIT : Pour le numéro 3, j'ai utilisé Firebase pour le faire.

15voto

toddg Points 261

Voici une implémentation qui utilise jetty au lieu de node. La partie angularjs est basée sur l'application angular-seed. Je ne suis pas sûr que le code angular soit idiomatique... mais j'ai testé que cela fonctionne. HTH -Todd.

TimerWebSocketServlet voir

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>

3voto

Kenneth Lynne Points 3294

Ce que vous cherchez, c'est Firebase et Deployd . Firebase est également livré avec un adaptateur qui rend son utilisation très facile : http://angularfire.com/

0voto

cweekly Points 814

Selon le livre "Discover Meteor", les montres/scopes d'Angular sont similaires aux calculs de Meteor en ce qui concerne la réactivité... mais Angular n'est que client et donne moins de contrôle granulaire que Meteor.

J'ai l'impression que l'utilisation d'Angular serait plus adaptée pour ajouter de la réactivité à une application existante, alors que Meteor s'envole lorsque vous l'utilisez pour l'ensemble de l'application. Mais je n'ai pas encore de réelle expérience avec Angular (bien que j'aie construit quelques petites applications Meteor).

0voto

Hallucynogenyc Points 2585

Andy Joslin a mentionné la meilleure solution à mon avis dans sa réponse, la troisième option, qui consiste à maintenir l'état de manière bidirectionnelle via des websockets ou toute autre bibliothèque asynchrone avec laquelle vous travaillez (il s'agirait de l'API de messages de Chrome pour les extensions et les applications de Chrome par exemple), et Toddg a donné un exemple de la manière dont cela pourrait être réalisé. Cependant, dans son exemple, il met en œuvre un anti-modèle dans AngularJS : le service appelle le contrôleur. Au lieu de cela, le modèle devrait être placé dans le service, puis référencé à partir du contrôleur.

Les callbacks du socket du service modifieront le modèle du service, et comme il est référencé depuis le contrôleur, il mettra à jour la vue. Attention cependant si vous avez affaire à des types de données primitifs ou à des variables qui peuvent être réaffectées, celles-ci devront être surveillées par le contrôleur pour que cela fonctionne.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X