On May 24, 2012, at 12:17 AM, Richard Frovarp wrote: > I'm trying to figure out if there is a way to create a variable number of > text fields in a form that are backed by normal strings. I've seen the > AJAXFormLoop stuff, and it's close to what I think I'm after, but not quite > there. The appears to require a mutable object returned fron onAddRow(). I > just really want straight Strings. Is there an easy way to use Javascript to > add a variable number of fields that doesn't require wrapping a String in > some sort of mutable object, and that doesn't require a lot of manipulation > of the form models? > > Thanks, > Richard
You can use a List<String> in your class and use a t:loop to create an arbitrary number of strings. That assumes you know the number at server render time or can refresh via AJAX to re-generate the form. The value could be a simple accessor (getString / setString) that uses the index from the t:loop to know where to put it. You can use ajax and form fragments, I'd imagine, to add more at runtime. If you don't care about validation you can use normal <input type="text">f fields and then have an on submit callback marshal them as JSON and store in a hidden Tapestry field. Then decode on the server side. Using Prototype or jQuery, you can tag all these string fields with a CSS class and do something like $$('input.varStrings'), add those to an object with the ID as the key name and then Object.toJSON() that. That's pretty easy, likely a single line of Javascript. Use scriptaculous' builder to create more fields. I've done the first and last options a few times, and they seem to work well. If you want validation, I'd go with the loop and AJAX. The one trick is if you want to preserve your values when you request an updated form with more values. I use prototype's "serialize" on the form and then use this (http://madchicken.altervista.org/js/deserialize.js) to deserialze when the AJAX completes. The only trick I've found is that you have to ignore any fields whose name starts with "t:" or your submission won't work, e.g. modify the deserial library: Object.extend(Form.Element, { deserialize: function(form, element, data) { if (element.indexOf("t:") == 0) return; // NWF - Tapestry Fix var elements = Form.getElements(form); for (var index = 0, len = elements.length; index < len; ++index) { var item = elements[index]; if(item.name == element) { var method = item.tagName.toLowerCase(); Form.Element.Deserializers[method](item, data); break; } } } }); Here is how I do the form save / restore: var concernFormSave = null; // Can't use the callback because the DOM hasn't been updated yet, so activate and deserialize don't work. function onZoneUpdate(e) { if (! concernFormSave) return; setupSelects(); Form.deserializeJSON($$('form')[0], concernFormSave, false); concernFormSave = null; } function saveFormFields(el) { concernFormSave = Form.serialize($$('form')[0], true); // To work around Tapestry ID mangling. // We need it as a JSON string, not an object. We've also modified deserialize.js to ignore all t: elements, which seriously confuses Tapestry. concernFormSave = Object.toJSON(concernFormSave); return null; } Norman Franke Answering Service for Directors, Inc. www.myasd.com