Hi, all!

Here's another one that's starting to boggle my mind.

I have a form that, with a button, adds a bunch of text-fields in a tablerow.
For every press of the button another row is added. This works in both IE and FF. No probs.

When pressing another button, Register, the information in the form is to be stored in a db.
In the javascript funktion assigned to this button I have a loop that goes through the dynamically created rows of text-fields, and stores the values in variables.
These vars is then passed to an ajax-function.

I have tried with calling the function once in every iteration of the loop. But if you have a bunch or rows, 9 or more, only a few rows of information is stored, 3 or less. Like this:

for (i = 0; i < nrapps; i++) {			
   var appnr = document.Form1.elements['txtAppNr' + id].value;
   var floor = document.Form1.elements['txtFloor' + id].value;
   var unitplac = document.Form1.elements['txtUnitPlac' + id].value;
   var consid = document.Form1.elements['txtConsID' + id].value;
   var unitnr = document.Form1.elements['txtUnitNr' + id].value;
   var unitset = document.Form1.elements['txtUnitSet' + id].value;
   var fuse = document.Form1.elements['txtFuse' + id].value;
   var customer = document.Form1.elements['txtCustomer' + id].value;
   var dob = document.Form1.elements['txtDOB' + id].value;
   <ajaxcode>.CB_Function(regid,appnr,floor,unitplac,consid,unitnr,unitset,fuse,customer,dob,ServerSide_Callback2);
   if (On_Error == true) { return; }
   id++;
}

So my thought was to store the information in a 2D-array and then pass that array to the ajax-function in order to let that function in turn store the information to the db in it's own loop.

for (i = 0; i < arrSize ; i++) {			
   arrApps[i][0] = document.Form1.elements['txtAppNr' + id].value;
   arrApps[i][1] = document.Form1.elements['txtFloor' + id].value;
   arrApps[i][2] = document.Form1.elements['txtUnitPlac' + id].value;
   arrApps[i][3] = document.Form1.elements['txtConsID' + id].value;
   arrApps[i][4] = document.Form1.elements['txtUnitNr' + id].value;
   arrApps[i][5] = document.Form1.elements['txtUnitSet' + id].value;
   arrApps[i][6] = document.Form1.elements['txtFuse' + id].value;
   arrApps[i][7] = document.Form1.elements['txtCustomer' + id].value;
   arrApps[i][8] = document.Form1.elements['txtDOB' + id].value;
   if (On_Error == true) { return; }
   id++;
}
<ajaxcode>.CB_Function(arrApps,nrapps,ServerSide_Callback2);

I've read that you can pass an array in the form of an object. But how do I turn this 2D-array into an object that can be passed? (I'm using AjaxPro by Michael Schwarz)

Look into JSON for shipping data back and forth between your server and Javascript. It has become a de-facto standard like XML for shipping data in a platform / language agnostic manner.

JSON look promising. I like the fact that it can contain an array.
But how to create a dynamic JSON object containing multiples.

My guess would be that the object needs to have the form:

var myJSONObject = {"bindings1": [
        {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"},
        {"ircEvent": "PRIVMSG", "method": "deleteURI", "regex": "^delete.*"},
        {"ircEvent": "PRIVMSG", "method": "randomURI", "regex": "^random.*"}
    ],"bindings2": [
        {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"},
        {"ircEvent": "PRIVMSG", "method": "deleteURI", "regex": "^delete.*"},
        {"ircEvent": "PRIVMSG", "method": "randomURI", "regex": "^random.*"}
    ], <and so on>
};

Am I right?
And how would I go about to access these values from codebehind? (ASP.NET)

> Am I right?
Yes, you can have nesting of arbitrary depths as long as it follows the key-value pair format where key is always a string and value can be either a string, number, array, another object, true, false or null.

> And how would I go about to access these values from codebehind? (ASP.NET)
Take a look at the .NET binding for JSON.

Everything about JSON looks interesting and workable.
But I'm new to JSON and used to passing information between functions using arguments. So, I'm gonna need a little hand-holding and guidance here. :)

On server-side i'm using AjaxPro by Michael Schwartz, which has built-in features for parsing JSON. And on client-side i've just added the json.js script found on json.org.

This is what I would like to do:
Build a JSON object on client-side filled with information from a dynamically created form (already working) that is then passed to server-side.
All examples i've read so far has been about creating the object/string on server-side and passing it to client-side.

The number of "sections" in the object is dependent on the number of dynamically created "form-rows", but each section will contain an array with a fixed size of 9 key/value pairs. As indicated on my first post.

Could you help me with a code-snippet on how to create that object in this manner?

Here is a crude snippet:

<html>
<head>
	<title>Forms</title>

	<script type="text/javascript">
	function objectify() {
		var o = {};
		var frms = document.forms;

		/* loop through all the form objects */
		for(var i = 0, maxI = frms.length; i < maxI; ++i) {
			var frm = frms[i];
			var elms = frm.elements;
			var tmp = {};
			/* loop through all the form elements of each form */
			for(var j = 0, maxJ = elms.length; j < maxJ; ++j) {
				var el = elms[j];
				switch(el.type) {
					case "textarea":
					case "text":
						tmp[el.name] = el.value;
						break;
					default:
						/* add custom behavior for other form elements */
						break;
				}
			}
			o[frm.name] = tmp;
		}
		return(o);
	}
	</script>
</head>
<body id="bdy">
	<form name="frmOne" action="#">
		<input name = "txtOne" value = "Text box one" />
		<input name = "txtTwo" value = "Text box two" />
		<input name = "txtThree" value = "Text box three" />
	</form>

	<form name="frmTwo" action="#">
		<input name = "txtOne" value = "Text box one" />
		<input name = "txtTwo" value = "Text box two" />
		<input name = "txtThree" value = "Text box three" />
	</form>

	<form name="frmThree" action="#">
		<input name = "txtOne" value = "Text box one" />
		<input name = "txtTwo" value = "Text box two" />
		<input name = "txtThree" value = "Text box three" />
	</form>
</body>
</html>

Just pass the object returned by objectify function to a function which returns the json string representation of a javascript object.

Ok. So i managed to use the code snippet you gave me which resulted in a javascript object. It gave me a happy.

This is what i came up with:

function somename() {
                var o = objectify();
                var jsonString = JSON.stringify(o); // This line gets halted and displays a 'Undefined' error
                <ajaxcode>.CB_Function(jsonString,ServerSide_Callback2);
}

function objectify() {
	var o = {};
	var frms = document.forms;
	var formID = 1;
	var id = 1;
 
for (i = 0, maxI = frms.length; i < maxI ; i++) {
	if (frms[i].name == 'form' + formID) {
		var frm = frms[i];
		var elms = frm.elements;
		var tmp = {};
      
		for (var j = 0, maxJ = elms.length; j < maxJ; j++) {
			var el = elms[j];
			tmp[el.name] = el.value;
		}
		o[frm.name] = tmp;
		formID++;
	}
}
return (o);
}

I'm now trying to use the json script from json.org in order to create a json string.
The script has the function stringify that's supposed to return a json string from a javascript object.
But everytime I get to that line all I get is undefined and my script just dies.

See anything wrong?

Did you include the 'json2.js' script at the top of your page? It must be the only reason or it has got something to do with your HTML file since stringify() works for me.

<html>
<head>
<title>Forms</title>
<script type="text/javascript" src="json2.js"></script>
<script type="text/javascript">
function somename() {
    var o = objectify();
    var jsonString = JSON.stringify(o);
    alert(jsonString);
}

function objectify() {
    var o = {};
    var frms = document.forms;
    var formID = 1;
    var id = 1;
    
    for (i = 0, maxI = frms.length; i < maxI ; i++) {
        if (frms[i].name == 'form' + formID) {
            var frm = frms[i];
            var elms = frm.elements;
            var tmp = {};
            
            for (var j = 0, maxJ = elms.length; j < maxJ; j++) {
                var el = elms[j];
                tmp[el.name] = el.value;
            }
            o[frm.name] = tmp;
            formID++;
        }
    }
    return (o);
}
</script>
</head>
<body id="bdy">
    <form name="form1" action="#">
    <input name = "txtOne" value = "Text box one" />
    <input name = "txtTwo" value = "Text box two" />
    <input name = "txtThree" value = "Text box three" />
    </form>

    <form name="form2" action="#">
    <input name = "txtOne" value = "Text box one" />
    <input name = "txtTwo" value = "Text box two" />
    <input name = "txtThree" value = "Text box three" />
    </form>

    <form name="form3" action="#">
    <input name = "txtOne" value = "Text box one" />
    <input name = "txtTwo" value = "Text box two" />
    <input name = "txtThree" value = "Text box three" />
    </form>
<script>somename();</script>
</body>
</html>

Yes, actually I did. But I'll have to look it over again.

The weird part is that when I debug using Firebug you can choose what js-script to debug and step through and I can clearly see the file and path. But in Firebug, the code of 'json2.js' doesn't contain any javascript code.

There is either a problem with your markup or the way you are using / including Javascript. Did you try the snippet pasted by me in the above post? Did it work for you?

I'm sorry. I haven't had the chance to try anything today.
But as soon as I do, I'll post my findings.

Ok. Now I'm back from the holidays and could check my code. I found that I missed a quote-mark. Now there are no errors, but there still seem to be something odd happening.

In the screenshot, in the attached image, you can see two dynamically created forms marked form1 and form2.
After the calls to the functions objectify and JSON.stringify the alert show the information marked in a green rectangle.
That's not right considering that each form has a number of fields and should be created as an "array".

This is my complete javascript code for adding forms, objectify and such.

<script type="text/javascript" src="js/json2.js"></script>
<script type="text/javascript">
var appInc = 0;
var rowInc = 0;
var On_Error = false;
								    
function addRow(r){ 
var root = r.parentNode;//the root 
var allRows = root.getElementsByTagName('tr');//the rows' collection 
var cRow = allRows[0].cloneNode(true)//the clone of the 1st row 
var cInp = cRow.getElementsByTagName('asp:TextBox');//the inputs' collection of the 1st row 
for(var i=0;i<cInp.length;i++) {//changes the inputs' names (indexes the names) 
cInp[i].setAttribute('name',cInp[i].getAttribute('name')+'_'+(allRows.length+1)) 
} 
root.appendChild(cRow);//appends the cloned row as a new row 
}
			
function addAppartement() {
appInc++;
var appTable = document.getElementById("appTable");
var a = document.createElement('div');
a.setAttribute("id", "a" + appInc);
appTable.appendChild(a);

var html = '<form name="form' + appInc + '" action="#">\n';
html += '<table>\n';
html += '<tr>\n';
html += '<td class="td" vAlign="top" align="center" width="60"><input id="txtAppNr' + appInc + '" style="width: 44px" type="text"></td>\n';
html += '<td class="td" vAlign="top" align="center" width="50"><input id="txtFloor' + appInc + '" style="width: 44px" type="text"></td>\n';
html += '<td class="td" vAlign="top" align="center" width="50"><input id="txtUnitPlac' + appInc + '" style="width: 43px" type="text"></td>\n';
html += '<td class="td" vAlign="top" align="center" width="115"><input id="txtConsID' + appInc + '" style="width: 104px" type="text"></td>\n';
html += '<td class="td" vAlign="top" align="center" width="90"><input id="txtUnitNr' + appInc + '" style="width: 74px" type="text"></td>\n';
html += '<td class="td" vAlign="top" align="center" width="90"><input id="txtUnitSet' + appInc + '" style="width: 74px" type="text"></td>\n';
html += '<td class="td" vAlign="top" align="center" width="50"><input id="txtFuse' + appInc + '" style="width: 44px" type="text"></td>\n';
html += '<td class="td" vAlign="top" align="center" width="135"><input id="txtCustomer' + appInc + '" style="width: 120px" type="text"></td>\n';
html += '<td class="td" vAlign="top" align="center" width="135"><input id="txtDOB' + appInc + '" style="width: 120px" type="text"></td>\n';
html += '<td class="td" vAlign="top" align="center" width="20">&nbsp;</td>\n';
html += '</tr>\n';
html += '</table>\n';
html += '</form>';
a.innerHTML = html;
document.forms[0].txtNrFlats.value = appInc;
}
			
function removeAppartement(appID) {
appInc--;
var d = document.getElementById('appTable');
var olddiv = document.getElementById('a' + appID);
d.removeChild(olddiv);
document.forms[0].txtNrFlats.value = appInc;
}
			
function SendForm() {
var regid = document.getElementById("txtRegistrationID").value;
var unitplace;
for (i = 0; i < document.forms[0].rdbUnitPlace.length; i++) {
if (document.forms[0].rdbUnitPlace[i].checked) {
unitplace = document.forms[0].rdbUnitPlace[i].value;
}
}
var nrapps = document.getElementById("txtNrFlats").value;

var city = document.getElementById("txtCity").value;
var date = document.getElementById("txtDate").value;
var installer = document.getElementById("txtInstaller").value;
				
if (nrapps == '' || nrapps == '0') {
document.getElementById('response').innerHTML = 'Du måste ange minst en lägenhet för att registreringen ska genomföras';
return;
}

<hidden>.multihousereg.DoStoringEvent(regid,unitplace,nrapps,city,date,installer,ServerSide_Callback);

if (On_Error == true) { return; }

var i = 0;
var arrSize = Number(nrapps);
var arrApps = new Array(arrSize );
for (i = 0; i < arrSize; i++) {
arrApps[i] = new Array(9);
}

var o = objectify();
var jsonString = JSON.stringify(o);
alert(jsonString);
//<hidden>.multihousereg.PopulateAppartements2(jsonString,ServerSide_Callback2);
//window.location = "https://www.a_web_server.se/<folder>/regThanks.aspx?op=multiReg";
}
			
function objectify() {
var o = {};
var frms = document.forms;
var formID = 1;
var id = 1;

for (i = 0, maxI = frms.length; i < maxI ; i++) {
if (frms[i].name == 'form' + formID) {
var frm = frms[i];
var elms = frm.elements;
var tmp = {};
						
for (var j = 0, maxJ = elms.length; j < maxJ; j++) {
var el = elms[j];
tmp[el.name] = el.value;
}
o[frm.name] = tmp;
formID++;
}
}
return (o);
}
			
function ServerSide_Callback(response) {
if (response.error != null) {
document.getElementById('response').innerHTML += response.error.value + '<br>';
On_Error = true;
return;
}
}

function ServerSide_Callback2(response) {
if (response.error != null) {
document.getElementById('response').innerHTML += response.error + '<br>';
On_Error = true;
return;
}
}
</script>

Do you see anything that I don't? (Please disregard the fact that I mix British and American english in my code) :)

Paste only the relevant and indented code. Sifting through 50+ lines of unindented code is more of a bother.

As far as your problem is concerned, I don't see any name attribute assigned to your form elements and the algorithm I posted uses element names.

Sorry about that. Won't happen again.

I'll try your solution by adding the name element.
But I was just thinking. If that's the reason why it won't work, then why does the code capture and hold the string in the last form element of each row and not the others?

Ok. So it works. I now get a correct json string.
Now I'll have to figure out how to Deserialize(?) it in server code-behind into a a use-able .NET object/class/structure.
Any suggestions?

Use any C# JSON binding library which converts from JSON objects to C# objects and vice versa. The bottom section of the JSON home page has a lot of bindings for the C# language. LitJSON is one of those libraries you can use.

I tried LitJSON only to find out that it's probably compiled using .NET 2.0. I'm working in 1.1.
In my latest attempt I used Jayrock.
And i've also been ripping my hair out trying to get the method JavaScriptDeserializerFromJson in AjaxPro to do my bidding.
No suck luck.

I'm trying to convert the json string into a .NET object in the form of a custom class.

The incoming Json string can contain an array, or not.
But either way I always get an exception thrown in my face.
With Jayrock the error is: "Cannot import System.<whatever> from a JSON Object value".
With AjaxPro there's not always an error but the object is not filled. However, when there is an error it's usually something along the lines of "invalid cast".

Here's two of my attempts:

Dim app As Appartements
'Dim app As String

Try
app = AjaxPro.JavaScriptDeserializer.DeserializeFromJson(jsonString, _
GetType(Appartements)) '//AjaxPro
'app = JsonConvert.Import(GetType(String), jsonString) '//Jayrock
...............

<Serializable()> _
Public Class Appartements
Public strAppNr As String = ""
Public strAppFloor As String = ""
Public strUnitPlace As String = ""
Public strConsID As String = ""
Public strUnitNr As String = ""
Public strUnitSet As String = ""
Public strFuse As String = ""
Public strCustomer As String = ""
Public strDOB As String = ""
End Class

Am I doing something wrong or am i totally incompetent? :)

> Am I doing something wrong or am i totally incompetent?
You are probably asking this question in the wrong forum. This question has no longer remained a Javascript one since you have been successfully able to send the JSON encoded string to the server.

The way you decode the string on the server is purely dependent on your server side language of choice. Try asking this question in the C# or VB .NET forums of Daniweb.

Perhaps that is the case.
But on the other hand. The fact that this forum also is about Ajax may be of relevance since that, for me, includes both client-side and server-side coding.

Problem solved.
Instead of using a JSON string I used a DataTable.
Appearantly AjaxPro supports using .NET objects as arguments and converts them into appropriate javascript objects.

Thank you very much for all your assistance.
Couldn't have done it without you.

Thank you, thank you, thank you!!!

This question has already been answered. Start a new discussion instead.