How to load JSON feature in Javascript for IE8? - javascript

I am trying to load JSON feature in JavaScript for IE8 in a comparability mode.
I was advised to use douglascrockford/JSON-js to get JSON loaded in obsolete browsers.
Here is what I have done. I added a new file in my resources folder and called it json2.js Then from the JSON-js project I copied the json2.js file content and pasted it into my json2.js file and included the file resources/json2.js into my app.
Now, I am trying to use JSON.stringify to convert an object into json string which is giving me the following error
But when I use JSON.stringify(records) in IE8 under compatibility mode I get this error
Line: 314
Char: 21
Error: Invalid procedure call or argument
Code: 0
Here is what I have done
HTML Markup
<div id="d">Click Here</div>
<div id="s"></div>
Javascript code
var records = {};
$(function(e){
records['123'] = {};
records['456'] = {};
records['123']['rec_id'] = 4456;
records['123']['created_at'] = '';
records['123']['assigned_at'] = '';
records['123']['sys_id'] = 1745;
records['456']['rec_id'] = 4456;
records['456']['created_at'] = '';
records['456']['assigned_at'] = '';
records['456']['sys_id'] = 1745;
$.each(records, function(callID, record){
record['campaign_id'] = '1';
record['offset'] = 123;
record['attempt'] = '7';
record['phone'] = '800-123-4567';
record['identity'] = 123;
record['code'] = 'Some Code';
record['notes'] = 'Some notes';
record['completed_by'] = 'Mike A';
record['name'] = null;
record['completed_at'] = "";
});
$('#d').click(function(e){
$('#s').text( JSON.stringify(records) );
});
});
the above code can be found in the following jFiddle https://jsfiddle.net/4632wf5n/
What can I do to convert my object into json string in IE8 with comparability mode?

Although according to Mozilla Developer Network (MDN), JSON.stringify is supported in IE8, in case if it's not, then you can use the polyfill (i.e. if it's not supported by browser, then use custom implementation). If Douglas JSON.js is not working then, MDN also provides a code for the polyfill, and I have copied that here. Just insert it before any other scripts, and JSON.stringify would work in IE6+ browsers where it's not supported.
if (!window.JSON) {
window.JSON = {
parse: function(sJSON) { return eval('(' + sJSON + ')'); },
stringify: (function () {
var toString = Object.prototype.toString;
var isArray = Array.isArray || function (a) { return toString.call(a) === '[object Array]'; };
var escMap = {'"': '\\"', '\\': '\\\\', '\b': '\\b', '\f': '\\f', '\n': '\\n', '\r': '\\r', '\t': '\\t'};
var escFunc = function (m) { return escMap[m] || '\\u' + (m.charCodeAt(0) + 0x10000).toString(16).substr(1); };
var escRE = /[\\"\u0000-\u001F\u2028\u2029]/g;
return function stringify(value) {
if (value == null) {
return 'null';
} else if (typeof value === 'number') {
return isFinite(value) ? value.toString() : 'null';
} else if (typeof value === 'boolean') {
return value.toString();
} else if (typeof value === 'object') {
if (typeof value.toJSON === 'function') {
return stringify(value.toJSON());
} else if (isArray(value)) {
var res = '[';
for (var i = 0; i < value.length; i++)
res += (i ? ', ' : '') + stringify(value[i]);
return res + ']';
} else if (toString.call(value) === '[object Object]') {
var tmp = [];
for (var k in value) {
if (value.hasOwnProperty(k))
tmp.push(stringify(k) + ': ' + stringify(value[k]));
}
return '{' + tmp.join(', ') + '}';
}
}
return '"' + value.toString().replace(escRE, escFunc) + '"';
};
})()
};
}

Related

Convert javascript array into a php unserializable string

I need to convert a javascript array into a string readable by php "unserialize".
In my javascript, I have:
var params = {};
params['showTitle'] = 0;
params['class'] = '';
params['ajax'] = 0;
params['ajaxDom'] = '';
params['what'] = 'defi';
params['color'] = 'dark';
The output I really need to get is this :
a:6:{s:9:"showTitle";i:0;s:5:"class";s:0:"";s:4:"ajax";i:0;s:7:"ajaxDom";s:0:"";s:4:"what";s:4:"defi";s:5:"color";s:4:"dark";}
Why do I need this? because the output is red on the server side (with php function unserialize) and I cannot change this (it's part of a framework).
My question is : how to convert the javascript array? I've tried (but didn't work):
params = JSON.stringify(params);
params = $.param(params);
It should be easy but I'm stuck... Thank you !
Please see if u can make use of this
http://phpjs.org/functions/serialize/
Just send that js array to the server as JSON, then parse it with json_decode and serialize it with serialize function. Then you can unserialize it.
This function/answer assumes a lot: mainly that the only two types of data in your JavaScript "array" will be integers and strings, none the less it produces the type of output you demonstrated that the PHP unserialize function requires.
var params = {};
params['showTitle'] = 0;
params['class'] = '';
params['ajax'] = 0;
params['ajaxDom'] = '';
params['what'] = 'defi';
params['color'] = 'dark';
function jsArrToPhpSerializedString( arrObj ) {
var str_parts = ['', '', '}'],
arrLen = 0,
ret = '';
for (var prop in arrObj) {
var val = arrObj[prop];
arrLen += 1;
str_parts[1] += 's:' + prop.length + ':"' + prop + '";';
if (typeof val == 'number') {
str_parts[1] += 'i:' + val + ';';
} else if (typeof arrObj[prop] == 'string') {
val = (!val) ? '""' : '"' + val + '"';
str_parts[1] += 's:' + arrObj[prop].length + ':' + val + ';';
}
}
str_parts[0] = 'a:' + arrLen + ':{';
ret = str_parts.join('');
return ret;
}
console.log( jsArrToPhpSerializedString(params) );
// "a:6:{s:9:"showTitle";i:0;s:5:"class";s:0:"";s:4:"ajax";i:0;s:7:"ajaxDom";s:0:"";s:4:"what";s:4:"defi";s:5:"color";s:4:"dark";}"

How to center google maps on users ip address using javascript?

//Using the Google Maps API to create the map.
var myLatlngCenter = new google.maps.LatLng(54.080743,-2.482910);
var mapOptions = {
center: myLatlngCenter,
zoom: 6,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var myMap = new google.maps.Map(document.getElementById("map_canvas"),mapOptions);
At the minute, this how my javascript looks and it centers the map on the new google.maps.LatLng(54.080743,-2.482910);
Is there something I can put inside () to center the map on the users ip address.
You need to identify the lon, lat from the IP so you have a few options
http://ipinfodb.com/ip_location_api_json.php is a useful resource for this
A javascript example of using that is here (from there site)
function geolocate(timezone, cityPrecision, objectVar) {
var api = (cityPrecision) ? "ip-city" : "ip-country";
var domain = 'api.ipinfodb.com';
var url = "http://" + domain + "/v3/" + api + "/?key=<your_api_key>&format=json" + "&callback=" + objectVar + ".setGeoCookie";
var geodata;
var callbackFunc;
var JSON = JSON || {};
// implement JSON.stringify serialization
JSON.stringify = JSON.stringify || function (obj) {
var t = typeof (obj);
if (t != "object" || obj === null) {
// simple data type
if (t == "string") obj = '"'+obj+'"';
return String(obj);
} else {
// recurse array or object
var n, v, json = [], arr = (obj && obj.constructor == Array);
for (n in obj) {
v = obj[n]; t = typeof(v);
if (t == "string") v = '"'+v+'"';
else if (t == "object" && v !== null) v = JSON.stringify(v);
json.push((arr ? "" : '"' + n + '":') + String(v));
}
return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}");
}
};
// implement JSON.parse de-serialization
JSON.parse = JSON.parse || function (str) {
if (str === "") str = '""';
eval("var p=" + str + ";");
return p;
};
//Check if cookie already exist. If not, query IPInfoDB
this.checkcookie = function(callback) {
geolocationCookie = getCookie('geolocation');
callbackFunc = callback;
if (!geolocationCookie) {
getGeolocation();
} else {
geodata = JSON.parse(geolocationCookie);
callbackFunc();
}
}
//API callback function that sets the cookie with the serialized JSON answer
this.setGeoCookie = function(answer) {
if (answer['statusCode'] == 'OK') {
JSONString = JSON.stringify(answer);
setCookie('geolocation', JSONString, 365);
geodata = answer;
callbackFunc();
}
}
//Return a geolocation field
this.getField = function(field) {
try {
return geodata[field];
} catch(err) {}
}
//Request to IPInfoDB
function getGeolocation() {
try {
script = document.createElement('script');
script.src = url;
document.body.appendChild(script);
} catch(err) {}
}
//Set the cookie
function setCookie(c_name, value, expire) {
var exdate=new Date();
exdate.setDate(exdate.getDate()+expire);
document.cookie = c_name+ "=" +escape(value) + ((expire==null) ? "" : ";expires="+exdate.toGMTString());
}
//Get the cookie content
function getCookie(c_name) {
if (document.cookie.length > 0 ) {
c_start=document.cookie.indexOf(c_name + "=");
if (c_start != -1){
c_start=c_start + c_name.length+1;
c_end=document.cookie.indexOf(";",c_start);
if (c_end == -1) {
c_end=document.cookie.length;
}
return unescape(document.cookie.substring(c_start,c_end));
}
}
return '';
}
}
You will need an api key but then good to go
You could also consider using HTML5 geolocation much easier https://developers.google.com/maps/articles/geolocation

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

Serving dynamic .js files with node.js

I'm searching for some kind of 'template/macro engine' for javascript files.
What I need to do is serving javascript files to the browser. These javascript files are mostly static but vary in some ways.
Here's what I'm basically doing at the moment:
app.get('/api/api.js', function (req, res) {
fs.readFile(
path.join(__dirname, './libraries/api.js'),
{ encoding: 'utf8' },
function (err, data) {
if (err) throw err;
res.set('Content-Type', 'text/javascript');
res.send(data);
});
});
Now I need to add/replace some few lines of code within the read file before serving it to the client.
Update:
Here are some examples:
var host = 'http://mydomain.com/';
var domains = ['mydomain1.com', 'mydomain2.org'];
Yes I could use basic search and replace but I wondered if there's a more generic solution.
I solved it writing my own little render engine as you can see here: http://jsfiddle.net/g5PEp/
var ApiRenderer = function(fileContent) {
var fileContent = fileContent || '';
var data = {};
function sourroundString(str, char) {
char = char || '\'';
return char + str + char;
}
function render() {
var result = fileContent,
str;
for(var key in data) {
var substr = '/*{{' + key + '}}*/';
if(typeof data[key] === 'string') {
str = sourroundString(data[key]);
}
if(Object.prototype.toString.call( data[key] ) === '[object Array]') {
str = '[';
for(var i = 0; i < data[key].length; i++) {
str += sourroundString(data[key][i]);
if(i !== data[key].length - 1) {
str += ',';
}
}
str += ']';
}
result = result.replace(substr, str);
}
return result;
}
return {
setData: function(key, value) {
return data[key] = value;
},
render: function() {
return render();
}
}
};
This is working for me at the moment but I'm a bit sad that this doesn't allow me to write valid javascript code in my templates.

How can I add or update a query string parameter?

With javascript how can I add a query string parameter to the url if not present or if it present, update the current value? I am using jquery for my client side development.
I wrote the following function which accomplishes what I want to achieve:
function updateQueryStringParameter(uri, key, value) {
var re = new RegExp("([?&])" + key + "=.*?(&|$)", "i");
var separator = uri.indexOf('?') !== -1 ? "&" : "?";
if (uri.match(re)) {
return uri.replace(re, '$1' + key + "=" + value + '$2');
}
else {
return uri + separator + key + "=" + value;
}
}
Update (2020): URLSearchParams is now supported by all modern browsers.
The URLSearchParams utility can be useful for this in combination with window.location.search. For example:
if ('URLSearchParams' in window) {
var searchParams = new URLSearchParams(window.location.search);
searchParams.set("foo", "bar");
window.location.search = searchParams.toString();
}
Now foo has been set to bar regardless of whether or not it already existed.
However, the above assignment to window.location.search will cause a page load, so if that's not desirable use the History API as follows:
if ('URLSearchParams' in window) {
var searchParams = new URLSearchParams(window.location.search)
searchParams.set("foo", "bar");
var newRelativePathQuery = window.location.pathname + '?' + searchParams.toString();
history.pushState(null, '', newRelativePathQuery);
}
Now you don't need to write your own regex or logic to handle the possible existence of query strings.
However, browser support is poor as it's currently experimental and only in use in recent versions of Chrome, Firefox, Safari, iOS Safari, Android Browser, Android Chrome and Opera. Use with a polyfill if you do decide to use it.
I have expanded the solution and combined it with another that I found to replace/update/remove the querystring parameters based on the users input and taking the urls anchor into consideration.
Not supplying a value will remove the parameter, supplying one will add/update the parameter. If no URL is supplied, it will be grabbed from window.location
function UpdateQueryString(key, value, url) {
if (!url) url = window.location.href;
var re = new RegExp("([?&])" + key + "=.*?(&|#|$)(.*)", "gi"),
hash;
if (re.test(url)) {
if (typeof value !== 'undefined' && value !== null) {
return url.replace(re, '$1' + key + "=" + value + '$2$3');
}
else {
hash = url.split('#');
url = hash[0].replace(re, '$1$3').replace(/(&|\?)$/, '');
if (typeof hash[1] !== 'undefined' && hash[1] !== null) {
url += '#' + hash[1];
}
return url;
}
}
else {
if (typeof value !== 'undefined' && value !== null) {
var separator = url.indexOf('?') !== -1 ? '&' : '?';
hash = url.split('#');
url = hash[0] + separator + key + '=' + value;
if (typeof hash[1] !== 'undefined' && hash[1] !== null) {
url += '#' + hash[1];
}
return url;
}
else {
return url;
}
}
}
Update
There was a bug when removing the first parameter in the querystring, I have reworked the regex and test to include a fix.
Second Update
As suggested by #JarónBarends - Tweak value check to check against undefined and null to allow setting 0 values
Third Update
There was a bug where removing a querystring variable directly before a hashtag would lose the hashtag symbol which has been fixed
Fourth Update
Thanks #rooby for pointing out a regex optimization in the first RegExp object.
Set initial regex to ([?&]) due to issue with using (\?|&) found by #YonatanKarni
Fifth Update
Removing declaring hash var in if/else statement
Based on #amateur's answer (and now incorporating the fix from #j_walker_dev comment), but taking into account the comment about hash tags in the url I use the following:
function updateQueryStringParameter(uri, key, value) {
var re = new RegExp("([?&])" + key + "=.*?(&|#|$)", "i");
if (uri.match(re)) {
return uri.replace(re, '$1' + key + "=" + value + '$2');
} else {
var hash = '';
if( uri.indexOf('#') !== -1 ){
hash = uri.replace(/.*#/, '#');
uri = uri.replace(/#.*/, '');
}
var separator = uri.indexOf('?') !== -1 ? "&" : "?";
return uri + separator + key + "=" + value + hash;
}
}
Edited to fix [?|&] in regex which should of course be [?&] as pointed out in the comments
Edit: Alternative version to support removing URL params as well. I have used value === undefined as the way to indicate removal. Could use value === false or even a separate input param as wanted.
function updateQueryStringParameter(uri, key, value) {
var re = new RegExp("([?&])" + key + "=.*?(&|#|$)", "i");
if( value === undefined ) {
if (uri.match(re)) {
return uri.replace(re, '$1$2').replace(/[?&]$/, '').replaceAll(/([?&])&+/g, '$1').replace(/[?&]#/, '#');
} else {
return uri;
}
} else {
if (uri.match(re)) {
return uri.replace(re, '$1' + key + "=" + value + '$2');
} else {
var hash = '';
if( uri.indexOf('#') !== -1 ){
hash = uri.replace(/.*#/, '#');
uri = uri.replace(/#.*/, '');
}
var separator = uri.indexOf('?') !== -1 ? "&" : "?";
return uri + separator + key + "=" + value + hash;
}
}
}
See it in action at https://jsfiddle.net/cdt16wex/
You can use the browser's native URL API to do this in a fairly simple way, where key and value are your parameter name and parameter value respectively.
const url = new URL(location.href);
url.searchParams.set(key, value);
history.pushState(null, '', url);
This will preserve everything about the URL and only change or add the one query param. You can also use replaceState instead of pushState if you don't want it to create a new browser history entry.
Thanks to modern javascript, node.js and browsers support, we can get out of 3rd-party library whirlpool (jquery, query-string etc.) and DRY ourselves.
Here are javascript(node.js) and typescript version for a function that adds or updates query params of given url:
Javascript
const getUriWithParam = (baseUrl, params) => {
const Url = new URL(baseUrl);
const urlParams = new URLSearchParams(Url.search);
for (const key in params) {
if (params[key] !== undefined) {
urlParams.set(key, params[key]);
}
}
Url.search = urlParams.toString();
return Url.toString();
};
console.info('expected: https://example.com/?foo=bar');
console.log(getUriWithParam("https://example.com", {foo: "bar"}));
console.info('expected: https://example.com/slug?foo=bar#hash');
console.log(getUriWithParam("https://example.com/slug#hash", {foo: "bar"}));
console.info('expected: https://example.com/?bar=baz&foo=bar');
console.log(getUriWithParam("https://example.com?bar=baz", {foo: "bar"}));
console.info('expected: https://example.com/?foo=baz&bar=baz');
console.log(getUriWithParam("https://example.com?foo=bar&bar=baz", {foo: "baz"}));
Typescript
const getUriWithParam = (
baseUrl: string,
params: Record<string, any>
): string => {
const Url = new URL(baseUrl);
const urlParams: URLSearchParams = new URLSearchParams(Url.search);
for (const key in params) {
if (params[key] !== undefined) {
urlParams.set(key, params[key]);
}
}
Url.search = urlParams.toString();
return Url.toString();
};
For React Native
URL is not implemented in React Native. So you have to install react-native-url-polyfill beforehand.
For object params
See the second solution in this answer
Here is my library to do that: https://github.com/Mikhus/jsurl
var u = new Url;
u.query.param='value'; // adds or replaces the param
alert(u)
If it's not set or want to update with a new value you can use:
window.location.search = 'param=value'; // or param=new_value
This is in simple Javascript, by the way.
EDIT
You may want to try using the jquery query-object plugin
window.location.search =
jQuery.query.set("param", 5);
I realize this question is old and has been answered to death, but here's my stab at it. I'm trying to reinvent the wheel here because I was using the currently accepted answer and the mishandling of URL fragments recently bit me in a project.
The function is below. It's quite long, but it was made to be as resilient as possible. I would love suggestions for shortening/improving it. I put together a small jsFiddle test suite for it (or other similar functions). If a function can pass every one of the tests there, I say it's probably good to go.
Update: I came across a cool function for using the DOM to parse URLs, so I incorporated that technique here. It makes the function shorter and more reliable. Props to the author of that function.
/**
* Add or update a query string parameter. If no URI is given, we use the current
* window.location.href value for the URI.
*
* Based on the DOM URL parser described here:
* http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
*
* #param (string) uri Optional: The URI to add or update a parameter in
* #param (string) key The key to add or update
* #param (string) value The new value to set for key
*
* Tested on Chrome 34, Firefox 29, IE 7 and 11
*/
function update_query_string( uri, key, value ) {
// Use window URL if no query string is provided
if ( ! uri ) { uri = window.location.href; }
// Create a dummy element to parse the URI with
var a = document.createElement( 'a' ),
// match the key, optional square brackets, an equals sign or end of string, the optional value
reg_ex = new RegExp( key + '((?:\\[[^\\]]*\\])?)(=|$)(.*)' ),
// Setup some additional variables
qs,
qs_len,
key_found = false;
// Use the JS API to parse the URI
a.href = uri;
// If the URI doesn't have a query string, add it and return
if ( ! a.search ) {
a.search = '?' + key + '=' + value;
return a.href;
}
// Split the query string by ampersands
qs = a.search.replace( /^\?/, '' ).split( /&(?:amp;)?/ );
qs_len = qs.length;
// Loop through each query string part
while ( qs_len > 0 ) {
qs_len--;
// Remove empty elements to prevent double ampersands
if ( ! qs[qs_len] ) { qs.splice(qs_len, 1); continue; }
// Check if the current part matches our key
if ( reg_ex.test( qs[qs_len] ) ) {
// Replace the current value
qs[qs_len] = qs[qs_len].replace( reg_ex, key + '$1' ) + '=' + value;
key_found = true;
}
}
// If we haven't replaced any occurrences above, add the new parameter and value
if ( ! key_found ) { qs.push( key + '=' + value ); }
// Set the new query string
a.search = '?' + qs.join( '&' );
return a.href;
}
window.location.search is read/write.
However - modifying the query string will redirect the page you're on and cause a refresh from the server.
If what you're attempting to do is maintain client side state (and potentially make it bookmark-able), you'll want to modify the URL hash instead of the query string, which keeps you on the same page (window.location.hash is read/write). This is how web sites like twitter.com do this.
You'll also want the back button to work, you'll have to bind javascript events to the hash change event, a good plugin for that is http://benalman.com/projects/jquery-hashchange-plugin/
Here's my approach: The location.params() function (shown below) can be used as a getter or setter. Examples:
Given the URL is http://example.com/?foo=bar&baz#some-hash,
location.params() will return an object with all the query parameters: {foo: 'bar', baz: true}.
location.params('foo') will return 'bar'.
location.params({foo: undefined, hello: 'world', test: true}) will change the URL to http://example.com/?baz&hello=world&test#some-hash.
Here is the params() function, which can optionally be assigned to the window.location object.
location.params = function(params) {
var obj = {}, i, parts, len, key, value;
if (typeof params === 'string') {
value = location.search.match(new RegExp('[?&]' + params + '=?([^&]*)[&#$]?'));
return value ? value[1] : undefined;
}
var _params = location.search.substr(1).split('&');
for (i = 0, len = _params.length; i < len; i++) {
parts = _params[i].split('=');
if (! parts[0]) {continue;}
obj[parts[0]] = parts[1] || true;
}
if (typeof params !== 'object') {return obj;}
for (key in params) {
value = params[key];
if (typeof value === 'undefined') {
delete obj[key];
} else {
obj[key] = value;
}
}
parts = [];
for (key in obj) {
parts.push(key + (obj[key] === true ? '' : '=' + obj[key]));
}
location.search = parts.join('&');
};
I know this is quite old but i want to fires my working version in here.
function addOrUpdateUrlParam(uri, paramKey, paramVal) {
var re = new RegExp("([?&])" + paramKey + "=[^&#]*", "i");
if (re.test(uri)) {
uri = uri.replace(re, '$1' + paramKey + "=" + paramVal);
} else {
var separator = /\?/.test(uri) ? "&" : "?";
uri = uri + separator + paramKey + "=" + paramVal;
}
return uri;
}
jQuery(document).ready(function($) {
$('#paramKey,#paramValue').on('change', function() {
if ($('#paramKey').val() != "" && $('#paramValue').val() != "") {
$('#uri').val(addOrUpdateUrlParam($('#uri').val(), $('#paramKey').val(), $('#paramValue').val()));
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input style="width:100%" type="text" id="uri" value="http://www.example.com/text.php">
<label style="display:block;">paramKey
<input type="text" id="paramKey">
</label>
<label style="display:block;">paramValue
<input type="text" id="paramValue">
</label>
NOTE This is a modified version of #elreimundo
It's so simple with URLSearchParams, supported in all modern browsers (caniuse).
let p = new URLSearchParams();
p.set("foo", "bar");
p.set("name", "Jack & Jill?");
console.log("http://example.com/?" + p.toString());
If you want to modify the existing URL, construct the object like this: new URLSearchParams(window.location.search) and assign the string to window.location.search.
My take from here (compatible with "use strict"; does not really use jQuery):
function decodeURIParams(query) {
if (query == null)
query = window.location.search;
if (query[0] == '?')
query = query.substring(1);
var params = query.split('&');
var result = {};
for (var i = 0; i < params.length; i++) {
var param = params[i];
var pos = param.indexOf('=');
if (pos >= 0) {
var key = decodeURIComponent(param.substring(0, pos));
var val = decodeURIComponent(param.substring(pos + 1));
result[key] = val;
} else {
var key = decodeURIComponent(param);
result[key] = true;
}
}
return result;
}
function encodeURIParams(params, addQuestionMark) {
var pairs = [];
for (var key in params) if (params.hasOwnProperty(key)) {
var value = params[key];
if (value != null) /* matches null and undefined */ {
pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(value))
}
}
if (pairs.length == 0)
return '';
return (addQuestionMark ? '?' : '') + pairs.join('&');
}
//// alternative to $.extend if not using jQuery:
// function mergeObjects(destination, source) {
// for (var key in source) if (source.hasOwnProperty(key)) {
// destination[key] = source[key];
// }
// return destination;
// }
function navigateWithURIParams(newParams) {
window.location.search = encodeURIParams($.extend(decodeURIParams(), newParams), true);
}
Example usage:
// add/update parameters
navigateWithURIParams({ foo: 'bar', boz: 42 });
// remove parameter
navigateWithURIParams({ foo: null });
// submit the given form by adding/replacing URI parameters (with jQuery)
$('.filter-form').submit(function(e) {
e.preventDefault();
navigateWithURIParams(decodeURIParams($(this).serialize()));
});
Based on the answer #ellemayo gave, I came up with the following solution that allows for disabling of the hash tag if desired:
function updateQueryString(key, value, options) {
if (!options) options = {};
var url = options.url || location.href;
var re = new RegExp("([?&])" + key + "=.*?(&|#|$)(.*)", "gi"), hash;
hash = url.split('#');
url = hash[0];
if (re.test(url)) {
if (typeof value !== 'undefined' && value !== null) {
url = url.replace(re, '$1' + key + "=" + value + '$2$3');
} else {
url = url.replace(re, '$1$3').replace(/(&|\?)$/, '');
}
} else if (typeof value !== 'undefined' && value !== null) {
var separator = url.indexOf('?') !== -1 ? '&' : '?';
url = url + separator + key + '=' + value;
}
if ((typeof options.hash === 'undefined' || options.hash) &&
typeof hash[1] !== 'undefined' && hash[1] !== null)
url += '#' + hash[1];
return url;
}
Call it like this:
updateQueryString('foo', 'bar', {
url: 'http://my.example.com#hash',
hash: false
});
Results in:
http://my.example.com?foo=bar
Here is a shorter version that takes care of
query with or without a given parameter
query with multiple parameter values
query containing hash
Code:
var setQueryParameter = function(uri, key, value) {
var re = new RegExp("([?&])("+ key + "=)[^&#]*", "g");
if (uri.match(re))
return uri.replace(re, '$1$2' + value);
// need to add parameter to URI
var paramString = (uri.indexOf('?') < 0 ? "?" : "&") + key + "=" + value;
var hashIndex = uri.indexOf('#');
if (hashIndex < 0)
return uri + paramString;
else
return uri.substring(0, hashIndex) + paramString + uri.substring(hashIndex);
}
The regex description can be found here.
NOTE: This solution is based on #amateur answer, but with many improvements.
Code that appends a list of parameters to an existing url using ES6 and jQuery:
class UrlBuilder {
static appendParametersToUrl(baseUrl, listOfParams) {
if (jQuery.isEmptyObject(listOfParams)) {
return baseUrl;
}
const newParams = jQuery.param(listOfParams);
let partsWithHash = baseUrl.split('#');
let partsWithParams = partsWithHash[0].split('?');
let previousParams = '?' + ((partsWithParams.length === 2) ? partsWithParams[1] + '&' : '');
let previousHash = (partsWithHash.length === 2) ? '#' + partsWithHash[1] : '';
return partsWithParams[0] + previousParams + newParams + previousHash;
}
}
Where listOfParams is like
const listOfParams = {
'name_1': 'value_1',
'name_2': 'value_2',
'name_N': 'value_N',
};
Example of Usage:
UrlBuilder.appendParametersToUrl(urlBase, listOfParams);
Fast tests:
url = 'http://hello.world';
console.log('=> ', UrlParameters.appendParametersToUrl(url, null));
// Output: http://hello.world
url = 'http://hello.world#h1';
console.log('=> ', UrlParameters.appendParametersToUrl(url, null));
// Output: http://hello.world#h1
url = 'http://hello.world';
params = {'p1': 'v1', 'p2': 'v2'};
console.log('=> ', UrlParameters.appendParametersToUrl(url, params));
// Output: http://hello.world?p1=v1&p2=v2
url = 'http://hello.world?p0=v0';
params = {'p1': 'v1', 'p2': 'v2'};
console.log('=> ', UrlParameters.appendParametersToUrl(url, params));
// Output: http://hello.world?p0=v0&p1=v1&p2=v2
url = 'http://hello.world#h1';
params = {'p1': 'v1', 'p2': 'v2'};
console.log('=> ', UrlParameters.appendParametersToUrl(url, params));
// Output: http://hello.world?p1=v1&p2=v2#h1
url = 'http://hello.world?p0=v0#h1';
params = {'p1': 'v1', 'p2': 'v2'};
console.log('=> ', UrlParameters.appendParametersToUrl(url, params));
// Output: http://hello.world?p0=v0&p1=v1&p2=v2#h1
To give an code example for modifying window.location.search as suggested by Gal and tradyblix:
var qs = window.location.search || "?";
var param = key + "=" + value; // remember to URI encode your parameters
if (qs.length > 1) {
// more than just the question mark, so append with ampersand
qs = qs + "&";
}
qs = qs + param;
window.location.search = qs;
A different approach without using regular expressions. Supports 'hash' anchors at the end of the url as well as multiple question mark charcters (?). Should be slightly faster than the regular expression approach.
function setUrlParameter(url, key, value) {
var parts = url.split("#", 2), anchor = parts.length > 1 ? "#" + parts[1] : '';
var query = (url = parts[0]).split("?", 2);
if (query.length === 1)
return url + "?" + key + "=" + value + anchor;
for (var params = query[query.length - 1].split("&"), i = 0; i < params.length; i++)
if (params[i].toLowerCase().startsWith(key.toLowerCase() + "="))
return params[i] = key + "=" + value, query[query.length - 1] = params.join("&"), query.join("?") + anchor;
return url + "&" + key + "=" + value + anchor
}
Use this function to add, remove and modify query string parameter from URL based on jquery
/**
#param String url
#param object param {key: value} query parameter
*/
function modifyURLQuery(url, param){
var value = {};
var query = String(url).split('?');
if (query[1]) {
var part = query[1].split('&');
for (i = 0; i < part.length; i++) {
var data = part[i].split('=');
if (data[0] && data[1]) {
value[data[0]] = data[1];
}
}
}
value = $.extend(value, param);
// Remove empty value
for (i in value){
if(!value[i]){
delete value[i];
}
}
// Return url with modified parameter
if(value){
return query[0] + '?' + $.param(value);
} else {
return query[0];
}
}
Add new and modify existing parameter to url
var new_url = modifyURLQuery("http://google.com?foo=34", {foo: 50, bar: 45});
// Result: http://google.com?foo=50&bar=45
Remove existing
var new_url = modifyURLQuery("http://google.com?foo=50&bar=45", {bar: null});
// Result: http://google.com?foo=50
Here's my slightly different approach to this, written as an excercise
function addOrChangeParameters( url, params )
{
let splitParams = {};
let splitPath = (/(.*)[?](.*)/).exec(url);
if ( splitPath && splitPath[2] )
splitPath[2].split("&").forEach( k => { let d = k.split("="); splitParams[d[0]] = d[1]; } );
let newParams = Object.assign( splitParams, params );
let finalParams = Object.keys(newParams).map( (a) => a+"="+newParams[a] ).join("&");
return splitPath ? (splitPath[1] + "?" + finalParams) : (url + "?" + finalParams);
}
usage:
const url = "http://testing.com/path?empty&value1=test&id=3";
addOrChangeParameters( url, {value1:1, empty:"empty", new:0} )
"http://testing.com/path?empty=empty&value1=1&id=3&new=0"
This answer is just a small tweak of ellemayo's answer. It will automatically update the URL instead of just returning the updated string.
function _updateQueryString(key, value, url) {
if (!url) url = window.location.href;
let updated = ''
var re = new RegExp("([?&])" + key + "=.*?(&|#|$)(.*)", "gi"),
hash;
if (re.test(url)) {
if (typeof value !== 'undefined' && value !== null) {
updated = url.replace(re, '$1' + key + "=" + value + '$2$3');
}
else {
hash = url.split('#');
url = hash[0].replace(re, '$1$3').replace(/(&|\?)$/, '');
if (typeof hash[1] !== 'undefined' && hash[1] !== null) {
url += '#' + hash[1];
}
updated = url;
}
}
else {
if (typeof value !== 'undefined' && value !== null) {
var separator = url.indexOf('?') !== -1 ? '&' : '?';
hash = url.split('#');
url = hash[0] + separator + key + '=' + value;
if (typeof hash[1] !== 'undefined' && hash[1] !== null) {
url += '#' + hash[1];
}
updated = url;
}
else {
updated = url;
}
}
window.history.replaceState({ path: updated }, '', updated);
}
Java script code to find a specific query string and replace its value *
('input.letter').click(function () {
//0- prepare values
var qsTargeted = 'letter=' + this.value; //"letter=A";
var windowUrl = '';
var qskey = qsTargeted.split('=')[0];
var qsvalue = qsTargeted.split('=')[1];
//1- get row url
var originalURL = window.location.href;
//2- get query string part, and url
if (originalURL.split('?').length > 1) //qs is exists
{
windowUrl = originalURL.split('?')[0];
var qs = originalURL.split('?')[1];
//3- get list of query strings
var qsArray = qs.split('&');
var flag = false;
//4- try to find query string key
for (var i = 0; i < qsArray.length; i++) {
if (qsArray[i].split('=').length > 0) {
if (qskey == qsArray[i].split('=')[0]) {
//exists key
qsArray[i] = qskey + '=' + qsvalue;
flag = true;
break;
}
}
}
if (!flag)// //5- if exists modify,else add
{
qsArray.push(qsTargeted);
}
var finalQs = qsArray.join('&');
//6- prepare final url
window.location = windowUrl + '?' + finalQs;
}
else {
//6- prepare final url
//add query string
window.location = originalURL + '?' + qsTargeted;
}
})
});
Here's an alternative method using the inbuilt properties of the anchor HTML element:
Handles multi-valued parameters.
No risk of modifying the # fragment, or anything other than the query string itself.
May be a little easier to read? But it is longer.
var a = document.createElement('a'),
getHrefWithUpdatedQueryString = function(param, value) {
return updatedQueryString(window.location.href, param, value);
},
updatedQueryString = function(url, param, value) {
/*
A function which modifies the query string
by setting one parameter to a single value.
Any other instances of parameter will be removed/replaced.
*/
var fragment = encodeURIComponent(param) +
'=' + encodeURIComponent(value);
a.href = url;
if (a.search.length === 0) {
a.search = '?' + fragment;
} else {
var didReplace = false,
// Remove leading '?'
parts = a.search.substring(1)
// Break into pieces
.split('&'),
reassemble = [],
len = parts.length;
for (var i = 0; i < len; i++) {
var pieces = parts[i].split('=');
if (pieces[0] === param) {
if (!didReplace) {
reassemble.push('&' + fragment);
didReplace = true;
}
} else {
reassemble.push(parts[i]);
}
}
if (!didReplace) {
reassemble.push('&' + fragment);
}
a.search = reassemble.join('&');
}
return a.href;
};
if you want to set multiple parameters at once:
function updateQueryStringParameters(uri, params) {
for(key in params){
var value = params[key],
re = new RegExp("([?&])" + key + "=.*?(&|$)", "i"),
separator = uri.indexOf('?') !== -1 ? "&" : "?";
if (uri.match(re)) {
uri = uri.replace(re, '$1' + key + "=" + value + '$2');
}
else {
uri = uri + separator + key + "=" + value;
}
}
return uri;
}
same function as #amateur's
if jslint gives you an error add this after the for loop
if(params.hasOwnProperty(key))
There are a lot of awkward and unnecessarily complicated answers on this page. The highest rated one, #amateur's, is quite good, although it has a bit of unnecessary fluff in the RegExp. Here is a slightly more optimal solution with cleaner RegExp and a cleaner replace call:
function updateQueryStringParamsNoHash(uri, key, value) {
var re = new RegExp("([?&])" + key + "=[^&]*", "i");
return re.test(uri)
? uri.replace(re, '$1' + key + "=" + value)
: uri + separator + key + "=" + value
;
}
As an added bonus, if uri is not a string, you won't get errors for trying to call match or replace on something that may not implement those methods.
And if you want to handle the case of a hash (and you've already done a check for properly formatted HTML), you can leverage the existing function instead of writing a new function containing the same logic:
function updateQueryStringParams(url, key, value) {
var splitURL = url.split('#');
var hash = splitURL[1];
var uri = updateQueryStringParamsNoHash(splitURL[0]);
return hash == null ? uri : uri + '#' + hash;
}
Or you can make some slight changes to #Adam's otherwise excellent answer:
function updateQueryStringParameter(uri, key, value) {
var re = new RegExp("([?&])" + key + "=[^&#]*", "i");
if (re.test(uri)) {
return uri.replace(re, '$1' + key + "=" + value);
} else {
var matchData = uri.match(/^([^#]*)(#.*)?$/);
var separator = /\?/.test(uri) ? "&" : "?";
return matchData[0] + separator + key + "=" + value + (matchData[1] || '');
}
}
This should serve the purpose:
function updateQueryString(url, key, value) {
var arr = url.split("#");
var url = arr[0];
var fragmentId = arr[1];
var updatedQS = "";
if (url.indexOf("?") == -1) {
updatedQS = encodeURIComponent(key) + "=" + encodeURIComponent(value);
}
else {
updatedQS = addOrModifyQS(url.substring(url.indexOf("?") + 1), key, value);
}
url = url.substring(0, url.indexOf("?")) + "?" + updatedQS;
if (typeof fragmentId !== 'undefined') {
url = url + "#" + fragmentId;
}
return url;
}
function addOrModifyQS(queryStrings, key, value) {
var oldQueryStrings = queryStrings.split("&");
var newQueryStrings = new Array();
var isNewKey = true;
for (var i in oldQueryStrings) {
var currItem = oldQueryStrings[i];
var searchKey = key + "=";
if (currItem.indexOf(searchKey) != -1) {
currItem = encodeURIComponent(key) + "=" + encodeURIComponent(value);
isNewKey = false;
}
newQueryStrings.push(currItem);
}
if (isNewKey) {
newQueryStrings.push(encodeURIComponent(key) + "=" + encodeURIComponent(value));
}
return newQueryStrings.join("&");
}
By using jQuery we can do like below
var query_object = $.query_string;
query_object["KEY"] = "VALUE";
var new_url = window.location.pathname + '?'+$.param(query_object)
In variable new_url we will have new query parameters.
Reference: http://api.jquery.com/jquery.param/
I wanted something that:
Uses the browser's native URL API
Can add, update, get, or delete
Expects the query string after the hash e.g. for single page applications
function queryParam(options = {}) {
var defaults = {
method: 'set',
url: window.location.href,
key: undefined,
value: undefined,
}
for (var prop in defaults) {
options[prop] = typeof options[prop] !== 'undefined' ? options[prop] : defaults[prop]
}
const existing = (options.url.lastIndexOf('?') > options.url.lastIndexOf('#')) ? options.url.substr(options.url.lastIndexOf('?') + 1) : ''
const query = new URLSearchParams(existing)
if (options.method === 'set') {
query.set(options.key, options.value)
return `${options.url.replace(`?${existing}`, '')}?${query.toString()}`
} else if (options.method === 'get') {
const val = query.get(options.key)
let result = val === null ? val : val.toString()
return result
} else if (options.method === 'delete') {
query.delete(options.key)
let result = `${options.url.replace(`?${existing}`, '')}?${query.toString()}`
const lastChar = result.charAt(result.length - 1)
if (lastChar === '?') {
result = `${options.url.replace(`?${existing}`, '')}`
}
return result
}
}
// Usage:
let url = 'https://example.com/sandbox/#page/'
url = queryParam({
url,
method: 'set',
key: 'my-first-param',
value: 'me'
})
console.log(url)
url = queryParam({
url,
method: 'set',
key: 'my-second-param',
value: 'you'
})
console.log(url)
url = queryParam({
url,
method: 'set',
key: 'my-second-param',
value: 'whomever'
})
console.log(url)
url = queryParam({
url,
method: 'delete',
key: 'my-first-param'
})
console.log(url)
const mySecondParam = queryParam({
url,
method: 'get',
key: 'my-second-param',
})
console.log(mySecondParam)
url = queryParam({
url,
method: 'delete',
key: 'my-second-param'
})
console.log(url)
Yeah I had an issue where my querystring would overflow and duplicate, but this was due to my own sluggishness. so I played a bit and worked up some js jquery(actualy sizzle) and C# magick.
So i just realized that after the server has done with the passed values, the values doesn't matter anymore, there is no reuse, if the client wanted to do the same thing evidently it will always be a new request, even if its the same parameters being passed. And thats all clientside, so some caching/cookies etc could be cool in that regards.
JS:
$(document).ready(function () {
$('#ser').click(function () {
SerializeIT();
});
function SerializeIT() {
var baseUrl = "";
baseUrl = getBaseUrlFromBrowserUrl(window.location.toString());
var myQueryString = "";
funkyMethodChangingStuff(); //whatever else before serializing and creating the querystring
myQueryString = $('#fr2').serialize();
window.location.replace(baseUrl + "?" + myQueryString);
}
function getBaseUrlFromBrowserUrl(szurl) {
return szurl.split("?")[0];
}
function funkyMethodChangingStuff(){
//do stuff to whatever is in fr2
}
});
HTML:
<div id="fr2">
<input type="text" name="qURL" value="http://somewhere.com" />
<input type="text" name="qSPart" value="someSearchPattern" />
</div>
<button id="ser">Serialize! and go play with the server.</button>
C#:
using System.Web;
using System.Text;
using System.Collections.Specialized;
public partial class SomeCoolWebApp : System.Web.UI.Page
{
string weburl = string.Empty;
string partName = string.Empty;
protected void Page_Load(object sender, EventArgs e)
{
string loadurl = HttpContext.Current.Request.RawUrl;
string querySZ = null;
int isQuery = loadurl.IndexOf('?');
if (isQuery == -1) {
//If There Was no Query
}
else if (isQuery >= 1) {
querySZ = (isQuery < loadurl.Length - 1) ? loadurl.Substring(isQuery + 1) : string.Empty;
string[] getSingleQuery = querySZ.Split('?');
querySZ = getSingleQuery[0];
NameValueCollection qs = null;
qs = HttpUtility.ParseQueryString(querySZ);
weburl = qs["qURL"];
partName = qs["qSPart"];
//call some great method thisPageRocks(weburl,partName); or whatever.
}
}
}
Okay criticism is welcome (this was a nightly concoction so feel free to note adjustments). If this helped at all, thumb it up, Happy Coding.
No duplicates, each request as unique as you modified it, and due to how this is structured,easy to add more queries dynamicaly from wthin the dom.

Categories

Resources