AngularJS-MongoLab $resource update error - angularjs

I am connecting AngularJS with MongoLab and trying to update the "users" collection.
AngularJS resource service:
angular.module("myApp.services", ["ngResource"])
.constant({
DB_URL: "https://api.mongolab.com/api/1/databases/mydb/collections/users/:id",
API_KEY: "[SOME_RANDOM_KEY]"
})
.factory("UsersService", ["$resource", "DB_URL", "API_KEY", function($resource, DB_URL, API_KEY) {
return $resource(DB_URL, { apiKey: API_KEY, id: "#_id.$oid" }, { update: { method: "PUT" }});
}]);
This is how I am trying to update my users collection:
angular.module("myApp", ["myApp.services"])
.controller("AppController", ["$scope", "UsersService", function($scope, UsersService) {
$scope.users = [];
$scope.getAllUsers = function() {
$scope.users = UsersService.query();
};
$scope.updateUser = function(user) { // user: firstName, lastName, email
//delete user._id;
UsersService.update({}, user, function() {
$scope.users = UsersService.query();
console.log("Users updated successfully");
}, function() {
console.log("Some problems updating the user", arguments);
});
};
}]);
When I try to update the user information, it throws an exception stating:
{ "message" : "cannot change _id of a document old:{ _id: ObjectId('[SOME_RANDOM_KEY]'), firstName: \"Anup\", lastName: \"Vasudeva\", email: \"anup.vasudeva#emal.com\" } new:{ _id: {}, firstName: \"Anup\", lastName: \"Vasudeva\", email: \"anup.vasudeva#email.com\" }"
I am new to MongoDB, so I don't understand why it is creating an empty _id object for the new user instance?

Try changing your $scope.updateUser function to the following:
$scope.updateUser = function (user) {
var userId = user._id.$oid;
user._id = undefined;
UsersService.update({id: userId}, user, function () {
$scope.users = UsersService.query();
console.log("Users updated successfully");
}, function () {
console.log("Some problems updating the user", arguments);
});
};
The update/replacement object ('user'), should not contain the _id property when being passed to UsersService.update(). Mongo will not replace the _id value, so the id will stay the same after the update.
One other thing that's changed in this function is that we're passing the user id as the first parameter of the UsersService.update() function so that mongo knows which document to update.

Related

Firebase angularjs firebase current auth gets replaced when creating a new user

I am working on angular firebase web app, in which as soon as admin login, he can create users by his own.
When admin log in , he is authenticated with firebase.auth()
But what is happening is, as admin creates a new user, the current auth details(admin) gets replaced by newly created user. I want the user creation without creating a newer session
Have a look at my controller:
app.controller('UserAdd', ['$scope','$sessionStorage','$http','$firebaseAuth', '$firebaseArray', '$location' ,'$firebaseObject', 'FBURL', function($scope,$sessionStorage,$http,$firebaseAuth,$firebaseArray, $location ,$firebaseObject, FBURL){
var user = firebase.database().ref().child("users");
$scope.user_auth_data = firebase.auth().currentUser;
$sessionStorage.uID = $scope.user_auth_data.uid ;
$scope.access_points= [];
$scope.teams = [];
$scope.org_details = [];
user.child($sessionStorage.uID).child("OrganizationId").on('value',function(org_id){
$sessionStorage.org_id = org_id.val();
})
user.child($sessionStorage.uID).child("ImagePath").on('value',function(img){
$scope.user_image = img.val();
})
//access points
firebase.database().ref().child("organization").child($sessionStorage.org_id).child("access_points").on('value',function(access_points){
angular.forEach(access_points.val(),function(ap,key){
$scope.access_points.push({id:key,ssid:ap.SSID,bssid:ap.BSSID,display_name:ap.DisplayName,lat:ap.Latitude,lng:ap.Longitude});
})
});
var obj = $firebaseArray(firebase.database().ref().child("organization").child($sessionStorage.org_id).child("access_points"));
obj.$loaded(
function(data) {
},
function(error) {
console.error("Error:", error);
}
);
firebase.database().ref().child("organization").child($sessionStorage.org_id).child("teams").on('value',function(teams){
angular.forEach(teams.val(),function(team,key){
$scope.teams.push({id:key,team_name:team.TeamName,team_leader:team.TeamLeader,channel_name:team.ChannelName});
})
});
var obj = $firebaseArray(firebase.database().ref().child("organization").child($sessionStorage.org_id).child("teams"));
obj.$loaded(
function(data) {
},
function(error) {
console.error("Error:", error);
}
);
$scope.selectItem = function(){
};
//add user
$scope.addUser = function() {
firebase.auth().createUserWithEmailAndPassword($scope.Email, $scope.Password)
.then(function(user) {
//adding single values in user node
var ref = firebase.database().ref().child("users").child(user.uid);
ref.set({
EmployeeId: $scope.emp_id,
Contact: $scope.Contact,
DOB: $scope.date_of_birth,
Designation: $scope.Designation,
Email: $scope.Email,
FirstName: $scope.FirstName,
LastName: $scope.LastName,
OrganizationId: $sessionStorage.org_id,
Gender: $scope.selectedGender,
IsAdmin: false
});
$scope.selectedAccess.forEach(function(access_values){ //adding nested access_points
var ref1 = firebase.database().ref().child("users").child(user.uid).child("AccessPoint").child(access_values.id);
ref1.set({
SSID: access_values.ssid,
BSSID: access_values.bssid,
DisplayName: access_values.display_name,
Latitude: access_values.lat,
Longitude: access_values.lng
});
});
$scope.selectedTeam.forEach(function(team_values){ //adding nested team
var ref2 = firebase.database().ref().child("users").child(user.uid).child("team").child(team_values.id);
ref2.set({
ChannelName: team_values.channel_name,
TeamName: team_values.team_name,
TeamLeader: team_values.team_leader
});
});
$scope.teams.forEach(function(team_values){
var ref3 = firebase.database().ref().child("organization").child($sessionStorage.org_id).child("channels").child(team_values.channel_name).child("info").child("users");
ref3.child(user.uid).set($scope.FirstName+" "+$scope.LastName);
var ref4 = firebase.database().ref().child("organization").child($sessionStorage.org_id).child("user_team").child(team_values.team_name).child(user.uid);
ref4.set($scope.FirstName+" "+$scope.LastName);
});
firebase.auth().sendPasswordResetEmail(user.email);
$location.path('/user_list');
}).catch(function(error) {
console.log(error);
});
};
}]);
Whats needs to be done to remain in same admin session instead of a new one?

Having trouble passing _id parameter in Login.controller

I'm using angular-fullstack-generator.
I'm having trouble with passing _id parameter to some function.
What I'm trying to achieve is after I created a user I want to create another Data in schema referencing to user's id
therefore here is my code
'use strict';
class SignupVendorController {
//end-non-standard
constructor(Auth, $state, $http) {
this.Auth = Auth;
this.$state = $state;
this.$http = $http;
this.submitted = false;
}
//start-non-standard
register(form) {
this.submitted = true;
if (form.$valid) {
this.Auth.createUser({
firstName: this.user.firstName,
lastName: this.user.lastName,
email: this.user.email,
password: this.user.password,
role: 'vendor'
})
.then( Auth => {
this.vendor = Auth.getCurrentUser;
this.createVendor(this.vendor._id);
console.log('user is ' + this.vendor.firstName);
console.log('vendor created');
// Account created, redirect to home
this.$state.go('main');
})
.catch(err => {
err = err.data;
this.errors = {};
// Update validity of form fields that match the mongoose errors
angular.forEach(err.errors, (error, field) => {
form[field].$setValidity('mongoose', false);
this.errors[field] = error.message;
});
});
}
}
createVendor(id) {
var vendor = {
category: ['publishing'],
_owner: id
}
this.$http.post('/api/vendors', vendor);
}
}
angular.module('aApp')
.controller('SignupVendorController', SignupVendorController);
I've tried several syntax modification but it all just got undefined variable on this.vendor.
like this, for instance
var vendor = Auth.getCurrentUser;
console.log('the user is ' + vendor.firstName);
the code cannot read either _id or firstName.
Any kind of help would be very appreciated.
Thank you !
Can you try this?:
this.vendor = Auth.getCurrentUser();
console.log('the user_id is ' + this.vendor._id);
In my App, that's working.

Restangular: first call returns array but subsequent calls return object

I have a AngularJS factory 'UserSrvc'. This is responsible for calling a RESTful back end to get and create user accounts using Restangular:
(function () {
'use strict';
angular
.module('myapp')
.factory('UserSrvc', UserSrvc);
function UserSrvc(Restangular) {
return {
getAllUsers: getAllUsers,
getUser: getUser,
saveUser: saveUser
};
/////////////////////
function getAllUsers(){
return Restangular.all('users').getList();
}
function getUser(user){
return Restangular.setFullResponse(true).one('users', user).get();
}
function saveUser(user) {
return Restangular.all('users').post(user);
}
};
})();
My User controller then has functions for initializing the data for loading in to Angular UI Grid as well as functions for saving a user and getting user data:
(function () {
'use strict';
var controllerId = 'UserCtrl';
// Define the controller on the module
// Inject the dependencies.
// Point to the controller definition function.
angular
.module('myapp')
.controller(controllerId, UserCtrl, ['UserSrvc', 'ngDialog', '$log', 'toaster']);
function UserCtrl(UserSrvc, ngDialog, $log, toaster){
// Using the 'Controller As' syntax, so we assign to the vm variable (for view model).
var vm = this;
var allUsers = [];
// Bindable properties and functions are placed on vm.
vm.activate = activate;
vm.allUsers = {};
vm.toggleForm = false;
vm.saveUser = saveUser;
vm.gridOptions = {
data: allUsers,
enableSorting: true,
enableColumnResizing: true,
enableGridMenu: true,
showGridFooter: true,
showColumnFooter: true,
enableFiltering: true,
columnDefs: [
{name: 'firstName', field: 'First'},
{name: 'lastName', field: 'Last'},
{name: 'login', field: 'Login'},
{name: 'email', field: 'Email'}
]
};
activate();
function activate() {
return getUsers().then(function() {
// User Controller is now activated
$log.info('UserCtrl activated');
});
}
function refreshUserTable() {
return UserSrvc.getAllUsers()
.then(function(data) {
// User table refresh
vm.gridOptions.data = data.data;
$log.info('User table data refreshed.', vm.gridOptions.data);
});
}
function getUsers() {
return UserSrvc.getAllUsers()
.then(function (data) {
$log.debug('data: ', data);
vm.gridOptions.data = data;
//allUsers = data;
$log.debug('allUsers: ', vm.gridOptions.data);
return vm.gridOptions.data;
},
function(response) {
$log.debug("Failed to get users, error with status code", response.status);
});
}
function saveUser(vm) {
var new_user = {
"user": {
"First": vm.user.firstname,
"Last": vm.user.surname,
"Login": vm.user.username,
"Password": vm.user.password,
"Email": vm.user.email
}
};
//$log.debug('The user to be saved: ', user);
return UserSrvc.saveUser(new_user)
.then(function (data) {
$log.debug('The user to be saved: ', new_user);
$log.debug('response: ', data);
// Refresh the table
refreshUserTable(vm);
// Reset the user form
resetForm();
// Close the form
vm.toggleForm = !vm.toggleForm;
// Success toast
toaster.pop("success","User saved", "User '" + new_user.user.Login + "' successfully created");
return data;
},
function(response) {
$log.debug("Failed to save user, error with status code", response.status);
toaster.pop("error", "Unable to save user", "Failed to save user, error with status code " + response.status);
});
}
}
})();
On the first call to UserSrvc.getAllUsers() in the getUsers() function the data parameter from the .then(function(data) returns an array like so:
[
{
"Last": "Jobs",
"Email": "test#example.com",
"Login": "jobs",
"id": 1,
"First": "Steve"
}
]
However, subsequent calls made by refreshUserTable() to the same UserSrvc.getAllUsers(), the data parameter from .then(function(data)) returns an object like so:
{
"data": [
{
"Last": "Jobs",
"Email": "test#example.com",
"Login": "jobs",
"id": 1,
"First": "Steve"
}
]
}
To get it to work I need to pull the data array from the data object by doing data.data.
Why is it that subsequent calls made by the refreshUserTable() return an object and not an array? My suspicion is that it has something to do with the way in which I'm using Restangular or is there something glaringly obvious I've missed?
Ideally I'd like to get rid of the refreshUserTable() function and just use the getAllUsers() to refresh the table.
you set setFullResponse to true which extend your response object. You confused because Restangular uses same property key with you data.
If you want to use full response specifically on one method just use withConfig method of Restangular.
Restangular.withConfig(function(RestangularConfigurer) {
RestangularConfigurer.setFullResponse(true);
});

Getting and Setting a Factory value/object in AngularJS

Part of this is includes the question of whether or not this is possible, but I am trying to make a factory value called currentUser, which will hold a single use from userService. I am trying to figure out how to make this interaction occur.
If my factories are as follows:
app.factory('currentUser', function() {
});
app.factory('userService', function() {
return {
users: [{
name: "John",
password: "12",
email: "test#example.com",
phone: "238-491-2138"
}, {
name: "Austin",
password: "potaoes",
email: "example#gmail.com",
phone: "138-490-1251"
}]
};
});
and I have a controller that does the following, is there a way to put currentuser = userService.users[i];. Or if this is a terrible way of doing it, how might I setup a way to keep track of a "current user"?
$scope.login = function() {
for (var i = 0; i < userService.users.length; i++) {
if (userService.users[i].email.toLowerCase() === $scope.credentials.email.toLowerCase()) {
if (userService.users[i].password === $scope.credentials.password) {
$scope.messageLogin = "Success!";
$timeout(function() {
$timeout(function() {
$location.path("/account");
}, 500)
$scope.loggedIn = true;
$scope.messageLogin = "Redirecting...";
// currentUser == userService.users[i];
}, 500)
} else {
$scope.messageLogin = "Incorrect login details";
}
return;
}
}
$scope.messageLogin = "Username does not exist";
};
Not sure if this is possible due to the fact that the factory seems to always have a return and never a get/set scenario. So if this is a bad use for Factory, how should I go about it?
You have a couple of options. You can make it part of the user service itself:
app.factory('userService', function() {
var currentUser;
return {
getCurrentUser: function() {
return currentUser;
},
setCurrentUser: function(user) {
currentUser = user;
},
users: [{
name: "John",
password: "12",
email: "test#example.com",
phone: "238-491-2138"
}, {
name: "Austin",
password: "potaoes",
email: "example#gmail.com",
phone: "138-490-1251"
}]
};
});
or you can store it in a separate object:
app.factory('currentUser', function() {
var currentUser;
return {
getCurrentUser: function() {
return currentUser;
},
setCurrentUser: function(user) {
currentUser = user;
}
};
});
Services/Factories in AngularJS are singletons, so you should build your application with the expectation that a service will always resolve to the same value.
That being said, your service is just a JavaScript object and its fields/properties are mutable. I don't see anything wrong with adding a field called "current" to your "userService", which is designed to contain a reference to the current user.

Angular and Leaflet : Looping through a promise object and copying its values

In my controller, I have a function executed on ng-init:
// Find a list of Messages
$scope.find = function() {
$scope.messages = Messages.query();
};
That's the service behind the query():
'use strict';
//Messages service used to communicate Messages REST endpoints
angular.module('messages').factory('Messages', ['$resource',
function($resource) {
return $resource('messages/:messageId', { messageId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}
]);
That's how each messag looks (aka the model):
0: Resource
$$hashKey: "00O"
__v: 0
_id: "546fb196971ba6fd20c8db62"
body: "foobar"
created: "2014-11-21T21:41:42.814Z"
location: Object
lat: 50.827409075117785
lng: 4.318828582763672
Angular has a $scope.markers object in which we can push markers that have lat and lng properties.
I need to go through the $scope.messages, get all location.lat and location.lng values and put them in $scope.markers._id.lat , $scope.markers._id.lng ..
How can we achieve this? I used angular.forEach without getting anything logged:
// Find a list of Messages
$scope.find = function() {
$scope.messages = Messages.query();
console.log($scope.messages);
angular.forEach($scope.messages, function(i, location) {
console.log($scope.messages[i]);
});
};
To access the messages from your query you need to do this:
var messages = Messages.query(function() {
console.log(messages);
});
If that correctly returns your messages to your console, your query is ok and you could then add them to your $scope.markers object:
var messages = Messages.query(function() {
angular.forEach(messages, function(obj, key) {
$scope.markers[obj._id] = {
'lat': obj.location.lat,
'lng': obj.location.lng
};
});
});

Resources