I am using jQuery Serialize to serialize my form elements and would like to deserialize them back. Unfortunately can't find any working jQuery deserializer, any suggestions?
I wrote a version of jQuery.deserialize that supports serialized data generated from the serialize, serializeArray and serializeObject functions. It also supports all form element types, including checkboxes and radio buttons.
Try this:
function deparam(query) {
var pairs, i, keyValuePair, key, value, map = {};
// remove leading question mark if its there
if (query.slice(0, 1) === '?') {
query = query.slice(1);
}
if (query !== '') {
pairs = query.split('&');
for (i = 0; i < pairs.length; i += 1) {
keyValuePair = pairs[i].split('=');
key = decodeURIComponent(keyValuePair[0]);
value = (keyValuePair.length > 1) ? decodeURIComponent(keyValuePair[1]) : undefined;
map[key] = value;
}
}
return map;
}
I was very interested in trying JQuery.deserialize, but it didn't seem to handle checkboxes at all, so it didn't serve my purposes. So I wrote my own. It turned out to be easier than I thought, because the jQuery val() function does most of the work:
jQuery.fn.deserialize = function (data) {
var f = this,
map = {},
find = function (selector) { return f.is("form") ? f.find(selector) : f.filter(selector); };
//Get map of values
jQuery.each(data.split("&"), function () {
var nv = this.split("="),
n = decodeURIComponent(nv[0]),
v = nv.length > 1 ? decodeURIComponent(nv[1]) : null;
if (!(n in map)) {
map[n] = [];
}
map[n].push(v);
})
//Set values for all form elements in the data
jQuery.each(map, function (n, v) {
find("[name='" + n + "']").val(v);
})
//Clear all form elements not in form data
find("input:text,select,textarea").each(function () {
if (!(jQuery(this).attr("name") in map)) {
jQuery(this).val("");
}
})
find("input:checkbox:checked,input:radio:checked").each(function () {
if (!(jQuery(this).attr("name") in map)) {
this.checked = false;
}
})
return this;
};
You should be able to use this like this:
$("#myform").deserialize(data);
Where data is a parameter list such as what $("#myform").serialize() would produce.
It affects all fields in the form, and it will clear the values of fields that are not contained in the data. But you can also pass any selector to affect only specific fields, as you can with the serialize function. E.g.:
$("select").deserialize(data);
Half of jQuery Serialize is param(), so half of something that deserializes a query string is going to be a deparam. Unfortunately I haven't been able to find a good standalone deparam. For now I recommend getting the jQuery BBQ library and using that. If you don't need the other stuff you can remove them. I read somewhere that Ben Alman (cowboy) planned to extract deparam into its own module.
For the rest of deserializing, you'll just need to loop through the object that deparam returns and for each key and value pair in the object, select the form element based on the key, and set the form elements value to the value.
Bit late on this one, but somebody might find this useful.
function fetchInput(identifier) {
var form_data = identifier.serialize().split('&');
var input = {};
$.each(form_data, function(key, value) {
var data = value.split('=');
input[data[0]] = decodeURIComponent(data[1]);
});
return input;
}
I'm not now answering your question but my guess is that you want to serialize it and send back to server and then use the serialized data which is why you have to deserialize it?
If that's the case you should consider using .serializeArray(). You can send it as POST data in ajax, and then access later as well because you will have object.
May be a bit late, but perhaps you are looking for something like JQuery.deserialize. Problems: no support for checkboxes or radio buttons.
Using Jack Allan's deparam function with jQuery, you can change this line:
map[key] = value;
to
$('input[name=' + key + ']').val(value);
Which will load the data back into your form fields.
this code returns an array when same key is spotted multiple times in the serialized string
chaine="single=Single1&multiple=Multiple&multiple=Multiple1&multiple=Multiple2&multiple=Multiple3&check=check2&radio=radio1"
function deserialize(txt){
myjson={}
tabparams=chaine.split('&')
var i=-1;
while (tabparams[++i]){
tabitems=tabparams[i].split('=')
if( myjson[decodeURIComponent(tabitems[0])] !== undefined ){
if( myjson[decodeURIComponent(tabitems[0])] instanceof Array ){
myjson[decodeURIComponent(tabitems[0])].push(decodeURIComponent(tabitems[1]))
}
else{
myjson[decodeURIComponent(tabitems[0])]= [myjson[decodeURIComponent(tabitems[0])],decodeURIComponent(tabitems[1])]
}
}
else{
myjson[decodeURIComponent(tabitems[0])]=decodeURIComponent(tabitems[1]);
}
}
return myjson;
}
Needed all in a single string, which can be stored in maybe COOKIE, and later read and fill the same form with input values.
Input elements seperator: ~ (use any seperator)
Input attributes seperator: | (use any seperator)
input type | input name | input value ~ input2 type | input2 name | input2 value
var formData = '';
$('#form_id').find('input, textarea, select').each(function(i, field) {
formData += field.type+'|'+field.name+'|'+field.value+'~';
});
Example:
hidden|vote_id|10~radio|option_id|~radio|option_id|427~radio|option_id|428~
If what you want is to remove the standard URL-encoded notation, you can use JavaScript's decodeURIComponent(), which will give you a regular string, just like this:
var decodedString = decodeURIComponent("Http%3A%2F%2FHello%3AWorld");
alert(decodedString);
In this case, decodedString will look like Http://Hello:World, here's a working fiddle.
Got all of this searching for this same issue, and found the answer here: How can I decode a URL with jQuery?
I know this is an old question, but doing some searches for jQuery deserialize got me here, so I might as well try to give a different approach on the issue for people with the same problem.
Related
I need to submit a form in a google script but get this error:
TypeError: Cannot call method "withItemResponse" of undefined
According to the link below, this is how it should be set up https://developers.google.com/apps-script/reference/forms/form#createResponse()
Code:
//Submit form
var formID = row[24];
var form = FormApp.openById(formID);
Logger.log(form.getId()); //returns correct ID
form.createResponse() ;
form.FormResponse.withItemResponse('Core Teachers', logSummary);
//form has only two questions, a short text and a paragraph text
form.FormResponse.submit();
form.createResponse() returns a FormResponse, which you need to assign to a variable.
also, withItemResponse() expects an object of type ItemResponse. I am not familiar with google forms, but maybe this gets you in the right direction:
var formID = row[24];
var form = FormApp.openById(formID);
var formResponse = form.createResponse();
// get items of form and loop through
var items = form.getItems();
for (index = 0; index < a.length; ++index) {
var item = items[index]
// Cast the generic item to the text-item class. You will likely have to adjust this part. You can find the item classes in the documentation. https://developers.google.com/apps-script/reference/forms/item-type.
if (item.getType() == 'TEXT') {
var textItem = item.asTextItem();
var itemresponse = textItem.createResponse('Core Teachers');
formResponse.withItemResponse(itemresponse);
}
}
formResponse.submit();
Generally, when the documentation of a method lists as parameter type something else than primitive types like String or Boolean you need to create or aquire an object of that type, like I did with createResponse. You need to familiarize yourself with these and other principles because the GoogleAppsScript documentation assumes knowledge of them.
Im using the following code,
jQuery.each(aDataSel, function(index, oData) {
oPushedObject = {};
aSelectedDataSet.push(fnCreateEnt(aProp, oData, oPushedObject));
});
This is aSelectedDataSet values
and this is the values of OData
What I need is that before I do the push is to fill the listTypeGroup & listTypeGroupDescription (with the red arrow ) with values that Are inside the oData -> ListTypeGroupAssigment -> result (listTypeGroup & listTypeGroupDescription) , The index is relevant since I want to add just the value of the index in each iteration (since this code is called inside outer loop and the index determine the current step of the loop) ,How it can be done nicely?
The result contain 100 entries (always) and the a selected data will have 100 entries at the end...
Update :)
Just to be clear In the pic I show the values which is hardcoded for this run but the values can be any values, we just need to find the match between the both objects values...
I mean to find a match between to_ListTypeGroupAssigment in both object (which in this case exist ) and if in oData there is result bigger then one entry start with the matching ...
UPDATE2 - when I try Dave code the following happen for each entry,
This happen in the Jquery.extend line...any idea how to overcome this?
The following hard-coded of Dave:-) work perfect but I need generic code which doesnt refer to specific field name
jQuery.each(aDataSet, function(index, oData) {
oPushedObject = {};
fnCreatePushedEntry(aProperties, oData, oPushedObject);
var result = oData.to_ListTypeGroupAssignment.results[index];
oPushedObject.to_ListTypeGroupAssignment = {
ListTypeGroup: result.ListTypeGroup,
ListTypeGroupDescription: result.ListTypeGroupDescription
};
aSelectedDataSet.push(oPushedObject);
});
Im stuck :(any idea how to proceed here ?what can be wrong with the extend ?
should I use something else ? Im new to jQuery...:)
I think that this happen(in Dave answer) because the oData[key] is contain the results and not the specified key (the keyValue = to_ListTypeGroupAssignment ) which is correct but we need the value inside the object result per index...
var needValuesForMatch = {
ListTypeGroup: 'undefined',
ListTypeGroupDescription: 'undefined',
}
//Just to show that oPushedObject can contain additional values just for simulation
var temp = {
test: 1
};
//------------------This object to_ListTypeGroupAssigment should be filled (in generic way :) ------
var oPushedObject = {
temp: temp,
to_ListTypeGroupAssignment: needValuesForMatch
};
oPushedObject is one instance in aSelectedDataSet
and after the matching I need to do the follwing:
aSelectedDataSet.push(oPushedObject);
Is this what you're after:
OPTION ONE - DEEP CLONE FROM oData TO aSelectedDataSet
aSelectedDataSet.forEach(function(currentObject,index){
for (var childObject in currentObject) {
if (! currentObject.hasOwnProperty(childObject))
continue;
var objectToClone = oData[childObject]['results'][index];
if(objectToClone)
$.extend(true,currentObject[childObject],objectToClone);
}
});
Here is your data in a fiddle with the function applied: https://jsfiddle.net/hyz0s5fe/
OPTION TWO - DEEP CLONE FROM oData ONLY WHERE PROPERTY EXISTS IN aSelectedDataSet
aSelectedDataSet.forEach(function(currentObject,index){
for (var childObject in currentObject) {
if (! currentObject.hasOwnProperty(childObject))
continue;
if(typeof currentObject[childObject] !== 'object')
continue;
for(var grandChildObject in currentObject[childObject]) {
var objectToClone = oData[childObject]['results'][index][grandChildObject];
if(typeof objectToClone === 'object') {
$.extend(true,currentObject[childObject][grandChildObject],objectToClone);
} else {
currentObject[childObject][grandChildObject] = objectToClone;
}
}
}
Fiddle for option 2: https://jsfiddle.net/4rh6tt25/
If I am understanding you correctly this should just be a small change:
jQuery.each(aDataSel, function(index, oData) {
oPushedObject = {};
fnCreateEnt(aProp, oData, oPushObj);
//get all the properties of oData and clone into matching properties of oPushObj
Object.getOwnPropertyNames(oData).forEach(function(key) {
if (oPushObj.hasOwnProperty(key)) {
//oPushObj has a matching property, start creating destination object
oPushObj[key] = {};
var source = oData[key];
var destination = oPushObj[key];
//can safely assume we are copying an object. iterate through source properties
Object.getOwnPropertyNames(source).forEach(function(sourceKey) {
var sourceItem = source[sourceKey];
//handle property differently for arrays
if (Array.isArray(sourceItem)) {
//just copy the array item from the appropriate index
destination[sourceKey] = sourceItem.slice(index, index + 1);
} else {
//use jQuery to make a full clone of sourceItem
destination[sourceKey] = $.extend(true, {}, sourceItem);
}
});
}
});
aSelectedDataSet.push(oPushedObject);
});
It is unclear what exactly your fnCreateEnt() function returns though. I am assuming it is the populated oPushObj but it's not entirely clear from your question.
I might have written a pretty confusing title but my question is rather simple.
I'm looking for an efficient way to remove an item from an array. But my array is full objects that has been stringified (I'm writing my app on Node.js and I'm using JSON.stringify method). So my array is like this;
"{\"userID\":\"15\",
\"possibleFollowers\":[
{\"followerID\":\"201\",\"friends\":716},
{\"followerID\":\"202\",\"friends\":11887},
{\"followerID\":\"203\",\"friends\":11887}],
\"name\":\"John\",
\"lon\":\"Doe\"}"
My question is on Javascript(or Node). If I wanted to remove the from possibleFollowers with "followerID: 202", how would I be able to do that efficiently?
var string = "…";
var obj = JSON.parse(string);
obj.possibleFollowers = obj.possibleFollowers.filter(function(fol) {
return fol.followerID != "202";
});
string = JSON.stringify(obj);
var data = "{\"userID\":\"15\",\"possibleFollowers\":[{\"followerID\":\"201\",\"friends\":716},{\"followerID\":\"202\",\"friends\":11887},{\"followerID\":\"203\",\"friends\":11887}],\"name\":\"John\",\"lon\":\"Doe\"}";
var dataObject = JSON.parse(data);
dataObject.possibleFollowers = dataObject.possibleFollowers.filter(function(follower) {
return !(follower.followerID == "202");
});
data = JSON.stringify(dataObject);
In javascript, the splice method is used to delete an array element by index.
see :
http://www.roseindia.net/java/javascript-array/javascript-array-remove-index.shtml
try just to delete it by using "delete"
for (var i in possibleFollowers) {
if (possibleFollowers[i]['followerId'] == '216') {
delete possibleFollowers[i];
}
}
this is my first post in stackoverflow.. I am trying to iterate over an object(my implementation is an associative array) which in turn has some properties. Now I wish to construct another array out of it in order to use it as a localsource in jquery autocomplete widget for seach operations. Now the problem is that i am using for in loop to that according to the documenations available... However the output is always one less than the original object. The itearation involving the last element is not performed at all. Below is the sample object that I am using as input.
SubTeachPair = object{"5CS1":{SubAbbrev:"CA-L",SubCode:"5CS1",SubName:"Computer Architecture",TeacherId:"1",TeacherName:"Ayush Pandey",label:"Computer Architecture",value:"5CS1"},"5CS2":{SubAbbrev:"CA-P",SubCode:"5CS2",SubName:"Computer Engg",TeacherId:"10",TeacherName:"MAyush Pandey",label:"Computer Engg",value:"5CS2"}}
It has this kind of elements and is dynamically generated so the property names are variable. The loop construct that I have written is
var SubSource = [];
console.log(SubTeachPair);
var count = 0;
for(sub in SubTeachPair){
console.log(count);
SubSource[count] = {};
SubSource[count]['label']=SubTeachPair[sub]['label'];
SubSource[count]['value']=SubTeachPair[sub]['value'];
count++;
}
However, the result for the given input is only:
object{{ label: "Computer Architecture", value: "5CS1"}}
Am I missing something here?
edit-- The function that produces the input object is as follows(It is triggered onclick by the next button).
$('#' + $(this).attr("id")).autocomplete({
source : 'search',
minLength : 1,
change : function(event, ui) {
if( typeof ui.item != 'undefined') {
SubTeachPair[$(this).attr("id")] = {};
// console.log(ui.item);
SubTeachPair[$(this).attr("id")]['value'] = $(this).attr("id");
SubTeachPair[$(this).attr("id")]['label'] = $('label[for="' + this.id + '"]').html();
SubTeachPair[$(this).attr("id")]['SubCode'] = $(this).attr("id");
SubTeachPair[$(this).attr("id")]['SubName'] =$('label[for="' + this.id + '"]').html();
SubTeachPair[$(this).attr("id")]['SubAbbrev'] =$('label[for="' + this.id + '"]').attr('id');
SubTeachPair[$(this).attr("id")]['TeacherId'] = ui.item.id;
SubTeachPair[$(this).attr("id")]['TeacherName'] = ui.item.value;
// console.log(SubTeachPair);
//window.SubTeachPair = SubTeachPair;
}
}
});
I think I have found the cause of the error -- the object that is the input is actually the out put of another form that uses jquery autocomplete . Now when I enter something in the input and then click on the suggestion, the suggestion is filled in the text input, however if i do not click outside the input text and directly click the button which triggers my script, I get that error. Otherwise its fine. Is there any way to avoid that?
In your code, the array SubSource and count are not defined, You have to declare:
var SubSource = [];
var count = 0`
before for(sub in SubTeachPair) {...}
See http://jsfiddle.net/abu5C/
Try this:
SubSource[count] = {};
for(sub in SubTeachPair) {
console.log(count);
SubSource[count]['label']=SubTeachPair[sub]['label'];
SubSource[count]['value']=SubTeachPair[sub]['value'];
count++;
}
I want to loop over the elements of an HTML form, and store the values of the <input> fields in an object. The following code doesn't work, though:
function config() {
$("#frmMain").children().map(function() {
var child = $("this");
if (child.is(":checkbox"))
this[child.attr("name")] = child.attr("checked");
if (child.is(":radio, checked"))
this[child.attr("name")] = child.val();
if (child.is(":text"))
this[child.attr("name")] = child.val();
return null;
});
Neither does the following (inspired by jobscry's answer):
function config() {
$("#frmMain").children().each(function() {
var child = $("this");
alert(child.length);
if (child.is(":checkbox")) {
this[child.attr("name")] = child.attr("checked");
}
if (child.is(":radio, checked"))
this[child.attr("name")] = child.val();
if (child.is(":text"))
this[child.attr("name")] = child.val();
});
}
The alert always shows that child.length == 0. Manually selecting the elements works:
>>> $("#frmMain").children()
Object length=42
>>> $("#frmMain").children().filter(":checkbox")
Object length=3
Any hints on how to do the loop correctly?
don't think you need quotations on this:
var child = $("this");
try:
var child = $(this);
jQuery has an excellent function for looping through a set of elements: .each()
$('#formId').children().each(
function(){
//access to form element via $(this)
}
);
Depending on what you need each child for (if you're looking to post it somewhere via AJAX) you can just do...
$("#formID").serialize()
It creates a string for you with all of the values automatically.
As for looping through objects, you can also do this.
$.each($("input, select, textarea"), function(i,v) {
var theTag = v.tagName;
var theElement = $(v);
var theValue = theElement.val();
});
I have used the following before:
var my_form = $('#form-id');
var data = {};
$('input:not([type=checkbox]), input[type=checkbox]:selected, select, textarea', my_form).each(
function() {
var name = $(this).attr('name');
var val = $(this).val();
if (!data.hasOwnProperty(name)) {
data[name] = new Array;
}
data[name].push(val);
}
);
This is just written from memory, so might contain mistakes, but this should make an object called data that contains the values for all your inputs.
Note that you have to deal with checkboxes in a special way, to avoid getting the values of unchecked checkboxes. The same is probably true of radio inputs.
Also note using arrays for storing the values, as for one input name, you might have values from several inputs (checkboxes in particular).
if you want to use the each function, it should look like this:
$('#formId').children().each(
function(){
//access to form element via $(this)
}
);
Just switch out the closing curly bracket for a close paren. Thanks for pointing it out, jobscry, you saved me some time.
for me all these didn't work. What worked for me was something really simple:
$("#formID input[type=text]").each(function() {
alert($(this).val());
});
This is the simplest way to loop through a form accessing only the form elements. Inside the each function you can check and build whatever you want. When building objects note that you will want to declare it outside of the each function.
EDIT
JSFIDDLE
The below will work
$('form[name=formName]').find('input, textarea, select').each(function() {
alert($(this).attr('name'));
});