How to access an object from a callback function? - javascript

I feel bad because it is very likely this has already been answered and I am just not using the right search terms. I am very new to asynchronous JavaScript. So, I will lead with an apology. If someone could even just help me get the right search terms I would most appreciate it.
I am trying to use the Google feeds api. I have it working when I follow the stock example as laid out in the hello world section. I am trying to make something that is a little more extensible so that I can use it in several places. So I created an object...
function AlertRSS(num, url, div, date) {
this.num = typeof num !== 'undefined' ? num : 5;
this.url = typeof url !== 'undefined' ? url : 'http://arstechnica.com/author/caseyjohnston/feed/';
this.sel = typeof sel !== 'undefined' ? sel : '#alert';
this.date = typeof date !== 'undefined' ? date : this.getYesterday();
}
I then try to call the object inside of the method...
AlertRSS.prototype.displayFeed = function() {
var retval = null;
var feed = new google.feeds.Feed(this.url);
feed.load(function(result) {
var tmp = this;
if (!result.error) {
for ( var i = 0; i < result.feed.entries.length; i++) {
var entry = result.feed.entries[i];
console.log(sel + ' <h2>' + entry.title + '</h2><br />');
$(tmp.sel).append('<h2>' + entry.title + '</h2><br />');
}
}
});
};
However, it seems like I am not able to access the properties from the object. I keep getting a Uncaught ReferenceError: sel is not defined in the console.
I think the issue is related to scope, but at this point I feel a little out of my depth. Any help would be most appreciated.
Update
For a first post this was a travesty. I had numerous mistakes in my code. Both responses were correct. However, in case another poor newb like me sees this question, I wanted to put working code out there.
The issue turned out to be placement of the var tmp = this; line. It needs to be placed outside of the internal callback function to work. As per Tomasz Nurkiewicz suggestion, I also changed var tmp to var that. Working code is as follows:
function AlertRSS(num, url, sel, date) {
this.num = typeof num !== 'undefined' ? num : 5;
this.url = typeof url !== 'undefined' ? url : 'http://arstechnica.com/author/caseyjohnston/feed/';
this.sel = typeof sel !== 'undefined' ? sel : '#alert';
this.date = typeof date !== 'undefined' ? date : this.getYesterday();
}
AlertRSS.prototype.displayFeed = function() {
var feed = new google.feeds.Feed(this.url);
var that = this;
feed.load(function(result) {
if (!result.error) {
for ( var i = 0; i < result.feed.entries.length; i++) {
var entry = result.feed.entries[i];
console.log(that.sel + ' <h2>' + entry.title + '</h2><br />');
$(that.sel).append('<h2>' + entry.title + '</h2><br />');
}
}
});
};

You are correctly creating tmp variable to capture this (note that typically it is called that in this context). You are even correctly using this reference here: tmp.sel. However you forgot to use it in line before that:
console.log(sel + ' <h2>' + entry.title + '</h2><br />');
Change to:
console.log(tmp.sel + //...
and you'll be fine.

Your function params ask for div not sel.

Related

Javascript, create Page title with URL Query string

I am going to create the title of the page according to its URL query String
The URL sample is:
domain.com/pricelist/phones/?min_price=0&max_price=50000
If max_price = 50000, My page title will be: Phones Under Rs.50000
If URL contains only brand like:
domain.com/pricelist/phones/?brand=apple
Page title will be: Apple phones Price list 2018
And if URL contains both price and brand like:
domain.com/pricelist/phones/?min_price=0&max_price=50000&brand=apple
Page title: Apple phones under Rs.50000
here is my code:-
<script>
function getUrlVars() {
var vars = {};
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, key, value) {
vars[key] = value;
});
return vars;
}
var path = window.location.pathname;
var pathName = path.substring(0, path.lastIndexOf('/') + 1);
console.log(path);
console.log(pathName);
pathName = pathName.replace(/\//g, "")
pathName = pathName.replace(/pricelist/g, "")
pathName = pathName.replace(/\b\w/g, l => l.toUpperCase())
var number = getUrlVars()["max_price"];
var brand = getUrlVars()["brand"];
brand = brand.replace(/\b\w/g, l => l.toUpperCase())
if (window.location.href.indexOf("min_price") != null) {document.title = pathName + ' Under Rs. ' + number;}
if (window.location.href.indexOf("pa_brand") > -1) {document.title = brand + ' ' + pathName + ' Price List India';}
if (window.location.href.indexOf("min_price") > -1 && window.location.href.indexOf("brand") > -1) {document.title = brand + ' ' + pathName + ' Under Rs.' + number;}
</script>
First off (in my opinion) I would try to stay away from regular expressions if I could. If you have not heard of URL Search Params, you should read up on it. It makes dealing with the query string very simple.
I also changed the capitalization to not use regular expressions too (source is this answer)
Now for the if statement, which seems like you had trouble with, try to break it down step by step.
First I see if maxPrice is not null, if its not null then great we have our first title: Phones Under Rs.${maxPrice}
Next I check if brand is not null (inside the maxPrice if) this way if brand is not null we can safely assume maxPrice is also not null, so we can change our message to ${brand} Phones Under Rs.${maxPrice}
Now since the only case where we have 2 variables in the message is done we can bounce back out of the first if and continue down to an else if. Now I check if brand is not null. If brand is not null then at this point we can assume maxPrice is also null (otherwise the code would've gone into the first if) so this gives us our final message ${brand} Phones
Now finally an else case just in case we missed something down the road, we can log it and fix the code easily.
Quick note if you are unfamiliar with the backticks in the strings they are Template Literals
var theURL = "https://www.example.com?min_price=0&max_price=5000&brand=apple";
var parsedURL = new URL(theURL);
// you should use window.location.search instead
var searchParams = new URLSearchParams(parsedURL.search);
var maxPrice = searchParams.get("max_price");
var minPrice = searchParams.get("min_price");
var brand = searchParams.get("brand");
// capitalize brand if it is in the query
if (brand !== null) {
brand = brand.toLowerCase()
.split(' ')
.map((s) => s.charAt(0).toUpperCase() + s.substring(1))
.join(' ');
}
// create the title based off which query parameters come through
var title;
if (maxPrice !== null) {
title = `Phones Under Rs.${maxPrice}`
if (brand !== null) {
title = `${brand} Phones Under Rs.${maxPrice}`
}
}
else if (brand !== null) {
title = `${brand} Phones Price list 2018`
}
else {
console.log(`other case came through: brand: ${brand} max_price: ${maxPrice} min_price: ${minPrice}`)
}
console.log(title);
In my opinion, you're having a hard time handling if/else statements, because of overall complexity you've brought to your script. Try to make it simpler and constructing conditions will become a breeze.
I have not tested it, but check out this solution:
function setTitle () {
const search = window.location.search
.substring(1)
.split('&')
.map(pair => pair.split('='))
.reduce((acc, pair) => {
acc[pair[0]] = pair[1];
return acc;
}, {});
const brandPart = search.brand ? `${search.brand} phones` : 'Phones';
const maxPricePart = search.max_price ? `under Rs.${search.max_price}` : '';
const pricePart = maxPricePart || 'Price list 2018';
document.title = `${brandPart} ${pricePart}`;
}
Maybe it has some problems, but it is much easier to understand and maintain.
Your code looks good and I think you can improve OR
as an alternate solution, you can first create a JSON format of all query parameters.
And based on JSON you can easily create the brand title.
https://gomakethings.com/getting-all-query-string-values-from-a-url-with-vanilla-js/
//get query paraeters in json format
var getParams = function (url) {
var params = {};
var parser = document.createElement('a');
parser.href = url;
var query = parser.search.substring(1);
var vars = query.split('&');
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('=');
params[pair[0]] = decodeURIComponent(pair[1]);
}
return params;
};
//get quer pareamaeter
var query_parameters = getParams(window.location.href);
var brand_name = '';
if ( query_parameters.max_price ) brand_name ="Phones Under Rs." + query_parameters.max_price;
if ( query_parameters.brand ) brand_name = query_parameters.brand.toUpperCase() + " phones Price list 2018"
if ( query_parameters.max_price && query_parameters.brand ) brand_name =query_parameters.brand.toUpperCase() + "phones Under Rs." + query_parameters.max_price;

javascript, exception for string/object manipulation

So, I have to functions to turn a string to an object and an object to a string, however I need to account for an except and I am not sure how. Let me show you what I have
parseObjectToUrl: function (obj){
var myStr = "";
var first_iteration = true;
for (var p in obj) {
if(first_iteration){
myStr += p + "=";
first_iteration = false;
}else{
myStr += "&" + p + "=";
}
tObj = obj[p];
var first_inner = true;
for(t in tObj){
if(first_inner){
myStr += t;
first_inner = false;
}else{
myStr += "," + t;
}
yObj = tObj[t];
for( y in yObj){
myStr += "/" + yObj[y];
}
}
}
return myStr;
},
parseObjectFromUrl : function(url){
var builtObj = {};
//remove first slash
url = url.slice(0, 0) + url.slice(1);
var ch = url.split('&');
var tempParent = {};
for (var p in ch) {
var tempSub = {};
var arr = ch[p].split('=');
var keyParent = arr[0];
var splitInside = arr[1].split(",");
for (var i in splitInside) {
var sub = splitInside[i].split('/');
var subKey = sub[0];
tempSub[subKey] = sub.slice(1);
}
tempParent[keyParent] = tempSub;
}
return tempParent
}
So these the string looks like
/module1=mod1/2/3/4,mod2/2/3/4&module2=mod2/3/4/5
and the object looks like
myObj =
{
module1 : { mod1 : [2,3,4] , mod2 [2,3,4]} ,
module2 : { mod2 : [3,4,5]}
}
So these functions work fine for me however I (unfortunately) need to be able to handle the case when the user adds an "/" into the options like -
myObj =
{
module1 : { mod1 : [2/,3/,4/] , mod2 [2,3,4]} ,
module2 : { mod2 : [3,4,5]}
}
I'm sure it's going to throw a wrench in my function because i'm splitting by the "/", so I'm not sure how to get around this. Would i escape the slash? How would that fit into the functions if so? Looking for any advice on this issue. Thanks!
Edit:
I was able to encode the escaped url like :
obj.replace(/([/-])/g, "%2F");
to an escaped url, hoever I am having trouble doing the reverse of this. here is my attempt.
obj.replace(/(%2F)/g, "/");
in my opinion it would be better to use url arrays, but keep in mind the characters for your url could be limited:
maximum length of HTTP GET request?
having said that one could do something like this:
module1[]=1&module1[]=2&module2[]=4&module2[]=3
this is equal to the following pseudo code:
$_GET["module1"] = array(1,2);
$_GET["module2"] = array(4,3);
and use encodeURIComponent & decodeURIComponent for your values
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent

Set URL parameters without causing page refresh

How can you set URL parameters using History.pushState() to avoid browser refreshes? If there is a not a simple JS solution, is there already a popular library or built in function for jQuery?
Here is a relevant SO question, where the accepted answer does not actually work according to comments & my test (it removes the query string instead of updating a value): history.pushState() change query values
Just to be clear, I am referring to the URL parameters in a query string:
http://google.com/page?name=don so we could change don to tim without causing a reload.
Here is one possible solution I found. However I'm nervous about using a JS library that only has 2 followers :P
You can just use queryString.push('my_param_key', 'some_new_value') from the small library below.
It will update your URL param using history.push, so the browser will not refresh.
It will only affect the param you wish to change, it will leave the path and other params unaffected.
/*!
query-string
Parse and stringify URL query strings
https://github.com/sindresorhus/query-string
by Sindre Sorhus
MIT License
*/
(function () {
'use strict';
var queryString = {};
queryString.parse = function (str) {
if (typeof str !== 'string') {
return {};
}
str = str.trim().replace(/^\?/, '');
if (!str) {
return {};
}
return str.trim().split('&').reduce(function (ret, param) {
var parts = param.replace(/\+/g, ' ').split('=');
var key = parts[0];
var val = parts[1];
key = decodeURIComponent(key);
// missing `=` should be `null`:
// http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters
val = val === undefined ? null : decodeURIComponent(val);
if (!ret.hasOwnProperty(key)) {
ret[key] = val;
} else if (Array.isArray(ret[key])) {
ret[key].push(val);
} else {
ret[key] = [ret[key], val];
}
return ret;
}, {});
};
queryString.stringify = function (obj) {
return obj ? Object.keys(obj).map(function (key) {
var val = obj[key];
if (Array.isArray(val)) {
return val.map(function (val2) {
return encodeURIComponent(key) + '=' + encodeURIComponent(val2);
}).join('&');
}
return encodeURIComponent(key) + '=' + encodeURIComponent(val);
}).join('&') : '';
};
queryString.push = function (key, new_value) {
var params = queryString.parse(location.search);
params[key] = new_value;
var new_params_string = queryString.stringify(params)
history.pushState({}, "", window.location.pathname + '?' + new_params_string);
}
if (typeof module !== 'undefined' && module.exports) {
module.exports = queryString;
} else {
window.queryString = queryString;
}
})();
Answering to the question in your comment, you'd be able to read those properties from history.state, a property that holds the value of the stat for the current URL. Whenever you go back and forward you'll receive a popstate event and you will be able tor read the state you pushed, which is far easier than dealing with urls.
Of course, when you go back or forward to a new entry in the history list pushed with pushState() or replaceState() the page does not reload.
You can read more about the History object in the MDN.
Here is a simple function I wrote it isn't as neat as the above answer but it does the trick...
function changeUrlParam (param, value) {
var currentURL = window.location.href;
var urlObject = currentURL.split('?');
var newQueryString = '?';
value = encodeURIComponent(value);
if(urlObject.length > 1){
var queries = urlObject[1].split('&');
var updatedExistingParam = false;
for (i = 0; i < queries.length; i++){
var queryItem = queries[i].split('=');
if(queryItem.length > 1){
if(queryItem[0] == param){
newQueryString += queryItem[0] + '=' + value + '&';
updatedExistingParam = true;
}else{
newQueryString += queryItem[0] + '=' + queryItem[1] + '&';
}
}
}
if(!updatedExistingParam){
newQueryString += param + '=' + value + '&';
}
}else{
newQueryString += param + '=' + value + '&';
}
window.history.replaceState('', '', urlObject[0] + newQueryString.slice(0, -1));
}

Passing variables through parameters in Javascript

Here I have a block of code that I've been debugging over Firebug. I want to know how I can pass my parameter foo into the function getHoliday(param,param,param). Here is the block of code from my XMLHttpRequest.
if (XMLHttpRequestObject.readyState==4 && XMLHttpRequestObject.status == 200)
{
var pp = null
var dd = null
var xmlResponse = XMLHttpRequestObject.responseXML;
var foo = new Array();
foo = parseXML(xmlResponse);
getHoliday(pp,dd,foo);
}
The first two parameters of getHoliday are un-used until later in the process. I want to first load getHoliday with data from the array foo so in the future I can use foo as shown below. As soon as my break point arrives at getHoliday, the script stops so I believe it's the parameters that are wrong. I want to point out, pp and dd are nothing, just place holders for empty undefined parameter.
function getHoliday(monthSelected,theday,names)
{
var HolidayName = new Array();
var holiday = ""
HolidayName = names;
monthSelected = monthSelected + 1;
for(var index = 0; HolidayName.length >= index; index++)
{
if(HolidayName[index] == monthSelected && HolidayName[index+1] == theday)
{
holiday = HolidayName[index+2]
}
}
return holiday
}
As soon as my gets down here, names array that I just passed becomes undefined. Why? Below is how HolidayName array should look.
HolidayName = new Array(2,4,"Party--12:00",2,22,"Eventalist Launch--6:00",2,18,"Play Day--12:00",3,17,"Play Day--12:00"););
When alerting foo the result is:
2,4,"Party--12:00",2,22,"Eventalist Launch--6:00",2,18,"Play Day--12:00",3,17,"Play Day--12:00"
Here is parseXML
function parseXML(xmlData)
{
var aOutput=document.getElementById("testing2");
var events = xmlData.getElementsByTagName('year').length;
for(var i=0;i< events;i++)
{
var eYear = xmlData.getElementsByTagName('year')[i].firstChild.nodeValue;
var eMonth = xmlData.getElementsByTagName('month')[i].firstChild.nodeValue;
var eDay = xmlData.getElementsByTagName('day')[i].firstChild.nodeValue;
var eHour = xmlData.getElementsByTagName('hours')[i].firstChild.nodeValue;
var eMinute = xmlData.getElementsByTagName('minutes')[i].firstChild.nodeValue;
var eTitle = xmlData.getElementsByTagName('title')[i].firstChild.nodeValue;
var holiStr = '"' + eTitle + "--" + eHour +":"+ eMinute + '"';
setup.push(eMonth,eDay, holiStr);
}
return setup;
}
Given the information you have provided, best guess: do you have var foo lower in the code? Javascript does not have block level scoping and these get hoisted to the top of functions and var foo lower could alter your foo value.

javascript / jquery modify query string parameter

I need to add or, if it already exists, modify one parameter of a URL query-string.
If I for example want to set param to the value newvalue,
http://example.org/file.php should lead to http://example.org/file.php?param=newvalue
http://example.org/file.php?abc=def should lead to http://example.org/file.php?abc=def&param=newvalue
http://example.org/file.php?param=oldValue should lead to http://example.org/file.php?param=newvalue
I know about the URI.js library, but it's smallest possible size of 21kb (non-gziped) is too big for me.
I am looking for either a small library to modify url-query-strings, or a small piece of code which does this for me.
Here's a solution in all JS, although it would make sense to make this a combo js/php script
var myParam = "foo"
var oldValue = "bar"
var newValue = "fighters"
var queryPairs = window.location.search.substr(1).split("&");
var queryParams = [];
queryPairs.forEach(function(element, index, array){
var pair = element.split("=");
queryParams[pair[0]] = pair[1];
})
if (queryParams[myParam] == oldValue){
queryParams[myParam] = newValue;
queryPairs = [];
for (var index in queryParams){
queryPairs.push(index + "=" + queryParams[index]);
}
var baseUrl = window.location.href.split("?")[0];
var newSearch = queryPairs.join("&")
var newUrl = baseUrl + "?" + newSearch
window.location = newUrl;
}
My (pretty long) version:
if (location.search.match(/([?&]param)=([^&#]*)/g)) {
location.search = location.search.replace(/([?&]param)=([^&#]*)/g, '$1=' + newvalue);
} else if (location.search.match(/([&][^&#]*)=/g)) {
location.search = location.search + "&param=" + newvalue;
} else {
location.search = location.search + "?param=" + newvalue;
}

Categories

Resources