overriding the jquery.param function - javascript

I have a problem with the jQuery.param function.
jQuery uses + instead of %20 to URL-encode spaces
var obje = {
'test': 'tester 2'
}
console.log($.param(obje));
returns "test=tester+2"
so I thought about overriding this core function:
(function($){
$.fn.param = function( a, traditional ) {
console.log('custom $.param');
var s = [],
add = function( key, value ) {
// If value is a function, invoke it and return its value
value = jQuery.isFunction( value ) ? value() : value;
s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
};
// Set traditional to true for jQuery <= 1.3.2 behavior.
if ( traditional === undefined ) {
traditional = jQuery.ajaxSettings.traditional;
}
// If an array was passed in, assume that it is an array of form elements.
if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
// Serialize the form elements
jQuery.each( a, function() {
add( this.name, this.value );
} );
} else {
// If traditional, encode the "old" way (the way 1.3.2 or older
// did it), otherwise encode params recursively.
for ( var prefix in a ) {
buildParams( prefix, a[ prefix ], traditional, add );
}
}
return s.join("&");
// Return the resulting serialization
//return s.join( "&" ).replace( r20, "+" );
};
})(jQuery);
var obje = {
'test': 'tester 2'
}
console.log($.param(obje));
This fails however.. The $.param isn't overridden.
Any idea what can be wrong?
Thanks!
Edit: my solution (because I'm a new user I appearently may not answer my own question in 8 hours (Why is that?))
With the solution of ThiefMaster I still had the problem that buildParams is undefined.
I solved this by calling the old function and then replacing the + back to %20
// modification of the jQuery.param function: spaces are encoded by jQuery.param with + instead of %20. replace these back to %20
(function($, oldFunction){
$.param = function( a, traditional ) {
var s = oldFunction.apply(oldFunction,[a,traditional]);
// Return the resulting serialization
return s.replace( '+', '%20' );
};
})(jQuery,jQuery.param);

You need to use $.param instead of $.fn.param (which would be a function to call on a jQuery object, e.g. $(...).param()).

Old post I know, but for the sake of recorded knowledge. To replace the '+' left behind when using $.param(), consider doing the following:
(Using the code you provided)
var obje = {
'test': 'tester 2'
}
console.log($.param(obje).replace(/\+/g, "%20"));
That will result in:
test = tester 2
Hope this helps someone.

The "re-replace" fix may also be implemented by using "beforeSend" in the ajax settings object:
{ beforeSend: function (request, settings) { settings.data = settings.data.replace(/\+/g, "%20"); } }
This approach is suitable for cases where you don't actually want to alter $.param()'s original behavior (for example, if you want "+" in URLs but "%20" for POST data).
[Edited because I remembered that string.replace() will only match once unless it's a regex object with the g flag.]

Related

How to get number of request query parameters in express.js?

At the moment I have to check every potentially existing parameter separately.
if (req.query.param1 != undefined ) {
}
if (req.query.param2 != undefined ) {
}
if (req.query.param3 != undefined ) {
}
...
To get all query parameter:
Object.keys(req.query)
To get number of all params:
Object.keys(req.query).length
Then you can iterate through all parameters:
for(p in req.query) {
//... do something
}
UPD:
surround your request with quotes to make right query
curl -X GET "localhost:9090/mypath?param1=123&param2=321"
without quotes the & in terminal makes the command run in the background.
If you hit /mypath?param1=5&param2=10, then the request.query will yield {param1: 5, param2:10}.
This means that the request.query is a JavaScript object with the key as the name of the param, and value as the value of the param. Now you can do anything with it as you want: Find the length or iterate over it as follows:
for (var key in request.query) {
if (request.query.hasOwnProperty(key)) {
alert(key + " -> " + request.query[key]);
}
}
Finding only the length might not work for you that well because you may have param1 and param3, with param2 missing. Iterating will be better IMO.
You want the number of non-undefined params right?
It is as simple as this;
var no = 0;
for (var key in req.query) {
if(req.query[key]) no++;
}

jQuery return multiple function

so, i have the following js:
function RHL(a,b,c)
{
return rx.removeClass(a).addClass(b);
return rhpfc.html(parseInt( rhpfc.html() ) -1 );
}
I am having a bit of difficult time with the formatting and syntax.
How do I combine both lines under one return. Also, I want to have two options: -1 or +1. So, I thought I would make - or + as c.
what kind of bracket do I need? (ie. 'c'1)
function RHL(a,b,c){
return [
rx.removeClass(a).addClass(b),
rhpfc.html(parseInt( rhpfc.html() ) -1 )
];
}
then you will need to use the index 0 or 1 to use the return value..
var rx = RHL(a,b,c)[0];
or
var rhpfc = RHL(a,b,c)[1];

Using element attr in Javascript function

In a page I call external js file and its includes a dictionary. I want to replace element text by their attiributes.
<p data-text="dict.dataP"></p>
<p data-text="dict.data.P2"></p>
I want to fill it with external file dict
var dict = {
"dataP1": "this is my p text",
"data" : {
"p2": "my another paragraph"
},
};
I tried to use as this
$.each(function () {
if ($(this).attr("data-text").length > 0) {
$(this).html(
$(this).attr('data-text') /*we got a problem here. it returns string*/ );
}
});
codePen here:
codepen.io
JSFiddle here
jsfiddle.net
How can I do this?
edited dict. we have dictionary in dictionary.
In order to access the data attribute, use:
$(this).data('text');
Text is the part after the hyphen within your attribute declaration.
There are a few things that you should change to get this working, taking Jimbo's answer and adding a few other things:
var dict = {
"dataP": "this is my p tag text"
};
$('[data-text]').each(function () {
if ( $(this).data("text") ) {
var dictAttr = $(this).data("text");
if ( dictAttr && dict[dictAttr] ) {
$(this).html( dict[dictAttr] );
}
}
});
You should also change your mark-up to make things easier (expecially if you are only dealing with one dict object):
<p data-text="dataP"></p>
With the above changes you should get things working as you expect.
http://jsfiddle.net/b2zgw/
string-based object navigation
Rather oddly I'm actually working on a framework for string-based object navigation as we speak. However the codebase if far too complicated to just tack on the end of a stackoverflow answer. As an addition to my comment I realised there is a third option which might be the best of both worlds (depending on what you need).
:: eval
I don't recommend this method, but it can't be argued with for simplicity — the following is a snippet from the code above and should replace that part:
var dictNav = $(this).data("text"); /// e.g. say dictNav == 'dict.dataP'
var ref; eval('ref='+dictNav);
if ( ref && red.substr ) {
$(this).html( ref );
}
The problem with the above is that eval will evaluate any JavaScript - so all an attacker would have to do is find a way to add a data-text attribute to something on your page and they would be able to execute any JavaScript they liked.
:: string-based navigation
The following is a simple function that could be improved, but should give you the idea:
function navigate( obj, path ){
var cur = obj, bits = path.split('.');
for ( var i=0, l=bits.length; i<l && cur; i++ ) {
cur = cur[bits[i]];
}
return cur;
}
Using the above you can navigate your dictionary structure - be aware because you start your 'navigation path' with a particular var name (i.e. dict) you'll have to place your dictionary one level down of the object you wish to traverse; this is the reason for {dict:dict}. To support multiple dictionaries you'd just need to extend that object like so {dict:dict,dict2:dict2} — again the following is a snippet and should replace the original code:
var dictNav = $(this).data("text"); /// e.g. say dictNav == 'dict.dataP.test'
var ref = navigate({dict:dict}, dictNav);
if ( ref && red.substr ) {
$(this).html( ref );
}
:: third option - simplify your dictionary
The third option is probably the most optimal, but means that the dictionary can't be modified in realtime (or at least not easily). Basically before you run the rest of your code, push your dictionary through a parsing function that modifies it's structure:
var dict = {
"dataP": "this is a test",
"forms": {
"inputLabel": "this is a second level"
}
};
function simplifyDict( obj, target, path, subpath ){
if ( !target ) { target = {}; }
if ( !path ) { path = ''; }
for( var i in obj ) {
subpath = (path ? path + '.' : '') + i;
if ( typeof obj[i] == 'object' ) {
simplifyDict( obj[i], target, subpath );
}
else {
target[subpath] = obj[i];
}
}
return target;
}
dict = simplifyDict( dict );
The above simplify function should return something like:
{
"dataP" : "this is a test",
"forms.inputLabel" : "this is a second level"
}
Then all you need to do is use my original code right at the top of this answer. Instead of converting your strings to separate object properties and navigating the dictionary, you've switched the dictionary to be a string-based lookup... so now you can just use strings directly i.e. dict['forms.inputLabel']
You'd like to set the text from the dictionary to the element with matching data attribute, right?
Try this:
var dict = {
"dataP": "this is my p tag text",
"dataDiv": "dummy div"
};
$('p').each(function () {
var data = $(this).data('text');
$(this).html(dict[data.split('.')[1]])
});
http://jsfiddle.net/eB6E2/1/

lack of identity between jQuery selector and jQuery variable?

I'm running into a maddening problem where I set a variable to point to a jQuery selector, such as: var foobar=jQuery(this); I then pass this variable to a function to be worked on. Let's simplify a little and say the function looks like this:
function SetFieldValue (selector) {
selector.val('test');
console.log ( selector );
console.log ( jQuery('#' + selector.attr('id')) );
}
In this situation if you assume that:
the selector is always a form element (and therefore val() is a valid operation)
the selector does resolve to a single dom element which has an 'id' attribute
You would then expect the two console.log statements to output the same result, right? Well I'm running into a situation where this condition only happens about 90% of the time.
In order to give more context I've created a short screencast demonstrating the problem:
SCREENCAST LINK
For reference purposes, here's the actual SetFieldValue code that is shown in the screencast:
function SetFieldValue ( domObject, value ) {
// as a safety function, check if a string representation of the domObject was passed in and convert it to a jQuery object if it was
if ( jQuery.type(domObject) === "string") {
console.log ("Value passed into SetFieldValue was a string representation so converting to jQuery object");
domObject = jQuery(domObject);
}
if ( jQuery.inArray (domObject.prop('tagName').toLowerCase(),['input' , 'select' , 'textarea']) >= 0 ) {
console.log ("setting to value attribute: " + value);
if ( domObject.hasAttr('id') ) {
domObject.val(value);
//jQuery('#' + domObject.attr('id')).val(value);
} else {
domObject.attr('value',value);
}
console.log ("Using jQuery ID it is set to: " + jQuery('#' + domObject.attr('id')).val() );
console.log ("Using jQuery selector variable it is set to: " + domObject.val() );
} else {
console.log ("setting to html attribute");
domObject.html( value );
}
return domObject;
}
Lets examine the code a bit.
First assigning back to a parameter is not a good practice adding a var at the start of your function would be a lot better, as scope can be lost.
//Suggestion change parameter to domItem
var domObject
Your missing an error handler for when the parameter is not String.
when identifying the type use
<VARNAME>.constructor.toString().match(/function (\w*)/)[1] === "<TYPE>"
It's more efficient and handles custom types.
No need for all the logic in assignment of value attribute. Any dom Object can be made to have a value attribute. also not sure why you are setting the val versus the value.
domObject.attr('value',value);
It is at this point that I can see your code could really use some documentation to help explain purpose
If you are explicitly only wanting to set value on Input fields and set value as innerhtml on non input fields then yes the logic would be needed but could be simplified to ... as the value doesn't need to be detected to overwritten.
if (jQuery.inArray (domObject.prop('tagName').toLowerCase(), ['input' , 'select' , 'textarea']) >= 0) {
domObject.attr('value',value);
} else {
domObject.html( value );
}
No Idea why you are returning the domObject out.
So a quick rewrite without the return and keeping most of the logic adding error handling results in
/*jslint sloppy: true*/
/*global jQuery*/
function SetFieldValue(domString, value) {
// as a safety function, check if a string representation of the domObjects was passed in and convert it to a jQuery object if it was
var domObjects, index;
//errorhandling
if (domString === undefined || domString === null) {
throw {error : "domString must have a value."};
}
if (domString.constructor.toString().match(/function (\w*)/)[1] !== "string") {
if (domString.constructor.toString().match(/function (\w*)/)[1].match(/HTML[a-zA-Z]*Element/) === null) {
throw {error : "domString expected to be String or domObjects"};
}
} else {
if (jQuery(domString).length === 0) {
throw {error : "domString does not resolve to a detectable domObjects."};
}
}
//errorhandling
//action
if (domString.constructor.toString().match(/function (\w*)/)[1].match(/HTML[a-zA-Z]*Element/)) {
//made as an array to normalize as jQuery returns an array allows code to be simplified
domObjects = [domString];
} else {
domObjects = jQuery(domString);
}
//given that domObjects are an array need to step through the array
for (index = domObjects.length - 1; index >= 0; index -= 1) {
if (
jQuery.inArray(
domObjects[index].tagName.toLowerCase(),
['input', 'select', 'textarea']
) >= 0
) {
if (domObjects[index].hasAttr('id')) {
domObjects[index].val(value);
} else {
domObjects[index].attr('value', value);
}
} else {
domObjects[index].html(value);
}
}
}
The above passes JSLint
I know I didn't provide enough context for people to really dig into this problem but I have in the end solved it. What was the issue? Well it was #Kobi who first asked is the DOM element's ID unique ... to which I happily reported it was. And it had been but in fact that WAS the problem. Jesus. It's always the obvious things that you then go onto overlook that get you in trouble.
Anyway, thanks for your patience and help.

how to check an array.. within an array? jquery

I'd like to know how to check an array that got several variables in it.. something like that.
I can explain better with the code shown:
// Ignore the words in here, they are just there to explan.
var $array = [
alpha = {
name : $('.a'),
date : $('.b'),
street: $('.c')
},
beta = {
name : $('.x'),
date : $('.y'),
street: $('.z')
}
];
/* So now I got this arrays.. withing an array? is that correct?
* or what is this called?
* and now I want to check each object's length, if its 0 -> return false and
* throw out an error, if >= 1 go on and check the next. */
// Check if all needed elements for the toggle to work are existent
$.each( $array, function(key, value) {
if ( !value.length ) {
alert("Could not find "+ '"' + value.selector +'"!')
return false
};
});
// Well obviously this doesnt work..
Thanks in advance!
You can loop over the names of properties of an object with a for (... in ...) loop:
/* since the array isn't a jQuery object, don't prefix the name with `$` */
var things = [
/* array elements have integer, not string, indices. In any case,
"alpha = ..." is the wrong syntax to set properties. What it
does is set a variable named "alpha".
*/
{...},
{...},
];
$.each(things, function(idx, item) {
for (p in item) {
if (! item[p].length) {
/* alerts are disruptive; use other means of informing
the user or developer.
*/
//alert("Could not find "+ '"' + value.selector +'"!')
return false;
} /* blocks don't need semicolon separators */
}
});
See also "For .. in loop?"

Categories

Resources