I have used to get current address using google api and now i want implement callback function in this function using angular 4 how can implement it?
let currgeocoder = new google.maps.Geocoder();
currgeocoder.geocode({
'location': location
}, function(results:any, status:any) {
if (status == google.maps.GeocoderStatus.OK) {
let place = results[0];
//this.showresult(place.formatted_address);
} else {
alert('Geocode was not successful for the following reason: ' + status);
}
});
this.myGroup.setValue({
searchControl: 'global'
});
you can create oberservable and push new values on it ,
let subject = new Subject();
let ovservable = subject.asObservable()
subject.next("b");
ovservable.subscribe((value) => {
console.log("Subscription got", value); // Subscription wont get
// anything at this point
});
so create observable , expose it and when you receive data from call make use of .next() method that will do
in your code
let subject = new Subject();
let ovservable = subject.asObservable();
let currgeocoder = new google.maps.Geocoder();
currgeocoder.geocode({
'location': location
}, function(results:any, status:any) {
if (status == google.maps.GeocoderStatus.OK) {
let place = results[0];
subject.next(place);
//this.showresult(place.formatted_address);
} else {
alert('Geocode was not successful for the following reason: ' + status);
}
});
this.myGroup.setValue({
searchControl: 'global'
});
ovservable.subscribe((value) => {
console.log("Subscription got", value); // Subscription wont get
// anything at this point
});
I think I am getting my keys, arrays, values and IDs mixed up here but can't seem to figure it out.
I want a way to get the current user in a ProfileCtrl controller. This is my current implementation using promises, $waitForAuth and once. But I am not sure if implementing currently.
var user = "";
var key = "";
var uids = Users.allUIDs();
console.log(uids);
Auth.$waitForAuth().then(function () {
var uid = Auth.$getAuth().uid;
console.log(uid);
for (var i = 0; i < uids.length; i++) {
console.log(uids[i].value().toString());
if (uids[i].value() == uid) {
var userKeyRef = new Firebase(firebaseUrl + uids + uids[i]);
userKeyRef.once('value').then(function(snapshot) {
key = snapshot.val();
}).then(function(){
user = new Firebase(firebaseUrl + users).child(key).val();
});
console.log(user);
console.log('User exists')
break;
}
}
$scope.user =user;
}).catch(function (error) {
console.log(error);
})
I do a check of the uids in an array, and if they match the authenticated user, I get the key from within the uids array and use that key to find the user object in the users array. Here is my database:
{
"uids" : {
"7d34fb85-813c-4586-857e-f062aed67f32" : {
"-KDQDk5vwJXmFngwI7iQ" : {
"registered" : true
}
}
},
"users" : {
"-KDQDk5vwJXmFngwI7iQ" : {
"email" : "random#gmail.com",
"firstname" : "Random",
"lastname" : "Person",
"uid" : "7d34fb85-813c-4586-857e-f062aed67f32"
}
}
}
For a clearer example, when I console.log the uids as it is returned from my service, it looks like:
Which means the uids are coming through?
Here is my code to get the uids:
app.factory('Users', ['$firebaseArray','$firebaseObject', 'Auth', function ($firebaseArray, $firebaseObject, Auth) {
var ref = new Firebase("https://urlformyapp.firebaseio.com");
var users = $firebaseArray(ref.child('users'));
var uids = $firebaseArray(ref.child('uids'));
return {
all: function () {
return users;
},
allUIDs: function () {
return uids;
},
get: function (id) {
// Simple index lookup
return users[id];
}
}
}])
Could someone tell me what is going wrong? Why does uids[i].value.toString() not print anything? Is there anything wrong with my code logic given the structure of my DB?
I am writing an Angular/Firebase application where users who visit a waiting room page are assigned a group and once that group has n users a new group is formed. Using transactions seems like the write path, but am stuck.
In the example below I have a Config service that returns an $firebaseObject
This object contains the group size or playerLimit.
angular.module('floodStudyApp')
.controller('WaitingroomCtrl', function ( $scope, $routeParams, Ref, $location, Config) {
Config.getConfig($routeParams.floodstudy).$loaded(function (config) {
$scope.floodstudyConfig = config;
var NUM_PLAYERS = config.playerLimit;
Ref.child('floodStudy/'+ config.name+ '/group' + $scope.floodstudyConfig.groups + '/players').transaction(function(playerList) {
if (playerList === null) {
playerList = {};
}
if(playerList.hasOwnProperty($routeParams.player)){
console.log("you already are here dude!");
return;
}
if(Object.keys(playerList).length % NUM_PLAYERS === 0) {
$scope.floodstudyConfig.groups++;
$scope.floodstudyConfig.$save();
}
playerList[$routeParams.player] = {
name: $routeParams.player,
startTime: Firebase.ServerValue.TIMESTAMP,
playerIndex: Object.keys(playerList).length+1
};
return playerList;
//}
}, function(error, committed, snapshot){
if(!error, committed){
$scope.$apply(function () {
$location.path('floodstudy/' + $routeParams.floodstudy+ '/group' + $scope.floodstudyConfig.groups + '/' + $routeParams.player);
});
}
});//end transaction
});// end get config
});
Assuming a surge of users, I need each group to have exactly n users. The code above handles a trickle of users, but not a surge. When hammered upon the groups contain 2-6 users each. Any suggestions on how to accomplish this would be greatly appreciated.
Here is a sample output after a surge: https://gist.github.com/shawnzam/041f4e26bc98a3f89a7b
Rather than attempting to do this with arrays, given all the reasons sequential, numeric ids fall over in distributed data, I'd instead recommend that you use a counter, simplify, and have great justice from every Zig.
Suggested data structure:
/rooms/$roomid/counter
/members/$counter_value/$memberid
Function to update the counter:
angular.factory('updateRoomCounter', function($q, Ref) {
return function(roomId) {
return $q(function(resolve, reject) {
Ref.child('rooms/'+roomId+'/counter').transaction(function(currentValue) {
if( currentValue >= <NUM_PLAYERS> ) { return; }
return (currentValue||0)+1;
}, function(err, committed, snap) {
if( err || !committed ) {
reject(err || 'Too Many Players');
}
else {
resolve(snap.val());
}
});
});
}
});
Using the counter update:
angular.controller(..., function(updateRoomCounter, Ref) {
function addAPlayer(roomId, userId) {
updateRoomCounter(roomId).then(function(myIndex) {
Ref.child('members/'+roomId+'/'+myIndex).set(userId, <doneFunction>, <errorFunction>);
}, function() {
// failed: try the next room?
})
}
});
Security rules to enforce structure:
{
"rules": {
"rooms": {
"$room_id": {
"counter": {
".write": "newData.exists()",
".validate": "newData.isNumber() && (newData.val() == data.val() + 1 || !data.exists() && newData.val() == 1)"
}
}
},
"members": {
"$room_id": {
"$counter_value": {
".write": "newData.val() === auth.uid && !data.exists() && newData.exists() && $counter_value <= root.child('rooms/'+$room_id+'/counter').val()"
}
}
}
}
}
Kato's answer is a good approach to implement your use-case. I want to chime in on why you are having this problem to begin with.
Firebase transactions work on a mixed client-and-server model. The code that you write for a transaction() runs on the client. It gets the current value as input and returns the new value (or nothing if no change is needed). This entire "current value + new value" package is then sent to the Firebase servers. The Firebase server then does a compare-and-set. If the stored value is the same as what you started the transaction with, your new value will be used. If the current value has changed in the meantime, your new value is rejected and your transaction handler is run again.
In your transaction handler, you don't just update the current value. You also have this snippet:
if(Object.keys(playerList).length % NUM_PLAYERS === NUM_PLAYERS) {
$scope.floodstudyConfig.groups++;
$scope.floodstudyConfig.$save();
}
Since this modifies data outside of the current/return value, it is not part of the transaction. So even if the new value that you return from the transaction on the server is rejected, you will already have updated the group.
I believe I have a solution. Instead of counting just the players per group I also count the current group. I do this in a single object of form {currentPlayers: 0, groups: 0}.
Function to update the counter object:
angular.module('floodStudyApp')
.factory('updateGroupCounter', function($q, Ref) {
return function(floodstudy, NUM_PLAYERS) {
return $q(function(resolve, reject) {
Ref.child('floodStudyConfig/'+floodstudy+'/currentPlayers').transaction(function(currentValue) {
if(currentValue.currentPlayers >= NUM_PLAYERS ) { return {currentPlayers: 1, groups: currentValue.groups +1}; }
return ({currentPlayers: currentValue.currentPlayers+1, groups: currentValue.groups});
}, function(err, committed, snap) {
if( err || !committed ) {
reject(err || 'Too Many Players');
}
else {
resolve(snap.val());
}
});
});
}
});
Function to update the counter object:
angular.module('floodStudyApp')
.controller('WaitingroomCtrl', function ( $scope, $routeParams, Ref, $location, Config, updateGroupCounter) {
function addAPlayer(roomId, userId, NUM_Player) {
updateGroupCounter(roomId, NUM_Player).then(function(currentConfig) {
Ref.child('floodstudy/' + roomId + '/group' + currentConfig.groups+ '/players/' + currentConfig.currentPlayers).set({
user: userId,
playerIndex: currentConfig.currentPlayers,
})
}, function() {
console.log("full");
})
}
Config.getConfig($routeParams.floodstudy).$loaded(function (config) {
$scope.floodstudyConfig = config;
var NUM_PLAYERS = config.playerLimit;
addAPlayer($routeParams.floodstudy, $routeParams.player, NUM_PLAYERS);
});// end get config
});
In my project I am writing e2e tests in node.js and I have a test firebase I am using. So I create a token in node before each describe in the test runs and then I send it to the front end(angular.js) and then I use the authWithCustomToken function to authenticate the person.
The problem is for some reason it isn't even calling the function because I put a console.log statement in the callback and every time my code runs it enters the if $location.search condition but the console.log doesn't print out anything. I dont seem to know what the problem is.
var Firebase = require('firebase');
var FirebaseTokenGenerator = require('firebase-token-generator');
var rootRef = new Firebase('https://xxxxx');
var data = require('./data_helper.js');
rootRef.child('users').set(data.users[0]);
var credentials = {
nonAdmin: {
uid: 'google',
email: 'xxxx'
},
admin: {
uid: 'google',
email: 'xxxxx'
}
};
var logInAndThen = function(options) {
var secret = 'sdmdfmdsjwdsjwjwwewewe';
var tokenGenerator = new FirebaseTokenGenerator(secret);
var token = tokenGenerator.createToken(credentials[options.userType || 'admin']);
browser.get('/login?token=' + token);
var alertDiv = by.className('alert');
//browser.wait(function(){});
var waitOnFirebase = browser.wait(function() {
return browser.isElementPresent(alertDiv);
});
waitOnFirebase.then(function(data) {
console.log('-------', data);
options.cb(data);
});
};
module.exports = logInAndThen;
--------- FRONT END ANGULAR CODE PUT IN APPLICATION.RUN---------------------
if($location.search().token) {
console.log(Refs.root.toString());
Refs.root.authWithCustomToken($location.search().token, function(err, authData) {
console.log(err,authData);
}, {scope: 'email'});
}
I would appreciate it if someone could help me with this
Try getting the token like this (put this in your .run):
var loc = $location.path();
if(loc.search('login?token') > 0) {
token = loc.splice(13)
//now incorporate the 'token' into whatever auth functions you need to.
}
Not entirely sure if this is the most technically 'correct' way of grabbing the token, but it should work for you.
I have been using parse for a while now and I am quite confused by the issue I am having.
Here is one function that I call first:
$scope.followUser = function(usernameToFollow)
{
console.log('ready to follow user: ' + usernameToFollow);
var user = Parse.User.current();
if (user)
{
var FollowUser = Parse.Object.extend('User');
var query = new Parse.Query(FollowUser);
query.equalTo('username', usernameToFollow);
query.find({
success: function(results)
{
var relationToUserPosts = user.relation('followUser');
$scope.userToAdd = results[0];//This is the user I want to add relational data to
relationToUserPosts.add(results[0]);
user.save();
},
error: function(error)
{
alert('Error: ' + error.code + '' + error.message);
}
});
}
else
{
console.log('Need to login a user');
// show the signup or login page
}
};
Next after I call that function I call this function:
$scope.addToFollowers = function()
{
var currUser = Parse.User.current();
console.log($scope.userToAdd);
var followerUser = $scope.userToAdd.relation('followers');
followerUser.add(currUser);
$scope.userToAdd.save();
};
I know for sure the $scope.userToAdd is the user I want, I know the relation I pull from the object is valid its when I try to save this object with $scope.userToAdd.save() is when I get the bad request, with no further information as to why its a bad request. Thank you in advance.
UPDATE:
The first method call has no errors and no bad requests.
Error message:
Well turns out you cannot save a user object unless your are logged in as that user time to find another solution thank you for the help eth3lbert.