Is there a clever way to figure out all attributes of an object referenced within a function WITHOUT executing it?
For example let's say I have the following function:
var fun = function(a){
a.text = "hello world";
a.title = "greetings";
a.ran = "fun";
}
I would like some magical function that does:
var results = magical_function(fun, {});
// results = ["text", "title", "ran"];
Basically it's returning all attributes of the argument object that will be accessed inside the fun function, WITHOUT having to actually execute fun.
I said "without running" it because I don't want the act of checking this affect any outside app logic, but I am fine as long as the checking doesn't influence the outside world.
function.toString() is going to return a parsable string. Use Regex on that.
var fun = function(a){
a.text = "hello world";
a.title = "greetings";
a.ran = "fun";
}
var fun2 = function(x){
x.text = "hello world";
x.title = "greetings";
a.ran = "fun";
}
function magical_function(func) {
var data = func.toString();
var r = /a\.([a-z]+)/g;
var matches = [];
var match;
while ((match = r.exec(data)) != null) {
matches.push(match[1]);
}
return matches;
}
function magical_function_2(func) {
var data = func.toString();
var attribute_finder_r = new RegExp('function \\(([a-z]+)\\)');
var attribute_name_match = attribute_finder_r.exec(data);
if (!attribute_name_match) {
throw 'Could not match attribute name';
}
var attribute_name = attribute_name_match[1];
var r = new RegExp(attribute_name + '.([a-z]+)', 'g');
var matches = [];
var match;
while ((match = r.exec(data)) != null) {
matches.push(match[1]);
}
return matches;
}
console.log(magical_function(fun));
console.log(magical_function_2(fun2));
var myObj = {
text: '',
title: '',
ran: ''
}
var fun = function(a){
a.text = "hello world";
a.title = "greetings";
a.ran = "fun";
}
function magical_function(func, obj) {
var data = func.toString();
var keys = Object.keys(obj);
var regExp = '';
for (let i= 0; i < keys.length; i++) {
if (keys.length > 1 && ((i+1) < keys.length)) {
regExp += keys[i] + '|';
}
else if (keys.length == 1 || ((i+1) == keys.length)) {
regExp += keys[i];
}
}
regExp = '\.(['+ regExp +']+)\\s*=';
var r = new RegExp(regExp, 'g');
var matches = [];
var match;
while ((match = r.exec(data)) != null) {
if (Object.keys(obj).includes(match[1]))
matches.push(match[1]);
}
return matches;
}
console.log(magical_function(fun, myObj));
There's no way those attributes are going to get set before running the function.
The only thing you can do is to write another version of the function which only accesses the object passed and returns the result.
The idea is when each select field is changed, it will pass part of the directory needed for the form action (the value of each option). ie:
<select onChange="chgFrmAtn" id="1-1">
<option value="">Any</option>
<option value="exDir1Option1">option 1</option>
<option value="exDir1Option2">option 2</option>
</select>
So here is the javascript, basically I want to build 2 directories, several different options. The number of options is much longer than the list in this example script. The options can be in any order. if any is selected, it doesn't add to the directory.
function chgFrmAtn( itemVal )
{
var directory1Part1 = '';
var directory1Part2 = '';
var directory1Part3 = '';
var directory2Part1 = '';
var directory2Part2 = '';
if(itemVal == '1-1'){
directory1Part1 = document.getElementById(itemVal);
}
if(itemVal == '1-2'){
directory1Part2 = document.getElementById(itemVal);
}
if(itemVal == '1-3'){
directory1Part3 = document.getElementById(itemVal);
}
if(itemVal == '2-1'){
directory1Part1 = document.getElementById(itemVal);
}
if(itemVal == '2-2'){
directory1Part2 = document.getElementById(itemVal);
}
document.advancedSearchForm.action = directory1Part1 + directory1Part2 + directory1Part3 + '/' + directory2Part1 + directory2Part2 + '/';
}
Thank you in advance.
You can use two array and map the comparison.
function chgFrmAtn(itemVal) {
var vals = ['1-1', '1-2', '1-3', '2-1', '2-2'],
directory = vals.map(function (a) {
return itemVal === a ? document.getElementById(a) : '';
});
document.advancedSearchForm.action = directory[0] + directory[1] + directory[2] + '/' + directory[3] + directory[4] + '/';
}
try
function chgFrmAtn(itemVal)
{
document.advancedSearchForm.action = document.getElementById(itemVal).value;
}
basically you will only get one value in your directoryxParty since itemVal will remain same and only one if statement will true.
Edit:
If it has to append values from each select, then
var selectIds = ["1-1", "1-2", "1-3", "2-1", "2-2"];
function chgFrmAtn()
{
var vals = selectIds.map(function(id){
var obj = document.getElementById(id);
return obj && obj.value ? obj.value : "";
});
document.advancedSearchForm.action = vals[0] + vals[1] + vals[2] + '/' + vals[3] + vals[4] + '/';
}
I have this code. I apologize for it being messy. I am a novice, hence the problem.It is supposed to populate checkboxes from the querystring. It works in Chrome, Safari, Firefox. Just started testing on IE and in IE 8 it doesn't work. The clicks are registered, but the checkboxes don't populate. No errors are thrown, it seems to simply ignore it.
//set var for queryString - "?"
var queryString = window.location.search.substring(1);
var parameters = queryString.split('&');
var paramObject = new Object();
for( var i =0; i < parameters.length; ++i){
var equalsPos = parameters[i].indexOf('=');
var key = decodeURIComponent(parameters[i].substring(0,equalsPos));
var stringLength = parameters[i].length;
var value = decodeURIComponent(parameters[i].substring(equalsPos + 1, stringLength).replace(/\+/g,' '));
if(!paramObject[key]) {
//console.log('paramObject[key] =' + paramObject[key]);
paramObject[key] = value;
//console.log('paramObject[key] = value = ' + value + paramObject[key]);
//console.log(paramObject[key]);
}else if(paramObject[key] instanceof Array){
paramObject[key].push(value);
//console.log(paramObject[key]);
} else {
var newArray = [];
var existingValue = paramObject[key];
//console.log('existing value: '+ existingValue);
//console.log('value: ' + value);
newArray.push(existingValue);
newArray.push(value);
paramObject[key] = newArray;
}
}
//console.log(paramObject);
for (key in paramObject) {
$('input[name="' + key + '"]').each(function(){
var obj = paramObject[key];
for(prop in obj){
if(obj instanceof Array){
if(obj.hasOwnProperty(prop)){
//console.log(key + '=' + obj[prop]);
if($(this).attr('value') == obj[prop]){
$(this).attr('checked','checked');
}
}
}else{
if(obj.hasOwnProperty(prop)){
if($(this).attr('value') == obj){
$(this).attr('checked','checked');
}
}
}
}
});
}
As answered here IE8 doesn't support the hasOwnProperty() method on host objects. There's a comment there with the answer you're looking for. Good luck!
I was trying to make a JSON Object from a String URL without success
i have this:
var URL = "http://localhost/index.php?module=search¶m1=4";
i need this:
var dir = index.php;
var result = {
module:'search',
param1:4
};
Can anyone help me with the code?
It's not entirely correct to post a link here, but in this case what OP needed is just some library to parse urls.
And here it is: http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
This function can parse variables AND arrays from a string URL:
function url2json(url) {
var obj={};
function arr_vals(arr){
if (arr.indexOf(',') > 1){
var vals = arr.slice(1, -1).split(',');
var arr = [];
for (var i = 0; i < vals.length; i++)
arr[i]=vals[i];
return arr;
}
else
return arr.slice(1, -1);
}
function eval_var(avar){
if (avar[1].indexOf('[') == 0)
obj[avar[0]] = arr_vals(avar[1]);
else
obj[avar[0]] = avar[1];
}
if (url.indexOf('?') > -1){
var params = url.split('?')[1];
if(params.indexOf('&') > 2){
var vars = params.split('&');
for (var i in vars)
eval_var(vars[i].split('='));
}
else
eval_var(params.split('='));
}
return obj;
}
In your case:
obj = url2json("http://localhost/index.php?module=search¶m1=4");
console.log(obj.module);
console.log(obj.param1);
Gives:
"search"
"4"
If you want to convert "4" to an integer you have to do it manually.
This simple javascript does it
url = "http://localhost/index.php?module=search¶m1=4";
var parameters = url.split("?");
var string_to_be_parsed = parameters[1];
var param_pair_string = string_to_be_parsed.split("&");
alert(param_pair_string.length);
var i = 0;
var json_string = "{"
for(;i<param_pair_string.length;i++){
var pair = param_pair_string[i].split("=");
if(i < param_pair_string.length - 1 )
json_string += pair[0] + ":'" + pair[1] + "',";
else
json_string += pair[0] + ":'" + pair[1] + "'";
}
json_string += "}";
alert(json_string);
I'm wondering how I can add a new parameter to an existing url.
The problem is: the url may also contain an anchor.
For example:
http://www.example.com?foo=bar#hashme
And I want to add another parameter to it, so it results in this:
http://www.example.com?foo=bar&x=y#hashme
I used parts of The Awesome One's solution, and a solution found on this question:
Adding a parameter to the URL with JavaScript
Combining them into this script:
function addParameter(url, parameterName, parameterValue, atStart/*Add param before others*/){
replaceDuplicates = true;
if(url.indexOf('#') > 0){
var cl = url.indexOf('#');
urlhash = url.substring(url.indexOf('#'),url.length);
} else {
urlhash = '';
cl = url.length;
}
sourceUrl = url.substring(0,cl);
var urlParts = sourceUrl.split("?");
var newQueryString = "";
if (urlParts.length > 1)
{
var parameters = urlParts[1].split("&");
for (var i=0; (i < parameters.length); i++)
{
var parameterParts = parameters[i].split("=");
if (!(replaceDuplicates && parameterParts[0] == parameterName))
{
if (newQueryString == "")
newQueryString = "?";
else
newQueryString += "&";
newQueryString += parameterParts[0] + "=" + (parameterParts[1]?parameterParts[1]:'');
}
}
}
if (newQueryString == "")
newQueryString = "?";
if(atStart){
newQueryString = '?'+ parameterName + "=" + parameterValue + (newQueryString.length>1?'&'+newQueryString.substring(1):'');
} else {
if (newQueryString !== "" && newQueryString != '?')
newQueryString += "&";
newQueryString += parameterName + "=" + (parameterValue?parameterValue:'');
}
return urlParts[0] + newQueryString + urlhash;
};
Example: addParameter('http://www.example.com?foo=bar#hashme', 'bla', 'valuebla', false)
Results in http://www.example.com?foo=bar&bla=valuebla#hashme
This can be another good solution, this version is even able to replace the parameter if it already exists, add parameter without value:
function addParam(url, param, value) {
var a = document.createElement('a'), regex = /(?:\?|&|&)+([^=]+)(?:=([^&]*))*/g;
var match, str = []; a.href = url; param = encodeURIComponent(param);
while (match = regex.exec(a.search))
if (param != match[1]) str.push(match[1]+(match[2]?"="+match[2]:""));
str.push(param+(value?"="+ encodeURIComponent(value):""));
a.search = str.join("&");
return a.href;
}
url = "http://www.example.com#hashme";
newurl = addParam(url, "ciao", "1");
alert(newurl);
http://jsfiddle.net/bknE4/81/
Try this:
location.href = location.href.replace(location.hash, '') + '&x=y' + location.hash
Update
What about this:
var a = document.createElement('a');
a.href = "http://www.example.com?foo=bar#hashme";
var url = a.href.replace(a.hash, '') + '&x=y' + a.hash;
I found out that the location object can be created by an anchor element(from Creating a new Location object in javascript).
You can use this JS lib called URI.JS
// mutating URLs
URI("http://example.org/foo.html?hello=world")
.username("rodneyrehm")
// -> http://rodneyrehm#example.org/foo.html?hello=world
.username("")
// -> http://example.org/foo.html?hello=world
.directory("bar")
// -> http://example.org/bar/foo.html?hello=world
.suffix("xml")
// -> http://example.org/bar/foo.xml?hello=world
.hash("hackernews")
// -> http://example.org/bar/foo.xml?hello=world#hackernews
.fragment("")
// -> http://example.org/bar/foo.xml?hello=world
.search("") // alias of .query()
// -> http://example.org/bar/foo.xml
.tld("com")
// -> http://example.com/bar/foo.xml
.search({ foo: "bar", hello: ["world", "mars"] });
// -> http://example.com/bar/foo.xml?foo=bar&hello=world&hello=mars
or
URI("?hello=world")
.addSearch("hello", "mars")
// -> ?hello=world&hello=mars
.addSearch({ foo: ["bar", "baz"] })
// -> ?hello=world&hello=mars&foo=bar&foo=baz
.removeSearch("hello", "mars")
// -> ?hello=world&foo=bar&foo=baz
.removeSearch("foo")
// -> ?hello=world
Easy.
<script>
function addPar(URL,param,value){
var url = URL;
var hash = url.indexOf('#');
if(hash==-1)hash=url.length;
var partOne = url.substring(0,hash);
var partTwo = url.substring(hash,url.length);
var newURL = partOne+'&'+param+'='+value+partTwo
return newURL;
}
document.write(addPar('http://www.example.com?foo=bar','x','y')) // returns what you asked for
</script>
The code could be modified a bit, and made a little more efficient, but this should work fine.
#Sangol's solution's better. Didn't know a location.hash property existed.
#freedev answer is great, but if you need something very simple (to insert key=value pair to the url and assume that key doesn't already exist), there's a much faster way to do it:
var addSearchParam = function(url,keyEqualsValue) {
var parts=url.split('#');
parts[0]=parts[0]+(( parts[0].indexOf('?') !== -1) ? '&' : '?')+keyEqualsValue;
return parts.join('#');
}
Example usage: addSearchParam('http://localhost?a=1#hash','b=5');
Here is an improved version of the answer by #skerit. This one supports # in URL path.
function addParameter(url, parameterName, parameterValue, atStart/*Add param before others*/) {
var replaceDuplicates = true;
var cl, urlhash;
parameterName = encodeURIComponent(parameterName);
parameterValue = encodeURIComponent(parameterValue);
if (url.lastIndexOf('#') > 0) {
cl = url.lastIndexOf('#');
urlhash = url.substring(cl, url.length);
} else {
urlhash = '';
cl = url.length;
}
var sourceUrl = url.substring(0, cl);
var urlParts = sourceUrl.split("?");
var newQueryString = "";
if (urlParts.length > 1) {
var parameters = urlParts[1].split("&");
for (var i=0; (i < parameters.length); i++) {
var parameterParts = parameters[i].split("=");
if (!(replaceDuplicates && parameterParts[0] === parameterName)) {
if (newQueryString === "") {
newQueryString = "?";
} else {
newQueryString += "&";
}
newQueryString += parameterParts[0] + "=" + (parameterParts[1]?parameterParts[1]:'');
}
}
}
if (newQueryString === "") {
newQueryString = "?";
}
if (atStart) {
newQueryString = '?'+ parameterName + "=" + parameterValue + (newQueryString.length>1?'&'+newQueryString.substring(1):'');
} else {
if (newQueryString !== "" && newQueryString != '?') {
newQueryString += "&";
}
newQueryString += parameterName + "=" + (parameterValue?parameterValue:'');
}
return urlParts[0] + newQueryString + urlhash;
}
Examples:
addParameter('http://www.example.com?foo=bar#hashme', 'bla', 'valuebla', false);
// Returns: http://www.example.com?foo=bar&bla=valuebla#hashme
addParameter('http://www.example.com/#iAmNotUrlHash/?foo=bar#hashme', 'bla', 'valuebla', false);
// Returns: http://www.example.com/#iAmNotUrlHash/?foo=bar&bla=valuebla#hashme
Something like this ?
var param = "x=y";
var split = url.split('#');
url = split[0] + '&' + param + "#" + split[1];
I always use this code, and its working fine ...
var currenturl=location.href;
var url = location.href+"?ts="+true;
window.location.replace(url,"_self");
if you are trying to add to the url parameter by html anchor tag, and, you have something like this just like I do:
<div class="wrapper-option">
JS
CSS
popular
newest
</div>
you can do something like:
// anchor setup
const anchors = this.document.querySelectorAll('.wrapper-option a');
anchors.forEach(a=>{
a.onclick = e => {
e.preventDefault();
if(a.href){
let uri = new URL(a.href);
let url = new URL(window.location.href);
for(const [k, v] of uri.searchParams){
url.searchParams.set(k, v);
}
window.location.href = url.href;
}
}
});
this will add param to url if it does exist, rewrite if exist. and will not allow duplicate and list.