I have a dictionary of functions which are essentially different calls to an API I am using to receive data (in promises). The way my API has structured its data, in order to get every species from each country, I must make a call to the API modifying the https request, using a keyword q which is specific to each country. I have created an function within the dictionary called sp_b_c, which means species by country. It takes an q, which is the country, where the call itself returns a promise with a promise value of all the species within that country.
I want to create another function in the dictionary which would allow me to grab all species from each country so that it all will be contained for later use.
What I have attempted to do is to create a new function called sp_b_c_all. I make a call to my country_list function in the dictionary to obtain all of the countries. I then iterate through each country and pass each country into the function sp_b_c. I have created an array sp_b_c_entire which essentially acts like a Promise.all, because all of the promises received by iterating through countries and passing each country into a call for sp_b_c results in a returned promise.
However, when making this call getData("accesses", "sp_b_c_all")],
I receive the following error:
script.js:38 Uncaught TypeError: country_li.then is not a function
at Object.accesses.sp_b_c_all (script.js:38)
at getData (script.js:68)
at initialization (script.js:194)
at script.js:365
Below is the code this is referring to:
var getData = function(set, target, q, ...manyMore) {
var pack = [];
// ~ USE rest parameters instead, grab array from ...
// set accesses
var api_token = "9d34bf3f79ae6a8b88c4f1f54ffc3e64e5f4cdcc2cc47bd1cf429e7e247d94b2";
var accesses = new Object();
var alternative = new Object();
// ~ do a promise all, might be overload for API, so limitations
if (set == "accesses") {
accesses.sp_b_c = function(q) {
return d3.json("https://apiv3.iucnredlist.org/api/v3/country/getspecies/"+ q +
"?token=9d34bf3f79ae6a8b88c4f1f54ffc3e64e5f4cdcc2cc47bd1cf429e7e247d94b2")
.then(function(d) { return d; });
}
accesses.sp_b_c_all = function() {
sp_b_c_entire = [];
console.log(accesses.sp_b_c("AE"))
var country_li = accesses.country_list;
country_li.then(function(countries) {
console.log(countries);
countries.forEach(function(country) {
sp_b_c_entire.push(accesses.sp_b_c(country));
})
})
return sp_b_c_entire;
}
accesses.country_list = function() {
return d3.json("https://apiv3.iucnredlist.org/api/v3/country/list?token="+api_token)
.then(function(d) { return d; });
}
accesses.comp_group_list = function() {
return d3.json("https://apiv3.iucnredlist.org/api/v3/comp-group/list?token="+api_token)
.then(function(d) { return d; });
}
accesses.comp_group_specific = function() {
return d3.json("https://apiv3.iucnredlist.org/api/v3/comp-group/getspecies/"+ key +"?token="+api_token)
.then(function(d) { return d; });
}
accesses.threats_regional = function() {
return d3.json("http://apiv3.iucnredlist.org/api/v3/threats/species/name/Ursus%20maritimus/region/europe?token="+api_token)
.then(function(d) { return d; });
}
accesses.threats_global = function() {
return d3.json("http://apiv3.iucnredlist.org/api/v3/threats/species/name/Loxodonta%20africana?token="+api_token)
.then(function(d) { return d; });
}
return accesses[target]();
}
// alternative threat dataset
else if (set == "csv") {
var data = d3.csv(target + ".csv");
var transformation = data.then(
function(d) {
var container = d.map(function(d) {
return {s_n: d.ScientificName,
c_n: d.CommonName,
state: d.States,
group: d.group};
});
pack.push(container);
} // end of anon/callback function
); // end of then function
return data;
} // end of else if conditional
};
I had thought if I made the call accesses.country_list from within accesses.sp_b_c_all that I would receive the promise for the country list. I then utilize then() to access the promise value. Inside of then(countries), countries is the dataset (the list of countries. This is where I utilize a forEach loop to iterate through each country in countries, and then I pass each country into the api call for accesses.sp_b_cwith the country parameter. From this, I hope to receive a promise, and then store it in the array.
What am I doing wrong and how might I fix this? How should I alter my though process, perhaps?
If country_li is a function that returns a promise, you need to call it first to get that promise:
country_li().then(function(countries) {...})
Related
I am filtering data while searching in my application. I am facing the issue to write if condition to check the function selected data and second function filter data.
I have 5 side menus in my application. If I click any one of that, I need to store that value in a variable.
I have another function, I am looping the results there.But I need to check already stored value, and the current function's response value is same or not.
$scope.toggleTab = function (id) {
$scope.categoryId = id;
}
And my another function is,
$scope.getTags = function () {
var keywords_regex = new RegExp($scope.search.split(' ').map(function (i) { return '(?=.*' + i + ')'; }).join(''), 'i');
return $scope.getData.filter(function (data) {
return !!data.match(keywords_regex);
}).map(function (data) {
return data;
});
}
In this map function I need to check the result like this,
}).map(function (data) {
if( selectedData == data.id){
return data;
}
});
How can I do this, I used $rootScope. But When it came inside loop, the result has changed..
I'm just getting started with the method chaining concept in javascript. I'm aware of returning this to chain methods but I'm using revealing module pattern here.
Code:
var currency = (function(){
var rates = {
INR: 64.10
};
function convert(value){
return value * rates["INR"];
//"return this"? and also get the return value (if no chained mathods) ?
}
function format(){
return this.replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,");
}
return {
convert: convert,
format: format
}
})();
I'll call the function in two different ways.
currency.convert(100); //6410; right now it returns rate and this is
expected
currency.convert(1000).format(); //64,100; this is expected
But the problem is if I return this; from the convert function how would #1 be possible? If I don't return this from the convert function method chaining won't be possible.
Q: convert() function in this pattern should be able to perform conversion and return the value if no chaining is requested and should be able to perform chaining?
Please ignore if the format function wrong.
As mentioned in the comments, the pattern you showed in the OP is not suited for chaining. But what you are trying to achieve is absolutely fine. Look through the embedded script to see how this can be done
let CurrencyConverter = (function() {
const rates = {
INR: 64.10
}
// CurrencyConverter class
function CurrencyConverter() {
// instantiate with new
// 'this' inside this function is the new instance
// of CurrencyConverter
this.value = 0;
}
// Add convert method
// this method just convert the value and store it
CurrencyConverter.prototype.convert = function convert(value) {
this.value = value * rates["INR"];
return this;
}
// Add format method
// this method formats the rate and
// return the formatted output
CurrencyConverter.prototype.format = function format() {
return (this.value + "").replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,");
}
// add as many more methods as you want
// ...
// finally return the 'class'
return CurrencyConverter;
})()
// instantiate new converter
let converter = new CurrencyConverter();
// convert
console.log(converter.convert(75).format())
NOTE: The snippet above is not 100% perfect but it is there just to give an idea of how this can be achieved in javascript.
UPDATE - 1
Based on the comment, here is an alternate approach:
let converter = (function() {
// constant rates
const rates = {
INR: 64.10,
GBP: 1.29
}
// converter function
return function convert(value, currency) {
let _val = (value * rates[currency || "INR"]).toFixed(2)
let ret = {}
// value getter
Object.defineProperty(ret, 'value', {
get: () => _val
});
// value formatter
Object.defineProperty(ret, 'formatted', {
get: () => (_val + "").replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,")
});
return ret;
}
})();
// use it like
console.log(converter(125).value)
console.log(converter(120, "GBP").formatted)
So for the past few hours I've been looking into async stuff and using promises. I'm using the testing framework protractor, and theres a few async things I'm having trouble with.
In this save function, I call cm.org1.all() asynchronously, and use then to get the response. I loop over the response, and I need call getNewElement() to each element in the response, which also has an async call in it, so each returns a promise.
So I have this array of promises, but I don't know how to return it. The return of cm.save() is []. I need it to be ['foo',foo',foo',foo']
This code below doesn't work, but it's what I have so far.
var cm = companyManagement() {
//whatever is initialized below is initialized up here
this.save = function() {
cm.saveButton.click();
var elements;
var promises = [];
var defer = protractor.promise.defer();
cm.org1.all(by.repeater('brand in vm.brands'))
.then(function(response) {
//elements is of length 4
elements = response;
for(var i=0; i<elements.length;i++) {
promises.push(getNewElement(elements, i));
}
//defer.fulfill(promises); not correct?
});
return protractor.promise.all(promises); //not correct?
};
function getNewElement(elements, i) {
var defer = protractor.promise.defer();
var alias = elements[i].element(by.binding('brand.alias'));
alias.getText().then(function(aliasText) {
defer.fulfill('foo');
});
return defer.promise;
}
}
cm.save()
.then(function(response){
console.log("my new array is",response);
});
Dealing with protractor promises manually in your tests is usually a sign of overcomplicating a problem. Protractor has a variety of abstractions and functional programming tools that cover most of the use cases.
You can solve it in just a single line if you would use repeater's .column():
this.save = function() {
cm.saveButton.click();
return cm.org1.all(by.repeater('brand in vm.brands').column('brand.alias')).getText();
};
I would do this, but I want to eventually be able to get the element's parent, if the column brand.alias matches with a certain constant I have. if I only have the alias text I couldn't be able to get the parent, correct me if I'm wrong.
filter() and map() to the rescue:
cm.org1.all(by.repeater('brand in vm.brands').column('brand.alias')).filter(alias) {
return alias.getText().then(function (aliasText) {
return aliasText === "foo";
});
}).map(function (alias) {
return alias.element(by.xpath("..")).getText(); // getting the parent
});
Try:
this.save = function() {
cm.saveButton.click();
var elements;
var promises = [];
var defer = protractor.promise.defer();
return cm.org1.all(by.repeater('brand in vm.brands'))
.then(function(response) {
//elements is of length 4
elements = response;
for(var i=0; i<elements.length;i++) {
promises.push(getNewElement(elements, i));
}
return protractor.promise.all(promises);
});
};
Given that I have a class defined such as
(function () {
function Dummy(){
var toReturn ={
myProp : "asdf",
myFunc : myFunc
}
return toReturn;
function myFunc(){};
}
})();
how does one get an instance of the same type after
var dummy = new Dummy();
JSON.stringify(dummy);
so that I have myFunc still available on the type.
JSON.parse(JSON.stringify(dummy)) returns same shape of the object by not the same type.
NOTE: I am not asking about capability of JSON, but how do people deal with this in general. Do you hand roll your mapping mechanism so that after parsing from JSON you map it onto instance of the type, or if there is such functionality in some library, such as underscore.
I created a helper function that helps me do this, but would like to hear from others how do you deal with situation like this. As I put in comments, JSON comes over the wire, for which we have a type defined. To get the values from JSON in our type, we parse json, create instance of type and then apply map function below.
function map(fromObj, toObj) {
Object.keys(fromObj)
.forEach(function (key) {
if (typeof fromObj[key] != 'function') {
if (toObj.hasOwnProperty(key)) {
if (typeof fromObj[key] !== 'object') {
toObj[key] = fromObj[key];
} else {
map(fromObj[key], toObj[key]);
}
}
}
}
});
}
Note, Not certain about requirement , if this similar to what posed at Question. If off-topic , please post comment , will withdraw.
Piece was originally composed for this Question Organizing large javascript files [on hold] . With a json response , having "x" type of contents , could map returned object to new object , copying properties utilizing $.extend() .
Result would be new object having both properties and functions of returned data. At piece below, at completion of process , $.Pages begins as function , then type gets converted to object - though it could retain both function and object properties by including || {} at definition stage.
Functions within returned json objects could be called within .then() callback ; see console at jsfiddle , object init functions.
At conclusion , $.Pages object has properties of returned json , including access to functions . Based on a jsonp - type processing flow.
Piece is "frame" of a processing approach ; could extend to include other functionality
$(function() {
var dfd = new $.Deferred();
dfd.progress(function(msg) {
console.log(msg);
});
ProductPage = {
name : "ProductPage",
addToCartBtn: "#add-to-cart",
initName : function() {return dfd.notify(this.name)},
init: function() {
this.initName();
// ProductPage.initAddToCartPopup();
// ProductPage.initSidebar();
}
};
ContactPage = {
name : "ContactPage",
validateEmail : function (e) {return dfd.notify(e)},
initName : function() {return dfd.notify(this.name)},
init: function() {
this.initName();
// ProductPage.initAddToCartPopup();
// ProductPage.initSidebar();
}
};
var mods = function() {
return {"ContactPage" : ContactPage
, "ProductPage" : ProductPage };
};
$.Pages = function() {
$.when(mods())
.done(function(pages) {
$.Pages = pages;
});
return $.Pages
};
$.when($.Pages())
.then(function() {
$.each($.Pages, function(k, v) {
v.init();
})
});
console.log($.Pages)
});
jsfiddle http://jsfiddle.net/guest271314/60kv2439/1/ (see console)
basic approach
$p = {};
var queue = [];
var mods = ["dep1.json", "service1.json"];
var mod = function(m) {
queue.push(m);
if (queue.length === mods.length) {
$.each(queue, function(k, v) {
$p = $.extend(v, $p)
})
}
};
$.each(mods, function(k, v) {
$.getScript(v, function(script, status, jqxhr) {
console.log($p)
})
})
I am performing a Google local search, and wish to return the lat/long via an object.
The Google search itself works fine.
When inspected (using console.log or alert()) in the object itself, the results field appears to be populated OK.
However, when inspecting the instance of the object (instantiated before running the callback) the result is blank. I'm aware I don't need the accessor function - the end result is the same either way.
Is there something fundamental missing here? Thanks!
function GeoSearch() {
this.results = [];
this.searchComplete = function(localSearch) {
if(localSearch.results[0]) {
var resultLat = localSearch.results[0].lat;
var resultLng = localSearch.results[0].lng;
this.results = localSearch.results[0].lat;
}
}
this.getResults = function() {
return this.results;
}
}
function populateCoords(postcode) {
var localSearch = new google.search.LocalSearch();
var gs = new GeoSearch();
localSearch.setSearchCompleteCallback(gs, gs.searchComplete, [localSearch]);
localSearch.execute(postcode + ", UK");
alert(gs.getResults());
}
When you reference the function gs.searchComplete, you're detaching the method from the object it belongs to. Switch it to function () { gs.searchComplete(); }