angularfire binding to primitive - angularjs

I'm trying to bind to a primitive with angularfire. Here's how I"m doing it:
$firebase(fb.child('counts/node')).$on('value', function (obj) {
$scope.nodeCount = obj.snapshot.value
})
Is this correct? This API seems very different from the rest of firebase. I expected to get an ss as callback and do ss.val() but that doesn't seem to be the case. Can someone confirm if this is how it's supposed to be or if I'm doing it wrong. Thanks.

Generally, as outlined in the getting started guide and API, you should simply be accessing the data directly in the view:
// javascript
$scope.messages = $firebase(new Firebase(URL));
<!-- html -->
<li ng-repeat="message in messages">{{message}}</li>
If you want to iterate the data in a controller (bad) or service (better), you can read the keys in the order as the database by using $getIndex().
// javascript
var ref = $firebase(new Firebase(URL));
ref.$on('loaded', function() {
angular.forEach(ref.$getIndex(), function(key) {
console.log('the next message is', key, ref[key]);
});
});
If you are, in fact, trying to synchronize a single primitive value, angularFire is hardly necessary:
$scope.primitive = null;
var ref = new Firebase(URL);
ref.on('value', function(snap) { $scope.primitive = snap.val(); });
$scope.saveValue = function(newValue) {
ref.set(newValue);
};
But certainly possible:
// javascript
$scope.primitive = $firebase(new Firebase(URL));
<!-- html -->
<input ng-model="primitive.$value" />
All of this is covered in the above links, which should be treated as required reading before getting started with Angular + Firebase.
changes in 0.8
angularFire 0.8 will be out soon. It will change this structure a little bit, utilizing a $asArray(), $asObject(), and also providing a .then() method, so a bit more like this:
// javascript
var ref = $firebase(new Firebase(URL));
$scope.messages = ref.$asArray();
$scope.ref.then(function() {
angular.forEach($scope.messages, function(message) {
console.log('the next message is', message.$id);
});
});
<!-- html -->
<li ng-repeat="message in messages">{{message}}</li>

Related

Angularjs scope data inside the function

I am trying to display the data to my view but $scope.plan outputs {}. I am thinking that it would output the fetched data from the initGetEdit function, console.log() inside the $http.post outputs expected data.
controller.js
var id = $stateParams.id;
$scope.plan = {}
$scope.initGetEdit = function(){
var data = { id : id }
$http.post("someUrl", data).then(function(res){
$scope.plan = res.data;
console.log($scope.plan); //----> logs expected data
})
}
$scope.initGetEdit();
console.log($scope.plan); //----> logs {}
In my view I have something like this.
view
<input ng-model="plan.something" type="text" />
UPDATE
First thank you for those answers provided and the comments, appreciated it. It gives me an insight. I solved my issue by removing the initGetEdit function and staying with just the http.post.
Try keeping the second console in watch.
$scope.$watch('plan',function(){
console.log($scope.plan);
});
At first, you declare a variable $scope.plan = {} after that in http call of your $scope.initGetEdit function its empty object after the function http is an async call your object may be filled based on the response. until that it will be an empty object.
#Ujjwala Bollam mention in answer to print it in the console.
var app = angular.module('testApp',[]);
app.controller('testCtrl',function($scope,$http){
//var id = $stateParams.id;
var id=1;
$scope.plan = {}
$scope.initGetEdit = function(){
var data = { id : id }
//$http.post("http://someurl", data).then(function(res){
$scope.plan ={id:1,something:"hai this is response data"};
console.log($scope.plan); //----> logs expected data
//})
}
$scope.initGetEdit();
console.log($scope.plan); //----> logs {}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div ng-app="testApp" ng-controller="testCtrl">
<input ng-model="plan.something" type="text" />
</div>

Persistence storage in ForerunnerDB not working properly

I am using ForerunnerDB - a NoSQL JSON Document DB for creating a data store on the client (web). This particular library offers a persistence storage option. However, there seems to be something wrong with it. I have included my code below:
App:
(function(){
angular.module("TestApp", ['ui.router', 'LocalStorageModule', 'forerunnerdb']);
})();
Controller:
(function(){
angular.module("TestApp")
.controller("FetchGroupsController", function(clientStore, $scope, $http){
clientStore.getTable("groups").load(function (err, tableStats, metaStats) {
if (err) {
// Load operation was unsuccessful
console.error("error in pulling collection " + name);
console.error(err)
}
else{
//there is persisted data corresponding to the requested table
if(tableStats.foundData && tableStats.rowCount > 0){
controller.groups = clientStore.fetchRecords("groups"); //returns an array of objects
console.log("User has " + tableStats.rowCount + " groups");
console.log(controller.groups);
}
else{//no table for group data persisted */
$http({ method: "POST", url: "api/groups/index"})
.success(function(data, status){
//TODO: handle the activation code
if(status == 200){
delete data["debug"]; //deleting an unnecessary object from response data
clientStore.addList("groups", data);
controller.groups = clientStore.fetchRecords("groups");
console.log(controller.groups);
clientStore.getTable("groups").save();
}
else if(status == 403){ //forbidden
controller.messages = data;
}
else if(status == 401){ //error
controller.errors = data;
}
})
;
}
}
});
});
})();
Service:
angular.module("TestApp")
.factory('clientStore', function($fdb, $http, localStorageService){
var clientDB = null;
var factory = {};
clientDB = $fdb.db("testDB");
factory.getDB = function(){
return clientDB;
};
factory.createTable = function(name, pk){
if(pk != false){
return clientDB.collection(name, {primaryKey : pk});
}
return clientDB.collection(name);
};
factory.resetTable = function(name){
clientDB.collection(name)._data = [];
clientDB.collection(name).save();
};
factory.getTable = function(name){
return clientDB.collection(name);
};
factory.add = function(name, record){ //insert a single object
clientDB.collection(name).insert(record/*, function(result){
console.warn(result);
}*/);
};
factory.addList = function(name, records){ //insert a list of objects
for (record in records){
clientDB.collection(name).insert(records[record]);
}
};
factory.fetchRecords = function(name){
return clientDB.collection(name)._data;
};
return factory;
});
View:
<div ng-repeat="group in fetchGrpsCtrl.groups" class="row">
<div class="col-md-12">
<div class="groups" id="grp-#{{group.id}}" ng-click="fetchGrpsCtrl.setGroup(group)">
<div class="details">
<h5> #{{group.title}}</h5>
</div>
</div>
</div>
</div>
The problem is that the variable controller.group is null in the view, but in the controller, I am getting the expected value when I log it (line 15) out to the console. I thought maybe it was a problem of scope and that the changes made to the variable inside the callback were not being picked up in the view. But that is the not the case because I commented out the line
clientStore.getTable("groups").save();
and ran it again and the view was updated perfectly as expected. I cannot figure out why the save() function is erasing the controller.groups variable in the view but is logged out perfectly in the controller.
You are using ForerunnerDB incorrectly. It includes an AngularJS plugin that makes using it with AngularJS very easy, but instead you've written a wrapper of your own that hooks onto the _data property of a collection (something that you shouldn't do because that property is managed internally by ForerunnerDB and can be destroyed and re-created meaning you will have an incorrect reference to an object that might no longer be used by a collection).
Instead you should use ForerunnerDB in AngularJS as described in the documentation: https://github.com/Irrelon/ForerunnerDB#angularjs-and-ionic-support
ForerunnerDB includes a helper method called "ng()" that allows you to correctly link data from a collection to your view's scope.
Also, when using third party javascript libraries, properties with an underscore are generally considered "private" and should not be accessed directly. You should use an accessor method (such as .find() in ForerunnerDB's case) to access data instead. Usually a property that starts with an underscore is a good indication that it is private (not all libraries and programmers follow this convention but many do).

How can I save data in forEach loop?

I create a forEach loop. I can access data from Firebase with this loop and I can change variable. But I can not save these changes on Firebase. How can I save these changes? Here's my code:
var posts = $firebaseArray(ref);
posts.$loaded().then(function(item){
item.forEach(function(childSnapshot){
var num = childSnapshot.point-1;
childSnapshot.lastPoint = num;
});
});
You're using the AngularFire framework, which builds UI bindings on top of Firebase's regular JavaScript SDK. You should only be using it for things that you're binding to the Angular UI elements. For everything else, you're likely better off using Firebase's regular JavaScript SDK.
If I understand your requirement correctly, you're trying to loop over all child nodes in a database location once and modify a property. If so:
ref.once('value', function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var child = childSnapshot.val();
childSnapshot.ref().update({ lastPoint: child.point - 1 });
});
});
The relevant sections of the Firebase documentation are on reading data once and updating data.
Since AngularFire is built on top of Firebase's JavaScript SDK, they work perfectly together. So if elsewhere you bind the posts to the scope ($scope.posts = $firebaseArray(ref)), they will be updated automatically when you update the last point with the above snippet.
You can create a service that contains a getter and a setter. It would look something like this;
angular.module('app').factory("DataHandler",
function() {
var data;
return {
get: function() {
return data;
},
set: function(something) {
data = something;
}
}
}
);
Then in your code you would call:
var posts = $firebaseArray(ref);
posts.$loaded().then(function(item){
item.forEach(function(childSnapshot){
var num = childSnapshot.point-1;
childSnapshot.lastPoint = num;
DataHandler.set(childSnapshot);
});
});
Then wherever/whenever you need to get that data just call:
Datahandler.get();

Pass static information from html to AngularJS application

I would like to pass some static configuration data from my server (.NET, PHP) to my Angular application. I don't want to call a web service for this.
In this question a javascript block is generated, but I don't want this.
How do I pass a value from main html to partials?
What's the best way to do this?
I was thinking of using the ng-init directive for this:
<div data-ng-app="MyApp" data-ng-init="foo='bar'">
Or is there a better way?
What I would recommend doing is using constants in angular. This is an example of one that I have used in a project (the #Url.Content part is c#, but I think you will get the idea).
<script>
angular.module('App.ConfigurationSettings', [])
.constant('ApiBaseUrl','#Url.Content("~/api/")')
.constant('WebBaseUrl','#Url.Content("~")');
</script>
and then when we actually use those constants in our service it looks like this:
var app = angular.module('App.BrandService', ['App.ConfigurationSettings']);
app.factory("BrandService", function ($http, $q, ApiBaseUrl) {
return {
getBrand: function (brandId) {
var deferred = $q.defer();
var url = ApiBaseUrl + 'brands/' + brandId + '.json';
return HttpGet($http, url, deferred);
},
getBrands: function () {
var deferred = $q.defer();
var url = ApiBaseUrl + 'brands.json';
return HttpGet($http, url, deferred);
}
};
});
Usually static information is configurable and related to some service. If so, I would create a provider (which is just a specialized service) and configure it in your config function.
Here is the Angular documentation on Providers
Create a Provider
myApp.provider('tooltip', function () {
var version;
var author;
this.setVersion= function(value) {
version = value;
};
this.setAuthor = function(value) {
author = value;
};
this.$get = function (/* injectibles go here */) {
return {
version: version,
author: author,
etc...
};
};
});
Configure the Provider
When you inject your provider in your config function, make sure that you append 'Provider':
myApp.config(function(tooltipProvider) {
tooltipProvider.setVersion('1.0');
tooltipProvider.setAuthor('John Smith');
// more configuration of static data
});
Using the Provider
Inject the provider where you need it, and make use of your static data. Here, we are binding the static data to scope so that we can display it in the view.
// JS
app.controller('ctrl', function($scope, tooltip) {
$scope.version = tooltip.version;
$scope.author = tooltip.author;
});
// HTML
<div ng-controller='ctrl'>
Tooltip Plugin: <br />
Version: {{ version }} <br />
Author: {{ author }} <br />
</div>

backbone.js: trouble persisting simple Model to localStorage

I'm getting started with backbone, I used this localStorage adapter.
Here's my test code:
cartStatus = Backbone.Model.extend({
localStorage: new Store("cartStatus"),
currentClientId: ""
});
var myStatus = new cartStatus;
$(function () {
myStatus.fetch();
alert("loaded" + myStatus.get("currentClientId"));
myStatus.set({ "currentClientId": "abc" });
myStatus.save();
});
If I load the page multiple times it says loaded: undefined every time.
however, after my second load I would expect loaded: abc every time.
when I inspect my localstorage after 2 loads I see this:
cartStatus-d2a7b64d-2f15-a741-9a8c-e254b4a13682 {"0":{"currentClientId":"abc","id":"dd5e0e47-9356-ea30-2de3-75a041848b88"},"currentClientId":"abc","id":"d2a7b64d-2f15-a741-9a8c-e254b4a13682"}
cartStatus dd5e0e47-9356-ea30-2de3-75a041848b88,d2a7b64d-2f15-a741-9a8c-e254b4a13682
cartStatus-dd5e0e47-9356-ea30-2de3-75a041848b88 {"currentClientId":"abc","id":"dd5e0e47-9356-ea30-2de3-75a041848b88"}
Does anyone know what's going wrong?
Edit
I've created a jsfiddle demonstrating this (run it twice) http://jsfiddle.net/Myster/fE9eQ/3/
#tkone, you are suggesting the correct answer I think. The fetch is async, so unless you use jquery deferreds or do the model set/save in the success callback, then this will be the behavior.
cartStatus = Backbone.Model.extend({
localStorage: new Store("cartStatus"),
currentClientId: ""
});
var myStatus = new cartStatus();
$(function () {
debugger;
myStatus.fetch({
success: function(x) {
document.write('myStatus.fetch - success !<br />');
myStatus.set("currentClientId", "abc" );
myStatus.save();
}
});
});

Resources