Creating and adding to arrays in angularFire / Firebase - arrays

I am trying to build an app with angularjs and Firebase similar to a forum for helping my classmates with problems. I also want people to be able to 'reply' to the specific problems the classmates are having, so I create an object with many values in the angularjs factory, like this:
factory.addError = function() {
factory.errors.$add({
...
replies: []
});
};
The problem with this is that Firebase doesn't save parameters with empty values for placeholders, such as the parameter 'replies' above. I have tried to hard code a placeholder value into the array, but that seems like a very patchy solution, and that comes with it's own set of problems for me having to delete out the data in Firebase. For reference, here is the code in the linked controller:
$scope.error.replies.$push({
name: $scope.replyName,
message: $scope.replyMessage,
time: (new Date()).toString(),
upvote: 0
});
How do you initialize an empty array into the object? And will $push properly use Firebase's commands to save it to it's own set of data?

First, here are some relevant resources and suggestions:
Resources
Check out Firebase's blog post, Best Practices: Arrays in Firebase - "Arrays are evil".
Also, the AngularFire Development Guide.
And the documentation for AngularJS providers.
Suggestions
As the AngularFire API Documentation says:
"There are several powerful techniques for transforming the data downloaded and saved by $firebaseArray and $firebaseObject. These techniques should only be attempted by advanced Angular users who know their way around the code."
Putting all that together, you accomplish what you want to do by:
Extending AngularFire services, $firebaseArray and $firebaseObject.
Following the documentation for extending services.
Example
Extended Error $firebaseObject
.factory('Error', function(fbUrl, ErrorFactory) {
return function(errorKey){
var errorRef;
if(errorKey){
// Get/set Error by key
errorRef = new Firebase(fbUrl + '/errors/'+errorKey);
} else {
// Create a new Error
var errorsListRef = new Firebase(fbUrl + '/errors');
errorRef = errorsListRef.push();
}
return new ErrorFactory(errorRef);
}
})
.factory('ErrorFactory', function($firebaseObject){
return $firebaseObject.$extend({
sendReply: function(replyObject) {
if(replyObject.message.isNotEmpty()) {
this.$ref().child('replies').push(replyObject);
} else {
alert("You need to enter a message.");
}
}
});
})
Error Controller
.controller('ErrorController',function($scope, Error) {
// Set empty reply message
$scope.replyMessage = '';
// Create a new Error $firebaseObject
var error = new Error();
$scope.error = error;
// Send reply to error
$scope.reply = function(){
error.sendReply({message:$scope.replyMessage});
}
})
And String.prototype.isNotEmpty()
String.prototype.isNotEmpty = function() {
return (this.length !== 0 && this.trim());
};
(adapted from this answer)
Hope that helps!

Related

Update FireStore Document on Read

I am using React and Firestore to make a Blog like site. Each Post is Stored as a separate document in Post collection.
The Document structure looks like :
--Posts
--Post1
--title
--body
--views
--likes
--Post2
--title
--body
--views
--likes
I want to update the views whenever someone Views a post. What is the best way to Achieve this in Firestore.
For many cases you would use update directly. However since you're incrementing a counter you should also use a transaction to prevent race conditions when multiple users are trying to increment it around the same time:
// Create a reference to the post.
const postRef = db.collection('Posts').doc('<postId>');
return db.runTransaction(function(transaction) {
// This code may get re-run multiple times if there are conflicts.
return transaction.get(postRef).then(function(post) {
if (!post.exists) {
throw new Error('Post does not exist!');
}
const newViews = post.data().views + 1;
transaction.update(postRef, { views: newViews });
});
}).then(function() {
console.log('Transaction successfully committed!');
}).catch(function(error) {
console.log('Transaction failed: ', error);
});

kinvey fetching and remove not working (AngularJS)

I have this problem with kinvey backend,
I'm trying to fetch data from my collection but it doesn't work for me. here is my code :
var query = new $kinvey.Query();
query.equalTo('_id', '5909e8084c68b1ef74fa4efc');
var dataStore = $kinvey.DataStore.collection('User1Bases', $kinvey.DataStoreType.Network);
var stream = dataStore.find(query);
stream.subscribe(function onNext(entity) {
// ...
}, function onError(error) {
// ...
}, function onComplete() {
//...
});
Can you help me please
If you let run the code you have posted then consider four things:
Make sure you have Kinvey implemented:
<script src="https://da189i1jfloii.cloudfront.net/js/kinvey-html5-sdk-3.10.2.min.js"></script>
Make sure you have initialized the Kinvey service before:
// Values shown in your Kinvey console
Kinvey.init({
appKey: '<your_appKey>',
appSecret: 'your_appSecret'
});
Make sure you are logged in with a user that has the rights to read your collection (should be fine using the All Users role (default)):
var promise = Kinvey.User.login('<username>', '<password>')
.then(function() {
console.log ("You are logged in");
})
.catch(function(error) {
console.log (error);
});
Output the return result to see whats coming back. To make sure you do the query AFTER successful login, paste you query inside the .then function of login.
I'm not sure if your query is valid unter 3.x since a lot has changed and I'm not working with older Kinvey versions.
So that all together would look like this:
// Initialize Kinvey
Kinvey.init({
appKey: '<your_appKey>',
appSecret: 'your_appSecret'
});
// Login with already registered user
var promise = Kinvey.User.login('<username>', '<password>')
.then(function() {
console.log ("You are logged in");
// Your query
var query = new $kinvey.Query();
query.equalTo('_id', '5909e8084c68b1ef74fa4efc');
var dataStore = $kinvey.DataStore.collection('User1Bases', $kinvey.DataStoreType.Network);
var stream = dataStore.find(query);
stream.subscribe(function onNext(entity) {
// Output of returning result
console.log (entity);
// ...
}, function onError(error) {
// ...
}, function onComplete() {
//...
});
})
.catch(function(error) {
console.log (error);
});
There are now three return sets possible:
Nothing (as you say) -> Something missing/wrong in the code (compare yours with mine)
Empty array: Your query didn't find anything, adapt the search value(s)
One or more entries in the array -> All fine, what you were looking for!
Hope that helps!
When querying by _id there is a built in method: http://devcenter.kinvey.com/angular/guides/datastore#FetchingbyId
Try switching to var stream = dataStore.findById('entity-id');
Also check to make sure you don't have any preFetch or postFetch BL that is interfering with the query.

Saving and Getting Data / Rows to and from PouchDB

i am very new to pouchdb, meaning i have not yet been successfully able to implement an app that uses it.
This is my issue now, in my controller i have two functions:
var init = function() {
vm.getInvoicesRemote(); // Get Data from server and update pouchDB
vm.getInvoicesLocal(); // Get Data from pouchDB and load in view
}
init();
Basically in my app i have a view that shows customer invoices, now i want customers to be able to still see those invoices when they're offline. I have seen several examples of pouchdb and couchdb but all use the "todo" example which does not really give much information.
Now i'm just confused about what the point was in me spending hours understanding couchdb and installing it if in the end i'm just going to be retrieving the data from my server using my API.
Also when the data is returned how does pouchdb identify which records are new and which records are old when appending.
well, i m working on same kind..!this is how i m making it work..!
$scope.Lists = function () {
if(!$rootScope.connectionFlag){
OfflineService.getLocalOrdersList(function (localList) {
if(localList.length > 0) {
$scope.List = localList;
}
});
}else{
if(!$scope.user){
}else {
Common.callAPI("post", '***/*************', $scope.listParams, function (data) {
if (data !== null) {
$scope.List = data.result;
OfflineService.bulkOrdersAdd_updateLocalDB($scope.List);
}
});
}
}
};
so,$scope.List will be filled if online as well as offline based on connectionFlag
note : OfflineService and Common are services.
call method:
$ionicPlatform.ready(function () {
OfflineService.configDbsCallback(function(res) {
if(res) {
$scope.Lists();
}
});
});
u can try calling $scope.Lists(); directly..!
hope this helps u..!

Why won't this code work to create a Parse object in an Ionic app?

I'm trying to create a Parse object in an app using the Ionic Framework, and I can't get it to work. I'm fairly new to programming, but I've been able to create Parse users, just not objects. Can anyone help me find a solution? Please see the code below for my controller in question. Thanks!
.controller('AddProspectsController', function($scope, $state, $rootScope) {
if (!$rootScope.isLoggedIn) {
$state.go('welcome');
}
$scope.prospect = {};
$scope.error = {};
// Syntax to create a new subclass of Parse.Object.
//var Prospects = Parse.Object.extend("Prospects");
$scope.addProspect = function() {
// Create a new instance of that class.
var Prospects = Parse.Objext.extend("Prospects");
var prospects = new Prospects();
prospect.set("name", $scope.prospect.name);
prospect.set("phone", $scope.prospect.phone);
prospect.set("email", $scope.prospect.email);
prospect.set("interest", $scope.prospet.interest);
prospect.save(null, {
success: function(prospect) {
// Execute any logic that should take place after the object is saved.
$state.go('app.prospects', {clear: true});
alert('New object created with objectId: ' + prospect.id);
},
error: function(prospect, error) {
// Execute any logic that should take place if the save fails.
// error is a Parse.Error with an error code and message.
alert('Failed to create new object, with error code: ' + error.prospect);
}
});
}
})
You have another spelling error on this line:
var Prospects = Parse.Objext.extend("Prospects");
This is not Objext, but Object.​​​​​​
I hope this will help.
There is a spelling error... you have the variable named prospects with an "s" and when you are creating the object, you are using a variable named prospect

Connection state with doowb/angular-pusher

I am trying to build an Angular project with Pusher using the angular-pusher wrapper. It's working well but I need to detect when the user loses internet briefly so that they can retrieve missed changes to data from my server.
It looks like the way to handle this is to reload the data on Pusher.connection.state('connected'...) but this does not seem to work with angular-pusher - I am receiving "Pusher.connection" is undefined.
Here is my code:
angular.module('respondersapp', ['doowb.angular-pusher']).
config(['PusherServiceProvider',
function(PusherServiceProvider) {
PusherServiceProvider
.setToken('Foooooooo')
.setOptions({});
}
]);
var ResponderController = function($scope, $http, Pusher) {
$scope.responders = [];
Pusher.subscribe('responders', 'status', function (item) {
// an item was updated. find it in our list and update it.
var found = false;
for (var i = 0; i < $scope.responders.length; i++) {
if ($scope.responders[i].id === item.id) {
found = true;
$scope.responders[i] = item;
break;
}
}
if (!found) {
$scope.responders.push(item);
}
});
Pusher.subscribe('responders', 'unavail', function(item) {
$scope.responders.splice($scope.responders.indexOf(item), 1);
});
var retrieveResponders = function () {
// get a list of responders from the api located at '/api/responders'
console.log('getting responders');
$http.get('/app/dashboard/avail-responders')
.success(function (responders) {
$scope.responders = responders;
});
};
$scope.updateItem = function (item) {
console.log('updating item');
$http.post('/api/responders', item);
};
// load the responders
retrieveResponders();
};
Under this setup how would I go about monitoring connection state? I'm basically trying to replicate the Firebase "catch up" functionality for spotty connections, Firebase was not working overall for me, too confusing trying to manage multiple data sets (not looking to replace back-end at all).
Thanks!
It looks like the Pusher dependency only exposes subscribe and unsubscribe. See:
https://github.com/doowb/angular-pusher/blob/gh-pages/angular-pusher.js#L86
However, if you access the PusherService you get access to the Pusher instance (the one provided by the Pusher JS library) using PusherService.then. See:
https://github.com/doowb/angular-pusher/blob/gh-pages/angular-pusher.js#L91
I'm not sure why the PusherService provides a level of abstraction and why it doesn't just return the pusher instance. It's probably so that it can add some of the Angular specific functionality ($rootScope.$broadcast and $rootScope.$digest).
Maybe you can set the PusherService as a dependency and access the pusher instance using the following?
PusherService.then(function (pusher) {
var state = pusher.connection.state;
});
To clarify #leggetters answer, you might do something like:
app.controller("MyController", function(PusherService) {
PusherService.then(function(pusher) {
pusher.connection.bind("state_change", function(states) {
console.log("Pusher's state changed from %o to %o", states.previous, states.current);
});
});
});
Also note that pusher-js (which angular-pusher uses) has activityTimeout and pongTimeout configuration to tweak the connection state detection.
From my limited experiments, connection states can't be relied on. With the default values, you can go offline for many seconds and then back online without them being any the wiser.
Even if you lower the configuration values, someone could probably drop offline for just a millisecond and miss a message if they're unlucky.

Resources