Comparing user input to some fields in an array of JSON objects - json

I have a webserver with JSON data in it. This is what my data looks like
[
{
iduser: 1,
username: "joe",
password: "****"
},
{
iduser: 2,
username: "gina",
password: "****"
}
]
In my app I take some user input and wish to compare it to the username and password field. Here is where I check the data
.service('LoginService', function ($q, $http) {
return {
loginUser: function (name, pw) {
var deferred = $q.defer();
var promise = deferred.promise;
var user_data = $http.get("http://<my ip address>:<port>/login");
user_data.then(function ($scope, result) {
$scope.user = result.data;
})
for (var x in $scope.user) {
if (name == x.username && pw == x.password) {
deferred.resolve('Welcome ' + name + '!');
} else {
deferred.reject('Wrong credentials.');
}
}
promise.success = function (fn) {
promise.then(fn);
return promise;
}
promise.error = function (fn) {
promise.then(null, fn);
return promise;
}
return promise;
}
}
})
I am still learning angularJS and I know this is not a secure way to check the data I just want this loop to work.
My understanding of what I have here is that $scope.user holds my JSON data. Then the data is cycled through with the for loop and the user input name is compared to the field username of each iteration. But this is not the case as I am getting a fail every time.
I'm almost certain its a syntax error, but I don't know JavaScript or AngularJS well enough to find the problem. Any help is really appreciated, Thanks.
Edit 1
After what Nujabes said I made some changes since I don't need $scope.
//previous code the same
user_data.then(function (result) {
var user = result.data;
})
for (var x in user) {
if (name == x.username && pw == x.password) {
//prior code the same
I don't think var can hold the data and thats why I'm still getting errors. I think it should be in an array.

I think your syntax error is that you omit $scope.
You should inject $scope service to this line:
.service('LoginService',function($q,$http,$scope){ ...
});
And this code :
user_data.then(function ($scope, result) {
$scope.user = result.data;
});
Omit the $scope.
->
user_data.then(function (result) {
$scope.user = result.data;
});
like this.
Give it a try.
I hope it work.
(However, why do you want to use $scope service in your 'service'?
I think, defining local value and returning some method is a better choice.
and you use the $scope service in your 'controller'.)

$scope.user you are trying to loop through is array right ?
using (for/in) will store the key in the variable x which is in your case the index of each element (0,1,2,..) , to loop through arrays use (for/of) like this :
for (var value of array)
this will give you the values ...

Related

Angular/Http "put" method only returning undefined?

I've been trying to make a very basic app pulling user information from a .json file and "logging them in", and have a json storing whether a user is logged into the app and their user ID. I'm stuck on a method which would take the given email and password, match them to an entry in the users json, then update the login json with the new information (login true, and user ID.) This is what I have so far in the method:
setUserLogIn(email, password):any{
if (this.users){
this.users.forEach(foundUser => {
if (foundUser.email === email && foundUser.password === password){
this.currentUser=foundUser;
let login:Login = {"id": 1, "loginStatus":true, "userId":foundUser.id}
return this.httpService.put<Observable<any>>('http://localhost:7800/loginCheck/1', login)
.pipe(map((log:Observable<Login>) =>{
console.log(log) //this isn't reached, never prints in console
if (log !== undefined){
return true;
}
return false;
}))
}
if (this.currentUser != null){
FetchUserService.isLoggedIn = true;
} else{
FetchUserService.isLoggedIn = false;
}
})
}
}
From my previous tests I know everything else in the method works correctly, just the put only returns undefined. I am subscribing to the method in the controller:
this.fetchUserService.setUserLogIn(this.userEmail, this.userPassword).subscribe(data => {
console.log(data);
})
This method of subscription returns an error. I also tried subscribing in the service itself, like:
return this.httpService.put<Observable<any>>('http://localhost:7800/loginCheck/1', login)
.pipe(map((log:Observable<Login>) =>{
console.log(log)
if (log !== undefined){
log.subscribe(data => {
return data
})
Taking this into the component and logging the result also just returns undefined.
Any suggestions? I have no idea what I'm doing wrong, after searching put methods for the past few hours I can't see any differences in what I have there. Any help is greatly appreciated!
There are multiple issues here.
Parallel subscriptions. Avoid them if possible. Here you could use forkJoin to combine all observables and trigger them in parallel.
Why would an HTTP request emit an Observable as it's response? Most probably it wouldn't.
Currently you aren't returning anything from the function.
Try the following
setUserLogIn (email, password): Observable<any> { // <-- return `Observable` here
if (!this.users) return NEVER;
return forkJoin(
this.users.map(foundUser => {
if (foundUser.email === email && foundUser.password === password) {
this.currentUser = foundUser;
FetchUserService.isLoggedIn = true;
let login: Login = {
"id": 1,
"loginStatus": true,
"userId": foundUser.id
};
return this.httpService.put('http://localhost:7800/loginCheck/1', login).pipe(
map((log: Login) => { // why would an HTTP request emit an observable?
console.log(log);
return (!!log);
})
);
}
FetchUserService.isLoggedIn = false;
return EMPTY; // `forkJoin` emits only when all observables complete
})
);
}

query DB for unknown number of params

Here is a simple express router, I want to give it query params and search the DB for them.
so, if the URL is like this api?x=value1 the app should query the DB for { x:value1 }
if the URL is api?x=value1&y=value2 the app should query the DB for { x:value1, y:value2 }
Since I don't know the number of params in advance, I have created an empty object and appended it with the params if existed.
if there are no params I want to retrieve all documents in DB.
.get(function (req, res){
let update_issue= {}; /*empty object*/
if(req.query.issue_title){update_issue["issue_title"] = req.query.issue_title}
if(req.query.issue_text){update_issue["issue_text"] = req.query.issue_text}
if(req.query.created_by){ update_issue["created_by"] = req.query.created_by }
/*append object if param exists*/
if(Object.keys(update_issue).length !== 0 ){ /*check if that object is not empty*/
db.collection('issues').find(update_issue, (err, data)=>{
res.json(data);
})
}
db.collection('issues').find().toArray((err, data)=>{
res.send(data);
})
this solution keeps giving me TypeError: Converting circular structure to JSON.
I understand that the object is in the form { x : "value" } and it should be JSON object like this { "x": "value" }
I tried flatted, JSON-stringify-safe still the same problem.
can you give me a solution to this problem, or an alternative way to continue the work.
I have solved the problem using node package called Api query params.
here is my code:
var aqp = require('api-query-params');
.get(function (req, res){
let update_issue= aqp(req.query);
if(Object.keys(update_issue).length !== 0 ){ /*check if that object is not empty*/
db.collection('issues').find(update_issue, (err, data)=>{
res.json(data);
})
}
db.collection('issues').find().toArray((err, data)=>{
res.send(data);
})
here is the package : https://www.npmjs.com/package/api-query-params

Why is async.map passing only the value of my JSON?

I have a function in node.js that looks like this:
exports.getAllFlights = function(getRequest) {
// this is the package from npm called "async"
async.map(clients, getFlight, function(err, results) {
getRequest(results);
});
}
The variable clients should be a JSON that looks like this:
{'"A4Q"': 'JZA8187', "'B7P"': 'DAL2098' }.
I expect that the map function will pass the individual indices of the array of the variable clients to getFlight. However, instead it passed the values of that each(ex: 'DAL2098', 'JZA8187' and so on).
Is this the expected functionality? Is there a function in async that will do what I want?
The signature of getFlight is getFlight(identifier, callback). Identifier is what is currently messed up. It returns callback(null, rtn). Null reprsents the nonexistence of an error, rtn represents the JSON that my function produces.
Yes, that's the expected result. The documentation is not very clear but all iterating functions of async.js pass the values of the iterable, not the keys. There is the eachOf series of functions that pass both key and value. For example:
async.eachOf(clients, function (value, key, callback) {
// process each client here
});
Unfortunately there is no mapOf.
If you don't mind not doing things in parallel you can use eachOfSeries:
var results = [];
async.eachOfSeries(clients, function (value, key, callback) {
// do what getFlight needs to do and append to results array
}, function(err) {
getRequest(results);
});
Another (IMHO better) workaround is to use proper arrays:
var clients = [{'A4Q': 'JZA8187'},{'B7P': 'DAL2098'}];
Then use your original logic. However, I'd prefer to use a structure like the following:
var clients = [
{key: 'A4Q', val: 'JZA8187'},
{key: 'B7P', val: 'DAL2098'}
];
First create a custom event. Attach a listener for return data. then process it.
var EventEmitter = require('events');
var myEmitter = new EventEmitter();
myEmitter.emit('clients_data',{'"A4Q"': 'JZA8187'}); //emit your event where ever
myEmitter.on('clients_data', (obj) => {
if (typeof obj !=='undefined') {
if (obj.contructor === Object && Object.keys(obj).lenth == 0) {
console.log('empty');
} else {
for(var key in obj) {
var value = obj[key];
//do what you want here
}
}
}
});
Well, you need to format your clients object properly before you can use it with async.map(). Lodash _.map() can help you:
var client_list = _.map(clients, function(value, key) {
var item = {};
item[key] = value;
return item;
});
After that, you will have an array like:
[ { A4Q: 'JZA8187' }, { B7P: 'DAL2098' } ]
Then, you can use async.map():
exports.getAllFlights = function(getRequest) {
async.map(client_list, getFlight, function(err, results) {
getRequest(results);
});
};

Get multi parameter values one-time from chrome.storage.local

I wanna inject a content script to pages with a method with two parameters. Since the Chrome.storage.local.get() is asynchronous, I have to make sure that all parameters are initialized from the chrome.local.storage and then begin to invoke my method.
Now I can get only one parameter every time with code like :
var parameter1;
storage.get('parameter1', function(items) {
parameter1 = items.parameter1;
if (parameter1) {
//do sothing
}
});
var parameter2;
storage.get('parameter2', function(items) {
parameter2 = items.parameter2;
if (parameter2) {
//do sothing
}
});
But this is not enough to call my method which contains 2 parameters:
function myMethod(parameter1, parameter2);
So how to get and retrieve them ?
If anyone comes back here in 2021 :)
chrome.storage.sync.get(["CONST", "user", "devMode"], (res) => {
reallyAwesomeFunction(res.CONST.PI, res.user.id, res.devMode);
});
You can try something like this -
function myMethod(parameter1, parameter2) {
var details = [parameter1, parameter2];
storage.get(details, function(items) {
alert(items.parameter1 + ' '+items.parameter2);
});
}

Using jQuery.when with array of deferred objects causes weird happenings with local variables

Let's say I have a site which saves phone numbers via an HTTP call to a service and the service returns the new id of the telephone number entry for binding to the telephone number on the page.
The telephones, in this case, are stored in an array called 'telephones' and datacontext.telephones.updateData sends the telephone to the server inside a $.Deferred([service call logic]).promise();
uploadTelephones = function (deffered) {
for (var i = 0; i < telephones.length; i++){
deffered.push(datacontext.telephones.updateData(telephones[i], {
success: function (response) {
telephones[i].telephoneId = response;
},
error: function () {
logger.error('Stuff errored');
}
}));
}
}
Now if I call:
function(){
var deferreds = [];
uploadTelephones(deferreds);
$.when.apply($, deferreds)
.then(function () {
editing(false);
complete();
},
function () {
complete();
});
}
A weird thing happens. All the telephones are sent back to the service and are saved. When the 'success' callback in uploadTelephones method is called with the new id as 'response', no matter which telephone the query relates to, the value of i is always telephones.length+1 and the line
telephones[i].telephoneId = response;
throws an error because telephones[i] does not exist.
Can anyone tell me how to keep the individual values of i in the success callback?
All of your closures (your anonymous functions capturing a variable in the local scope) refer to the same index variable, which will have the value of telephones.length after loop execution. What you need is to create a different variable for every pass through the for loop saving the value of i at the instance of creation at for later use.
To create a new different variable, the easiest way is to create an anonymous function with the code that is to capture the value at that particular place in the loop and immediately execute it.
either this:
for (var i = 0; i < telephones.length; i++)
{
(function () {
var saved = i;
deffered.push(datacontext.telephones.updateData(telephones[saved],
{
success: function (response)
{
telephones[saved].telephoneId = response;
},
error: function ()
{
logger.error('Stuff errored ');
}
}));
})();
}
or this:
for (var i = 0; i < telephones.length; i++)
{
(function (saved) {
deffered.push(datacontext.telephones.updateData(telephones[saved],
{
success: function (response)
{
telephones[saved].telephoneId = response;
},
error: function ()
{
logger.error('Stuff errored ');
}
}));
})(i);
}
should work.
Now, that's a bit ugly, though. Since you are already going through the process of executing an anonymous function over and over, if you want your code to be a little bit cleaner, you might want to look at Array.forEach and just use whatever arguments are passed in, or just use jQuery.each as you are already using jQuery.