Reputation: 2884
I'm tring to get 3-way data binding with firebase and angularfire. You can see what I've got in Plunker: http://plnkr.co/edit/RGA4jZK3Y6n4RkPCHK37
app.js:
angular.module('ideaBattle', ["firebase"]);
services:
angular
.module('ideaBattle')
.constant('FBURL', 'https://ideabattle.firebaseio.com/')
.service('Ref', ['FBURL', Firebase])
.factory('dataBank', function(Ref, $firebase) {
return $firebase(Ref).$asArray();
});
controller:
angular
.module('ideaBattle')
.controller('ideaListCtrl', displayIdeas);
displayIdeas.$inject = ['dataBank'];
function displayIdeas(dataBank){
var vm = this;
vm.ideas = dataBank;
vm.upVote = function(idea){
vm.ideas[idea.id].votes++;
};
}
HTML:
<div ng-controller="ideaListCtrl as vm">
<div ng-repeat="idea in vm.ideas | orderBy: '-votes'">
<div>
<h2>{{idea.name}}</h2>
<p>{{idea.desc|limitTo: 190}}</p>
<span class="btn" ng-click="vm.upVote(idea)">Vote! <span class="badge"> {{idea.votes}}</span></span>
</div>
</div>
</div>
Plunker version: http://plnkr.co/edit/RGA4jZK3Y6n4RkPCHK37
What it does, it gets the data from firebase and displays it correctly, but when I push the button to call upVote function it only updates locally. I know why it only works locally, but I don't know how to make it also update in firebase.
I've tried with $bindTo, but from what I understand it requires $scope to work, and I'm trying to use "Controller as vm" pattern without injecting $scope.
Can anybody tell me how to bite that?
Upvotes: 5
Views: 2024
Reputation: 389
Adding a few clarifications comments to the response above using ES6/JS2015 systax as an example.
export class SomeController {
constructor($firebaseObject, $scope) {
'ngInject';
//using the firebase SDK 3.0
let obj = $firebaseObject(firebase.database().ref().child('someKey'));
// To make the data available in the DOM, assign it to
// 'this.data' accessible from DOM as $ctrl.data
this.data = obj;
// For three-way data bindings, you will still need to inject '$scope'
// but you can alias your controller on $scope
obj.$bindTo($scope, '$ctrl.data');
// Why does this work?
// This works because angular 1x puts controllerAs
// on top of $scope. So '$scope.$ctrl.data' is the same as 'this.data'.
// Note: $ctrl is the default controllerAs syntax if not specified,
// just change $ctrl to your defined controllerAs ailias if
// specified.
}
}
Upvotes: 1
Reputation: 1721
John Papa talks about one of the purposes of using the var vm = this;
syntax instead of $scope
in every controller is to make the use of $scope
a conscious choice. In this case we need to include $scope.
I took David East's plunkr in his answer and fiddled with it a bit. It isn't perfect because it depends on the controllerAs value being 'vm'.
http://plnkr.co/edit/vLLaa7QJvfryYRD7cZvO?p=preview
.controller('MainCtrl', function(Todos, $scope) { /* Add $scope */
var vm = this;
vm.todos = Todos.all();
vm.lonelyTodo = Todos.get('-JeNOtYPv7AZmVAoZ1bu');
vm.lonelyTodo.$bindTo($scope, 'vm.lonelyTodo'); /* Add three way binding */
});
Upvotes: 5
Reputation: 32604
bindTo
method requires $scope
.You can use AngularFire with ControllerAs syntax, but you can't use it with ControllerAs with $bindTo
.
$bindTo
has a hard dependency on $scope
and it will break without it.
If you want an example of using AngularFire with ControllerAs syntax, check out this Plunker demo.
angular.module('app', ['firebase'])
// constant for the Firebase we're using
.constant('FBURL', 'https://<your-firebase>.firebaseio.com/todos')
// return the Firebase ref as a service
.service('Ref', ['FBURL', Firebase])
// return the Todos from Firebase by returning the
// array from the factory
.factory('Todos', function(Ref, $firebase) {
return $firebase(Ref).$asArray();
})
// inject the Todos and assign them to "this"
// for the ControllerAs syntax
.controller('MainCtrl', function(Todos) {
this.todos = Todos;
});
Upvotes: 10