Angularjs and Meteor “Session” reactivity, is ther

2019-04-09 05:21发布

问题:

I'm trying to work with Meteor and Angularjs. I'm using Meteor_angularjs package, which works OK with Collections.

Now I'm trying to use Session and my reactive data store:

TestCtrl = [
    "$scope",
    function($scope){
        $scope.value = Session.get('someValue');
    }
]

This does not work.

QUESTION: Any suggestions on how to tie down Meteor's Session and Angular?

As far as I understand, I can write directive that will be polling Session every so ofter, however I don't think that's a good choice.
Thanks

UPDATE:

I've tried the following:

TestCtrl = [
    "$scope",
    function($scope){
        Meteor.autorun(function(){
            $scope.config = Session.get('testsConfig');
            if (!$scope.$$phase){
                $scope.$digest();
            }
        });
    }
]

and it sort of works, however I get the following error:

Error: INVALID_STATE_ERR: DOM Exception 11
Error: An attempt was made to use an object that is not, or is no longer, usable.
    at derez (http://localhost:3000/test:95:41)
    at derez (http://localhost:3000/test:95:30)
    at derez (http://localhost:3000/test:95:30)
    at derez (http://localhost:3000/test:95:30)
    at derez (http://localhost:3000/test:95:30)
    at derez (http://localhost:3000/test:95:30)
    at derez (http://localhost:3000/test:95:30)
    at derez (http://localhost:3000/test:95:30)
    at derez (http://localhost:3000/test:95:30)
    at derez (http://localhost:3000/test:95:30) angular.js:5526
$get angular.js:5526
$get angular.js:4660
$get.Scope.$digest angular.js:7674
(anonymous function) controllers.js:46
Meteor.autorun.rerun deps-utils.js:78
_.extend.run deps.js:19
Meteor.autorun.rerun deps-utils.js:78
_.extend.flush deps.js:63
_.each._.forEach underscore.js:79
_.extend.flush deps.js:61
_.each._.forEach underscore.js:79
_.extend.flush deps.js:60

UPDATE 2:

I've tried the service like this (might be wrong usage), still nothing. Now it doesn't update at all on Session value's changes.

Meteor.autorun(function(){
    app.factory('ssn', function(){ return{
        get: function(val){
            return Session.get(val);
        }
    }});
});
TestCtrl = [
    "$scope","ssn",
    function($scope, ssn){
        $scope.config = ssn.get('testsConfig');
    }
]

UPDATE 3: Angular has $apply() for

to execute an expression in angular from outside of the angular framework. (For example from browser DOM events, setTimeout, XHR or third party libraries)

At the same time Meteor has Meteor.render() for

Most of the time, though, you won't call these functions directly — you'll just use your favorite templating package, such as Handlebars or Jade. The render and renderList functions are intended for people that are implementing new templating systems.

However, it seems like I just cannot put 2 and 2 together. :(

回答1:

this as an old question with old answers but I see people referring to it so here is the updated answer.

First - there is a new library for angular-meteor that handles those cases for you.

And this library gives you two possible solutions:

  1. If you want to bind a Session variable to a scope variable, use the $meteorSession service. What it does is that every time the scope variable will change, it will change to Session variable (and trigger an autorun if it's placed inside one). and every time the Session variable will change, the scope variable will change as well (and change the view that it's placed upon).

  2. If you are using the Session variable just to get a variable reactive (meaning trigger an autorun), you should use getReactively . this just returns the already existing scope variable but trigger an autorun every time it changes. a good example of this can be found it our tutorial.

    • Note: In anyway, when you use Tracker.autorun inside Angular, you need to connect it to a scope. this can be easily done if you replace Tracker.autorun with the $meteorUtils autorun function


回答2:

Hi here is an option (might not be the best but it works I think)

app.service('Session',function($rootScope){
    var self = this;
    self.objects = {};
    self.get = function(name){
            self.objects[name] = {"value" : Session.get(name)};
            Meteor.autorun(function() {
                    var i = Session.get(name);
                    if(self.objects[name].value != i){
                            if (!$rootScope.$$phase){
                                    $rootScope.$apply(function(){
                                            self.objects[name].value = i;
                                    });
                            }
                    }
            });
            return self.objects[name];
        }
        self.set = function(name,value){
            self.objects[name].value  = value;
            Session.set(name,value);
        }
        return self;
});

Call it in the $scope like this $scope.test = Session.get("test");

In the view as {{test.value}}. Sorry for the late answer .

Happy new year!



回答3:

try

angular.module('yourmod', [])
.controller('TestCtrl', ['$scope', function($scope) {
  var c = Deps.autorun(function (comp) {
     //... put reactive stuf on scope.....
     if(!comp.firstRun) {
       // only do not do aply at first run becaulse then apply is already running.
       $scope.$apply()
     }
  });

  // and to realy make it nice...
  $scope.on('$destroy', function () {c.stop()});
}])