1
votes

Hi I've been trying to create an app using the new angularfire version 0.8, which features an update version of $bind, $bindTo. However im having a little difficulty with it. The bind to method only appears to propagate changes back to firebase on the first update. Subsequent changes to the data on the page do not. Do I need to rebind the object on every update?

I've created a simple app to show the issue. The app has an object created in a factory (Test) which adds an object to the $rootScope. The controller then accesses this, and a view accesses it and updates as required.

Factory (services/test.js)

app.factory('Test',function($firebase, FIREBASE_URL, $rootScope) {
    var URL = FIREBASE_URL + 'test12/';
    var Test = {
        create: function (user,obj) {
            console.log("Creating new test object");
            obj.something = "1234";
            obj.somethingElse = "567";
            obj.$priority="7";
            obj.$save();
            setCurrentTest(user);
        },
        getCurrent: function() {
            return $rootScope.currentTest;
        }
    };

    function setCurrentTest(user) {
        var obj = $firebase(new Firebase(URL)).$asObject();

        obj.$loaded().then(function() {
            if (obj.$priority) {
                obj.$bindTo($rootScope,'currentTest').then(function() {
                    console.log("bound");
                });
            }
            else {
                Test.create(user,obj);
            }
        });
    }

    $rootScope.$on('$firebaseSimpleLogin:login', function(e, user) {
        setCurrentTest(user);
    });

    return Test;
});

Controller (controller/test.js)

app.controller('TestCtrl', function($scope,  Test) {
    $scope.testy = Test.getCurrent();
});

View (test.html)

<div class="t_center">
    <h3>Testing</h3>
        <div>
            <input type="test" name="test1" value="testy.something" ng-model="testy.something"/>
            <input type="test" name="test2" ng-model="testy.somethingElse"/>
        </div>
    <br/>
</div>

Im currently using;

  • angular#1.2.21
  • firebase#1.0.18
  • firebase-simple-login#1.6.2

Any advice greatly appreciated.

Background I don't think my example code highlighted what I was trying to achieve very well so I will provide a little background to what I was trying to do. The object I create here (called "Test" in the example here) is actually basically a users profile. Amongst the usual usery type things (name etc) it also contains some preferences which are used by all of the controllers. Rather than copy that code around I wanted to make a service which obtained the users profile on login and placed it in the $rootScope ready for whatever controller required it. If the service couldn't find the profile in the system then it creates it (with sensible values).

1
Are you using Angular 1.2.18+? firebase.com/docs/web/bindings/angular/… - bobjones
Alas I am (I was hoping for something that simple :)). I've edited the post to include the versions im running. - Steven Franklin
It's extremely hard to understand the use case here. Why is a new $firebase object bound each time login state changes or any time $priority is set to null? Why isn't the old object unbound? Why not just continue binding to the same object? Can you simplify this to the smallest example that still reproduces the error? There seem to be a lot of unnecessary moving parts. - Kato
Firstly thank you for coming back to me on this - pretty new to angular and to firebase. Ah, I maybe should have explained the use case a little better, my use of $rootScope rather than $scope was kind of deliberate. Though im happy to be shown the error of my ways. I'll add a little background to the question to see if you can see whats driving my madness :) - Steven Franklin

1 Answers

3
votes

Since this seems like a gross misappropriation of $rootScope, it seemed simpler to fix the issue than to understand what is wrong with your example. Here's a working example with a service and $bindTo.

var app = angular.module("sampleApp", ["firebase"]);

app.constant('FIREBASE_URL', 'https://kato-so25069621.firebaseio-demo.com/');

app.factory('Test',function($firebase, FIREBASE_URL) {
    return function(path) {
        var URL = FIREBASE_URL + path;
        var obj = $firebase(new Firebase(URL)).$asObject();
        obj.$loaded(function() {
            console.log('loaded', obj);
            if( obj.$value === null ) { // if object has not been initialized
                angular.extend(obj, {
                    something: "1234", 
                    somethingElse: "567",
                    $priority: 7
                });
                obj.$save();
            }
        });
        return obj;
    }
});

app.controller('TestCtrl', function($scope,  Test) {
    Test('test12/').$bindTo($scope, 'testy');
});

Note these important principles:

  • the service is no longer bound to $rootScope
  • we use $bindTo with the current $scope, so when it is destroyed it unbinds automagically
  • we do not worry about authentication inside our service but assume user is already authenticated, see more below

The only component missing here is authentication, which was purposefully left out. This should not be checked in every service and controller (instead, check out Using Simple Login with Routers under Authentication in the guide.