Removing one item from array results in removing all items at first? - javascript

I'm creating a simple to-do list app with angular and cannot seem to figure out this strange bug. When the page loads initially, if I add tasks to my to-do list, then try to delete one the whole list disappears. However, if I don't refresh and add more task, they will delete individually afterwards. Can someone help me figure out what I'm missing?
Factory:
//Save user in local storage
AccountFactory.saveUser = function (user) {
var users = getUsers();
var index = this.getUser(user.email, 'index');
users[index] = user;
localStorage.setItem('Users', JSON.stringify(users));
return { status: 200, message: 'User saved', data: user };
};
AccountFactory.setCurrentUser = function (user) {
localStorage.setItem('currentUser', JSON.stringify(user));
return { status: 200, message: 'Current user set', data: user };
};
//Delete Task
AccountFactory.removeTask = function (user, task) {
var index = user.tasks.indexOf(task);
user.tasks.splice(index, 1);
return this.saveUser(user);
}
//Get all users function
function getUsers() {
var users = JSON.parse(localStorage.getItem('Users')) || [];
return users;
}
//Get user function
AccountFactory.getUser = function (email, type) {
var users = getUsers();
var account,
index;
for (var i = 0, user; user = users[i]; i++) {
if (user.email.toLowerCase() === email.toLowerCase()) {
account = user;
index = i;
break;
}
}
if (type === 'account') return account;
if (type === 'index') return index;
};
Controller:
function saveUser(user) {
var response = AccountFactory.saveUser(user);
if (response.status === 200) {
var newUser = new User(response.data);
AccountFactory.setCurrentUser(user);
$scope.user = user;
console.log(response.message);
}
}
$scope.removeTask = function (task) {
var response = AccountFactory.removeTask($scope.user, task);
saveUser(user);
}

Related

Code not being executed - Mongoose - Cannot set headers after they are sent to the client

I'm trying to see if the userlookUp in the User.prototype.userExists function is true based on the UserChema.findOne() but for some unknown reason, the block is not being executed if its true. In this case, return this.errors.push('User already exists'), is not being executed.
I have some other error checks in another function, and they work great as they are supposed to (being shown in the browser console) except this one.
Looking for some help.
I appreciate it.
userController.js
const User = require('../models/User');
exports.login = function () {};
exports.logout = function () {};
exports.register = function (req, res) {
let user = new User(req.body);
user.register();
if (user.errors.length) {
res.send(user.errors);
} else {
res.send(user);
res.send('Congrats, there are no errors.');
}
};
exports.home = function (req, res) {
res.send('API up and running!');
};
User.js
const validator = require('validator');
const UserSchema = require('./UserSchema');
const gravatar = require('gravatar');
const bcrypt = require('bcryptjs');
let User = function (data) {
this.data = data;
this.errors = [];
};
User.prototype.cleanUp = function () {
if (typeof this.data.username != 'string') {
this.data.username = '';
}
if (typeof this.data.email != 'string') {
this.data.email = '';
}
if (typeof this.data.password != 'string') {
this.data.password = '';
}
// get rid of any bogus properties
this.data = {
username: this.data.username.trim().toLowerCase(),
email: this.data.email.trim().toLowerCase(),
password: this.data.password,
};
};
User.prototype.validate = function () {
if (this.data.username == '') {
this.errors.push('You must provide a username.');
}
if (
this.data.username != '' &&
!validator.isAlphanumeric(this.data.username)
) {
this.errors.push('Username can only contain letters and numbers.');
}
if (!validator.isEmail(this.data.email)) {
this.errors.push('You must provide a valid email.');
}
if (this.data.password == '') {
this.errors.push('You must provide a password longer than 6 characters.');
}
if (this.data.password.length > 0 && this.data.password.length < 6) {
this.errors.push('The password must be longer than 6 characters.');
}
if (this.data.password.length > 50) {
this.errors.push('The password cannot exceed 50 characters.');
}
if (this.data.username.length < 3 && this.data.username.length > 15) {
this.errors.push('The username must be at least 3 characters.');
}
};
User.prototype.userExists = async function () {
try {
let userLookUp = await UserSchema.findOne({
email: this.data.email,
});
if (userLookUp) {
return this.errors.push('User already exists');
} else {
const avatar = gravatar.url(this.data.email, {
s: '200',
r: 'pg',
d: 'mm',
});
userLookUp = new UserSchema({
username: this.data.username,
email: this.data.email,
password: this.data.password,
avatar: avatar,
});
const salt = await bcrypt.genSalt(10);
userLookUp.password = await bcrypt.hash(this.data.password, salt);
await userLookUp.save();
}
} catch (e) {
console.log('there is a server problem');
}
};
User.prototype.register = function () {
// Step #1: Validate user data
this.cleanUp();
this.validate();
this.userExists();
// Step #2: See if user exists
// Step #3: Get users gravatar
// Step #4: Encrypt the password
// Step #5: Return jsonwebtoken
// Step #6: Only if there are no validation errors
// then save the user data into a database
};
module.exports = User;
In the User.register function you run some functions that are promises (async functions) which are not fulfilled before the User.register function returns.
You can do something like this:
User.prototype.register = async function () {
this.cleanUp();
this.validate();
await this.userExists();
};
...
exports.register = async function (req, res) {
let user = new User(req.body);
await user.register();
if (user.errors.length) {
res.send(user.errors);
} else {
res.send(user);
res.send('Congrats, there are no errors.');
}
};

How to create user specific data when user logs in for the first time in realtime firebase database?

I want the code to behave such that it creates specific data when user is signed in but doesn't create it if already present in the firebase real-time database.
I have used the following code through which i check if the child is already present or not and if not then creates the child in firebase database, but somehow the code isn't behaving as it should.
Whenev the user logins again the complete data part is rewritten.
Snippet I need help in
if (!(checkdata(user.uid))) {
writeUserData(user.uid,user.displayName,user.email,user.photoURL)
}
var database = firebase.database();
function checkdata(userid){
var ref = firebase.database().ref("users");
ref.once("value")
.then(function(snapshot) {
var datapresent = snapshot.hasChild(userid); // true
return datapresent
});
}
function writeUserData(userId, name, email, imageUrl) {
firebase.database().ref('users/' + userId).set({
username: name,
email: email,
profile_picture : imageUrl,
cropdata : []
});
}
Complete JS file
const signInBtn = document.getElementById('signinbtn');
const signOutBtn = document.getElementById('signoutbtn');
const userDetails = document.getElementById('username');
const auth = firebase.auth();
const provider = new firebase.auth.GoogleAuthProvider();
signInBtn.onclick = () => auth.signInWithPopup(provider);
signOutBtn.onclick = () => auth.signOut();
function toggle(className, displayState){
var elements = document.getElementsByClassName(className)
for (var i = 0; i < elements.length; i++){
elements[i].style.display = displayState;
}
}
auth.onAuthStateChanged(function(user) {
if (user) {
// signed in
toggle('userishere', 'block');
toggle('usernothere', 'none');
//userDetails.innerHTML = `<h3>Hello ${user.displayName}!</h3> <p>User ID: ${user.uid}</p>`;
userDetails.innerHTML = `Hello ${user.displayName}!`
console.log(user)
if (!(checkdata(user.uid))) {
writeUserData(user.uid,user.displayName,user.email,user.photoURL)
}
} else {
// not signed in
toggle('userishere', 'none');
toggle('usernothere', 'block');
userDetails.innerHTML = '';
}
});
var database = firebase.database();
function checkdata(userid){
var ref = firebase.database().ref("users");
ref.once("value")
.then(function(snapshot) {
var datapresent = snapshot.hasChild(userid); // true
return datapresent
});
}
function writeUserData(userId, name, email, imageUrl) {
firebase.database().ref('users/' + userId).set({
username: name,
email: email,
profile_picture : imageUrl,
cropdata : []
});
}
I just found the solution, the asynchronous code wasn't waiting for my firebase response and just checeked if datapresent was true or not, so with a async definition before function and await before ref.once(value) does the trick and my problem is solve. Working code below :
const signInBtn = document.getElementById('signinbtn');
const signOutBtn = document.getElementById('signoutbtn');
const userDetails = document.getElementById('username');
var database = firebase.database();
const auth = firebase.auth();
const provider = new firebase.auth.GoogleAuthProvider();
signInBtn.onclick = () => auth.signInWithPopup(provider);
signOutBtn.onclick = () => auth.signOut();
async function checkdata(user){
let ref = firebase.database().ref("users");
let snapshot = await ref.once('value');
if (!snapshot.hasChild(user.uid)){
console.log(user)
writeUserData(user.uid,user.displayName,user.email,user.photoURL)
console.log("write done")
}
else{
console.log("did not write")
}
}
function writeUserData(userId, name, email, imageUrl) {
firebase.database().ref('users/' + userId).set({
username: name,
email: email,
profile_picture: imageUrl,
cropdata: []
});
}
function toggle(className, displayState) {
var elements = document.getElementsByClassName(className)
for (var i = 0; i < elements.length; i++) {
elements[i].style.display = displayState;
}
}
auth.onAuthStateChanged(function (user) {
if (user) {
// signed in
toggle('userishere', 'block');
toggle('usernothere', 'none');
//userDetails.innerHTML = `<h3>Hello ${user.displayName}!</h3> <p>User ID: ${user.uid}</p>`;
userDetails.innerHTML = `Hello ${user.displayName}!`
console.log(user)
checkdata(user)
}
else {
toggle('userishere', 'none');
toggle('usernothere', 'block');
userDetails.innerHTML = '';
}
})

How to obtain the current user's profile image URL from Firebase

I've built a website where users can log in through Facebook, Google, or Twitter, and then their email, name, and profile picture URL will be saved to a Firebase database. Now, I'm trying to obtain the currently logged in user's profile picture URL from the Firebase database, but I have no idea where to start. I've read Firebase's accessing data documentation, but didn't understand it enough to make it work.
This is the function that checks if the user is logged in and then checks if they're an admin. I need to grab the currently logged in user's profile image on the line labeled "RIGHT HERE".
$(document).ready(function() {
var ref = new Firebase("https://mpacares.firebaseio.com/");
ref.onAuth(function (auth) {
if (auth) {
var userRef = ref.child('users').child(auth.uid);
userRef.on('value', function (snap) {
var user = snap.val();
if (user) {
// RIGHT HERE: set the user image src to user.picture
} else {
// TODO: hide the user image
}
}, function (error) {
console.log(error);
});
var adminRef = ref.child('admins').child(auth.uid);
adminRef.on('value', function (snap) {
var user = snap.val();
if (user) {
console.log("You're an admin!");
// enable admin button
} else {
console.log("Sorry, no access for you.");
// disable admin button
}
}, function (error) {
console.log(error);
});
} else {
// logged out
}
});
});
Additionally, you can view my current Firebase app on https://mpacares.firebaseapp.com/.
Here's what worked for me in the end:
$(document).ready(function() {
var ref = new Firebase("https://mpacares.firebaseio.com/");
ref.onAuth(function (auth) {
if (auth) {
var userRef = ref.child('users').child(auth.uid);
userRef.on('value', function (snap) {
var user = snap.val();
if (user) {
$(document).ready(function() {
var ref = new Firebase("https://mpacares.firebaseio.com/");
var user = ref.getAuth();
console.log(user);
var userRef = ref.child('users').child(user.uid);
userRef.once("value", function(snap) {
var user = snap.val();
console.log(user);
console.log(user.name);
console.log(user.picture);
console.log(user.email);
var userName = user.name;
var userPicURL = user.picture;
var userEmail = user.email;
document.getElementById("account-txt").innerHTML = user.name;
$(".account-img").attr("src", userPicURL);
});
});
} else {
$(".account-txt").hide();
$(".account-img").hide();
}
}, function (error) {
console.log(error);
});

Firebase push don't work inside value event

I have code like this:
var firebase = new Firebase('https://<MY_APP>.firebaseio.com');
var users = firebase.child('users');
var usersDefer = $.Deferred();
var userName;
if (window.localStorage) {
userName = localStorage.getItem('username');
if (!userName) {
function newUser(users) {
if (userName) return;
var newUserName = prompt('Enter Username:');
if (users.indexOf(newUserName) !== -1) {
alert('Username already taken');
newUser(users);
} else {
localStorage.setItem('username', newUserName);
userName = newUserName;
console.log('push');
// this push don't work
users.push({
name: newUserName
});
console.log('after');
}
}
usersDefer.then(newUser);
}
}
users.once('value', function(snapshot) {
var value = snapshot.val()
if (value) {
var users = Object.values(value).map(function(object) {
return object.name;
});
usersDefer.resolve(users);
} else {
usersDefer.resolve([]);
}
});
and
users.push({
name: newUserName
});
don't work unless I use developer console, anybody have a clue why?
UPDATE:
Same happen if I use this code without jQuery Deferred
users.once('value', function(snapshot) {
function newUser(users) {
if (userName) return;
var newUserName = prompt('Enter your username');
if (users.indexOf(newUserName) !== -1) {
alert('Username already taken');
newUser(users);
} else {
userName = newUserName;
if (window.localStorage) {
localStorage.setItem('username', newUserName);
}
console.log('push');
users.push({
name: userName
});
console.log('after');
}
}
var value = snapshot.val()
var users;
if (value) {
users = Object.values(value).map(function(object) {
return object.name;
});
} else {
users = [];
}
if (window.localStorage) {
userName = localStorage.getItem('username');
if (!userName) {
newUser(users);
}
} else {
newUser(users);
}
});
The problem was that I was using same variable users for firebase reference and list of users.

How to Implement $child method in new AngularFire v0.8.0?

A user is logged in to the website and tries to create a post. Whenever a new post is created, this post gets associated with the user who created the post.
Referring to a thinkster.io Tutorial, which uses older API of AngularFire.
When using AngularFire API v0.8.0, this line of code which adds the post breaks:
user.$child('posts').$child(postId).$set(postId);
The Post Factory (post.js) with the method for creating post is:
app.factory('Post',
function ($firebase, FIREBASE_URL, User) {
var ref = new Firebase(FIREBASE_URL + 'posts');
var posts = $firebase(ref).$asArray();
var Post = {
all: posts,
//Starting of create function
create: function (post) {
if (User.signedIn()) {
var user = User.getCurrent(); //Gets the current logged in user
post.owner = user.username;
return posts.$add(post).then(function (ref) {
var postId = ref.name();
user.$child('posts').$child(postId).$set(postId);
//user.$getRecord('posts').$getRecord(postId).$set(postId);
return postId;
});
}
},
//End of create function
Changelog for AngularFire states that
$child() no longer exists. The data already exists in the parent object and creating additional synchronized children is not efficient and discouraged. Use data transformations, flatten your data, or drop down to the Firebase SDK and use its child() method.
I am confused as to how to change the code to work with the update in the API.
After Edit
This is the getCurrent method:
getCurrent: function(){ // retrieves current user
return $rootScope.currentUser;
},
Which belongs to user.js Factory:
'use strict';
app.factory('User', function ($firebase, FIREBASE_URL, Auth, $rootScope) {
var ref = new Firebase(FIREBASE_URL + 'users');
var users = $firebase(ref);
var usersdiv = $firebase(ref).$asArray();
var User = {
create: function (authUser, username) {
users[username] = {
md5_hash: authUser.md5_hash,
username: username
};
users.$update(username, {
md5_hash: authUser.md5_hash,
username: username
}).then(function (dataRef) {
dataRef.setPriority(authUser.uid);
setCurrentUser(username);
});
}, // end of create method
findByUsername: function(username){
if(username){
return usersdiv.$getRecord(username);
}
},
getCurrent: function(){ // retrieves current user
return $rootScope.currentUser;
},
signedIn: function(){ //checks if user is signed in
return $rootScope.currentUser !== undefined;
}
}; // end of User
// so that we can pull info about user when logged in
function setCurrentUser (username){
$rootScope.currentUser = User.findByUsername(username);
}
//for logins and refreshes
$rootScope.$on('$firebaseSimpleLogin:login', function(e, authUser){
var queryRef = ref.startAt(authUser.uid).endAt(authUser.uid);
var queryArray = $firebase(queryRef).$asArray();
queryArray.$loaded().then(function() {
setCurrentUser(queryArray.$keyAt(0));
});
});
//logout
$rootScope.$on('$firebaseSimpleLogin:logout', function(){
delete $rootScope.currentUser;
});
return User;
});
You don't need to create a synchronized object locally (what $child used to do) just to set a value in Firebase. You can do this at any time with the Firebase ref you've already created. I can't tell exactly what the data structure of user is since it wasn't included, but something like this:
new Firebase(FIREBASE_URL).child('...path/to/posts').child(postId).set(postId);
Most likely, this belongs on your user object, so that in the Post factory, you can just do something like user.addPost(postId).
I was facing the same problem. As Kato suggested, you will have to use the child function in the Firebase object. I chose to add the post to the user in the Post factory itself.
Adding Post to User
var usersref = new Firebase(FIREBASE_URL + 'users');
usersref.child(post.owner).child('posts').child(postId).set(postId);
The Entire post.js is as below:
'use strict';
app.factory('Post',
function($firebase, FIREBASE_URL, User){
var ref = new Firebase(FIREBASE_URL + 'posts');
var usersref = new Firebase(FIREBASE_URL + 'users');
var posts = $firebase(ref).$asArray();
var Post = {
all : posts,
create : function(post){
if(User.signedIn()){
var user = User.getCurrent();
post.owner = user.username;
return posts.$add(post).then(function(ref){
var postId = ref.name();
usersref.child(post.owner).child('posts').child(postId).set(postId);
return postId;
});
}
},
find: function(postId){
return $firebase(ref.child(postId)).$asObject();
},
delete: function(postId){
if(User.signedIn()){
var postToDel = Post.find(postId);
postToDel.$loaded().then(function(){
var p = posts[postToDel.$id];
posts.$remove(postId).then(function(){
$firebase(usersref.child(p.owner).child('posts')).$asArray().$remove(p.$id);
});
});
}
}
};
return Post;
});
Correct Answer is:
'use strict';
app.factory('Post',
function ($firebase, FIREBASE_URL, User) {
var postsref = new Firebase(FIREBASE_URL + 'posts');
var usersref = new Firebase(FIREBASE_URL + 'users');
var posts = $firebase(postsref).$asArray();
var Post = {
all: posts,
create: function (post) {
if (User.signedIn()) {
var user = User.getCurrent();
post.owner = user.username;
return posts.$add(post).then(function (ref) {
var postId = ref.name();
//a child in user forge should be made with its key as postID
usersref.child(post.owner).child('posts').child(postId).set(postId);
return postId;
});
}
},
find: function (postId) {
return $firebase(postsref.child(postId)).$asObject();
},
delete: function (postId) {
if (User.signedIn()) {
var postToDel = Post.find(postId);
postToDel.$loaded().then(function(){
var p = posts[postToDel.$id];
posts.$remove(postId).then(function(){
$firebase(usersref.child(p.owner).child('posts')).$remove(p.$id);
});
});
}
},
Thus, child can be used at Firebase SDK Level.
Example:
var ref = new Firebase(FIREBASE_URL);
var userArray = $firebase(ref.child('user')).$asArray();
var userObject = $firebase(ref.child('user')).$asObject();

Categories

Resources