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

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);
});
}

Related

Asynchronously working of for loop in protractor

when i execute the following code using protractor it works. I am passing nested json to for loop. Because of asynchronously working of for loop it print all values of variable i and reaches to last value because of this it always access last pair of username and password. How can i solve this issue?
var data = require('.../testdata.json');
describe('homepage Test', function() {
it('candidate login', function() {
browser.driver.get('https://abcxyz.com');
for (i in data.testdata) {
element(by.id('tool_btn3')).click();
console.log(i);
browser.getTitle().then(function(title) {
console.log("Title: " + title)
if (title === "<page title>") {
browser.driver.sleep(3000);
element(by.id('email_input')).sendKeys(data.testdata[i].username);
element(by.id('pwd_input')).sendKeys(data.testdata[i].password);
element(by.xpath('//*[#id="signIn_btn"]/div[2]')).click();
browser.sleep(3000);
element(by.id('setting_img')).click();
browser.sleep(2000);
element(by.id('logout_div')).click().then(function() {
console.log('success');
});
} else {
console.log("problem");
}
});
}
});
});
You need to keep in mind that you can't use a for-loop with promises. All is async so in the end it will bite you in the ass, meaning that the it is ready but the test isn't.
Based on you example it would suggest to make a method called for example logon (place it in a Page Object or something). It will do the logon and stuff for you. Add an empty promise-container (array) and push the promises in there.
When the for-loop is done you can resolve the complete promise-container at once and it will execute all the promises 1 after each other. It will look something like this.
var data = require('.../testdata.json');
describe('homepage Test', function() {
it('candidate login', function() {
var promises = [];
browser.driver.get('https://abcxyz.com');
for (i in data.testdata) {
promises.push(expect(logon(data.testdata[i].username, data.testdata[i].password)).to.equal(true));
promises.push(console.log(i));
}
Promise.all(promises);
});
});
/**
* Logon
* #params {string} username
* #params {string} password
* #return {boolean}
*/
function logon(username, password) {
element(by.id('tool_btn3')).click();\
return browser.getTitle().then(function(title) {
console.log("Title: " + title)
if (title === "<page title>") {
browser.driver.sleep(3000);
element(by.id('email_input')).sendKeys(username);
element(by.id('pwd_input')).sendKeys(password);
element(by.xpath('//*[#id="signIn_btn"]/div[2]')).click();
browser.sleep(3000);
element(by.id('setting_img')).click();
browser.sleep(2000);
return element(by.id('logout_div')).click()
.then(function() {
return Promise.resolve(true);
});
} else {
return Promise.resolve(false);
}
});
}
If you are using for example Node 7 you can use async/await, or use Babel to transpile the code. If you can write TypeScript you also get the async/await

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);
});
};

AngularJS $http and filters

I have a JSON file, which contains:
{
"/default.aspx": "headerBg",
"/about.aspx": "aboutBg",
"/contact.aspx": "contactBg",
"/registration.aspx": "regBg",
"/clients.aspx": "clientsBg",
"/onlinesessions.aspx": "bg-white-box",
"/ondemamdsessions.aspx": "bg-grey"
}
Now I am reading this json file using $http, but I want to add a filter in below fashion:
Using window.location.pathname, I am reading path of the current page, suppose the current page is /about.aspx
Then I want to add a filter in $http response by which I want to read only aboutBg.
The code I wrote can retrieve all the values, but unable to filter that. Please help.
User this function where you receive the response.
function getPageBgClass(currentPage, responseData) {
if (responseData.hasOwnProperty(currentPage))
return responseData[currentPage]
else
return "none"
}
Here is how it should be used in your promise then function
function(response) {
var bg = getPageBgClass(window.location.pathname, response.data);
//Your code here ...
}
there is no direct method to get key using value from json.
you should make sure that there are no 2 keys having same value for below code to work
function swapJsonKeyValues(input) {
var one, output = {};
for (one in input) {
if (input.hasOwnProperty(one)) {
output[input[one]] = one;
}
}
return output;
}
var originaJSON = {
"/default.aspx": "headerBg",
"/about.aspx": "aboutBg",
"/contact.aspx": "contactBg",
"/registration.aspx": "regBg",
"/clients.aspx": "clientsBg",
"/onlinesessions.aspx": "bg-white-box",
"/ondemamdsessions.aspx": "bg-grey"
}
var invertedJSON = swapJsonKeyValues(originaJSON);
var samplepathname = "aboutBg";
var page = invertedJSON[samplepathname];
[function swapJsonKeyValues from https://stackoverflow.com/a/1970193/1006780 ]

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

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 ...

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.