Comparing items in $firebaseArray to object and removing matching items - angularjs

I feel like I'm so close, but I can't figure this out.
I have a data tree in Firebase with events and under each event is a list of participants with their user id and name.
-events
-UniqueID
-participants
-userID
facebook_id: "12345678"
display_name: "John Doe"
-userID
facebook_id: "12345678"
display_name: "John Doe"
-userID
facebook_id: "12345678"
display_name: "John Doe"
In my routes I have a resolve function that queries the Facebook API for users who have my app installed and passes a friends object into the controller.
This is a page for the user to invite friends to the event. I want to check the participants array and remove users who are already in the event from the friends object.
I loop through the $firebaseArray and use lodash to find the corresponding id. Lodash's _.find returns the object if found or undefined if not found.
I found this removeItemsById function in another answer here, but it doesn't seem to work.
The _.find works correctly because I see it log the matched item, but it doesn't get removed from the object. Any ideas?
$scope.participants = $firebaseArray(firebase.database().ref().child("events").child($stateParams.eventID).child("participants"));
$scope.participants.$loaded().then(function(){
console.log(friends);
angular.forEach($scope.participants, function(part){
var i = _.toString(part.facebook_id);
console.log(part.facebook_id);
var f = _.find(friends, {'id': i});
console.log("f value is: " + f);
if (f) {
console.log("Found matching facebook id: " + part.facebook_id);
removeItemsById(friends, part.facebook_id);
}
})
$scope.friends = friends;
})
function removeItemsById(arr, id) {
var i = arr.length;
if (i) { // (not 0)
while (--i) {
var cur = arr[i];
if (cur.id == id) {
arr.splice(i, 1);
}
}
}
}

Related

angularjs reinitializing arrays gives me "TypeError: Cannot read property 'push' of undefined"

I am running into a peculiar problem.
I have a my view of drop down list as this in HTML:
<div ng-controller='ConfigurableInputController as configurableInput'>
<select class="fixed-input"
ng-model="configurableInput.selectedCriteria"
ng-change="configurableInput.update()"
ng-options="criterion.selected as criterion.name for criterion in configurableInput.criteriaList">
<option value="">--Please select the comparison criteria--</option>
</select>
The above shows me 3 options in drop down list: Store, Channel and Permissions.
When ever I change the option from Store to Channel or Permissions or any combination the view changes (input boxes, certain labels etc.)
My update() method in controller does this:
configurableInput.update = function () {
configurableInput.permission = "";
configurableInput.id1 = "";
configurableInput.id2 = "";
configurableInput.items1 = "";
configurableInput.items2 = "";
configurableInput.defaultValueArray = [];
configurableInput.permissionsArr = [];
}
On selection of the drop down item, I do a ng-click on a button which retrieves information from Db.
There are 2 flavors of methods which are called on ng-click but the one giving me trouble is this one in the Service method:
StoreConfigurableService.$inject = ['$q', '$http', 'ApiBasePath'];
function ConfigurableService($q, $http, ApiBasePath) {
var service = this;
var defaultValueArr = [];
var permissionsArr = [];
var items1 = "";
var items2 = "";
service.retrievePermissions = function (criterion, id1, id2, rlNumber1, rlNumber2) {
$q.all([
$http.get(ApiBasePath + "/" + criterion + "/" + id1 + "/" + rlNumber1),
$http.get(ApiBasePath + "/" + criterion + "/" + id2 + "/" + rlNumber2)
])
.then(function (response) {
items1 = response[0].data;
items2 = response[1].data;
if (criterion === 'Permissions') {
var processed = false;
permissionsArr = makePermissionsArray(permissionsArr, items1, items2, processed);
}
})
.catch(function (errorResponse) {
console.log("Error: " + errorResponse);
throw errorResponse;
});
};
... so on
In my makePermissionsArray() I am doing this:
function makePermissionsArray(arr, items1, items2, processed) {
var map = items1.storePermissions;
var map2 = items2.storePermissions;
var map3 = items1.allPermissions;
for (var key in map) {
arr.push({
'code': key,
'description': map3[key],
'repStorePermission1': map[key],
'repStorePermission2': map2[key]
});
}
}
I get this permissionsArr back to controller through this:
service.getPermissionsArr = function () {
return permissionsArr;
};
NOTE that 'arr' in the argument of method makePermissionsArray() is not initialized because I am getting it by passing permissionsArr in the argument.
Now how the flow goes is:
First I select Store from drop down list, click on button to retrieves configurables for the store. This gives me correct response.
Then I select 'Permissions' from drop down list, click on button to retrieve permission configurables from Db, it gets stuck and does not get me any response.
I thought I am not clearing the arrays correctly in update() method and after some long search I found and changed these array initializing from:
configurableInput.defaultValueArray = [];
configurableInput.permissionsArr = [];
to
configurableInput.defaultValueArray.length = 0;
configurableInput.permissionsArr.length = 0;
in my update() method.
Now what happens is this:
First I select Store from drop down list, click on button to retrieves configurables for the store. This gives me correct response.
Then I select 'Permissions' from drop down list, click on button to retrieves permission configurables from Db, it gives me correct response.
I select Store from drop down list again, click on button and I get correct response.
But when I again select 'Permissions' from drop down list, click on button, it gives me this error - TypeError: Cannot read property 'push' of undefined
Error I get is at this point:
arr.push({
'code': key,
'description': map3[key],
'repStorePermission1': map[key],
'repStorePermission2': map2[key]
});
I am literally tearing my hair out because of this problem. Can someone please help me what's wrong?

Output all documents in mongoose

I am using mongoose ODM and have a schema which looks like this:
var banSchema = new Schema({
userid: { type: String, required: true, unique: true },
name: String,
groupid: String,
reason: String,
timestamp: Date
});
I want to output every single user id from all documents in the collection. I am using this query to obtain the userid objects. However I cannot seem to get the full list automatically. I have to manually enter the object number as seeen below:
bot.onText(/\/sync/i, function (msg) {
var fromId = msg.from.id;
var chatId = msg.chat.id;
if (fromId == config.sudo) {
console.log('Sudo Confirmed And Authorized!');
Ban.find({}, function (err, obj) {
console.log(obj[0].userid); // Returns A Single ID
console.log(obj[1].toObject().userid); // Returns a different ID
bot.sendMessage(chatId, obj[1].toObject().useridid);
});
} else {
console.log('Someone Is Trying To Act Like Sudo! *sigh*');
bot.sendMessage(chatId, 'You Are Not A Mod!');
}
});
This however does not return a full list of id's as I want. How could I solve this issue?
The code above is for a telegram bot which on a /sync command it should return a message with all ids from the collection.
Telegram bot API Limits
Due to the API limits, the entire output should be in a single message.
var query = Ban.find({}).select({
"userid": 1,
//Add more column fields here
"_id": 0 //Ensures _id is not displayed
});
var arr = [];
query.exec(function (err, results) {
if (err) throw err;
results.forEach(function (result) {
arr.push(result.userid);
// Add more column fields here;
});
var fixedJoin =arr.join("\n");
console.log(fixed);
bot.sendMessage(chatId, 'List\n\n' + fixedJoin);
});
The easiest way to get all values of a particular field across all docs in the collection is to use distinct:
Ban.distinct('userid', function (err, userids) {
// userids is an array containing all userid values in the collection.
// string.join into a single string for the message.
bot.sendMessage(chatId, 'USER IDs\n\n' + userids.join('\n'));
});
Use this syntax
Ban.find({}).
select('userid').
exec(function(err, result) {
//result is array of userid of all document
});
You can use this syntax:
Ban.find({}, 'userid', function(err, users) {
users.forEach(function(user) {
console.log(user);
bot.sendMessage(chatId, 'users \n' + user);
});
})

Search through a JavaScript object and its nested properties looking for something in underscore

I am looking to use .where or .find to look through an array of objects that look like:
Looking for anything that the user inputs that might match.
So imaging, you have this expanded object but you have an array of them. Well as you can see here, there is a relationship between this object (user) and profile (the expanded node). If I enter in (into a search box) "CA", I should get all matching elements back because as we see here: user.profile.data.country === 'CA' evaluates to true.
Now If I enter in "Kyle", again I should get this object back because the middle_name is Kyle.
The question is, how do I use where or find to search an array of objects, going as deep as their nesting goes to search for a value that matches?
An example of how deep nesting can go:
- user
- profile
- contact_info
- id_verification
- investments (array)
- offering
- company
If I type in "shoppers" and shoppers is a company it would then return that object. Ideas?
You can use recursion to find a property with a given value;
I added a path attribute to indicate where the nested object was found
var data = {
user: {
profile: {},
contact_info: {},
id_verification: {
name: 'any'
},
investments: [{
offering: "an offer",
company: "acme"
}, {
offering: "an offer",
company: "shopping"
}]
}
}
function search(obj, toMatch, path) {
path = path ? path : '';
if ((!_.isObject(obj) && !_.isArray(obj)) || _.isEmpty(obj)) return false;
var i = _.indexOf(_.values(obj), toMatch)
if (i > -1) {
var f = {}
f[_.keys(obj)[i]] = _.values(obj)[i];
f.path = path;
return f;
} else {
path = path + '|ANY'
for (var v in obj) {
var a = path.split('|')
a.pop();
a.push(v);
path = a.join('|');
var found = search(obj[v], toMatch, path);
if (found) {
return found;
}
}
}
}
search(data, 'shopping')

Accessing data from a $firebaseobject based on data from another $firebaseobject

I have the following structure on Firebase.
+Groups
-group1
-groupMessage: abc
-groupName: xyz
-members
-User1 = STATUS: "true"
-User2 = STATUS: "pending"
+group2
+group3
etc..
+Users
-User1
-Groups
-group1 = STATUS: "true"
-group3 = STATUS: "pending"
etc..
+User2
+User3
etc..
I'm trying to display group info to individual users based on whether they have a "true" or "pending" status. My app has separate page views for "pending" and "true" statuses.
Below is how I'm trying to achieve this.
.controller('GroupCtrl', function($scope, $firebaseObject, $rootScope) {
// Get a reference to the Firebase account
var fbRef = new Firebase("https://####.firebaseio.com/");
// Get a reference to where the User's Group IDs are stored
var fbUserCircle = new Firebase(fbRef + "/Users/" + $rootScope.fbAuthData.uid + "/Groups/");
var fbCircles = new Firebase(fbRef + "/Groups/");
var obj = $firebaseObject(fbUserCircle.orderByChild("Status").equalTo("pending"));
obj.$loaded().then(function() {
console.log("loaded record:", obj.$id);
// Iterating the key/value pairs of the object
angular.forEach(obj, function(value, key) {
var groupObj = $firebaseObject(fbCircles.child(key));
console.log("$ref: " + circlesObj.$ref());
circlesObj.$loaded().then(function() {
circlesObj.$bindTo($scope, "groups");
})
})
})
})
In my page view I'm trying to display {{groups.groupName}} and {{groups.groupMessage}} over ng-repeat for a user who has groups with a "pending" status.
No data is being displayed in my view for displaying a user's group with "pending" statuses. What am I doing wrong? Anyone one know of a better way of doing this?

Getting object or array value for Auth on Firebase

I'm using angularfire 1.1.1 to store my apps objects and each object creates associated indexes. So when a user is created, that user is added to the 'users' table and then the users index table gets keyed with the UID and points to the actual user's id.
When the main state is called, I run a checkAuth() method to see if a user is signed in. If so, then I want to assign $rootScope.auth = {id:userID, role: role} etc.
The function works great in my login method but i don't know how to grab the value from my checkAuth() method. I've tried $value on both $firebaseObject and $firebaseArray, also tried to call them with [0] since there is only one id value in the table for each user's uid.
The sloppy regex is for changing the semi-colon from SimpleLogin:47 to SimpleLogin-47 for keying to the index.
Here's the code that doesn't work:
function authCheck(){
var getAuth = $firebaseAuth(Data.ref);
console.log('signed in as', getAuth.$getAuth().uid);
var uid = getAuth.$getAuth().uid.toLowerCase().replace(/'+/g, '').replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "-").replace(/^-+|-+$/g, '');
var userIndexRef = Data.ref.child('index/users/uid/'+uid);
var userIndexArray = $firebaseArray(userIndexRef);
var userIndexObject = $firebaseObject(userIndexRef);
console.log(userIndexArray, userIndexObject);
var realId = '';
angular.forEach(userIndexObject, function(key, id){
realId = id;
$rootScope.auth = realId;
return realId;
});
}
Here's the login code that does work:
function login(email, pass) {
ref.authWithPassword({email:email,password:pass}, function(error, authData){
if (error) {
console.log(error);
} else {
console.log('signed in as',authData.uid);
var uid = authData.uid.toLowerCase().replace(/'+/g, '').replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "-").replace(/^-+|-+$/g, '');
angular.forEach(Data.dataObject.index.users.uid[uid],function(id, key){
$rootScope.role = Data.dataObject.users[id].role;
$rootScope.auth = {authData:authData, id:id, role:Data.dataObject.users[id].role};
});
}
});
}
If anyone sees where I've messed up, I'll be happy to know. Here's the repo https://github.com/irthos/medviz if it helps. Thank you very much!

Resources