I'm designing a form-building interface. All available fields will be in an unordered list on the left of the interface, with a large, empty unordered list on the right which will become my webform. The "trick" to making this interface work is having the list items from the left transformed into valid html elements by appending html into the droppable ui element just before they are appended into the sortable list on the right.
I have it working...mostly...using draggable() and sortable(). Currently, I use the receive event of sortable to get the id from the draggable element, which I place into a data() block to pass to the update event. From there, I do an ajax call with the id element, determine what type of field it is and what options should be added from the back end, build the element, then put it in the interface using ui.item.html
, which is an element passed by the update function.
The problem with my method is that it also is firing when an element is dragged, which cause select elements to litter the screen when they unintentionally append to the sortable list. Clearly, the receive event is the one that is fired only when the sort gets an item from a connected list. However, if I try to inner html the ui.item
element, it changes the source list, not the desired target. When items are already in the webform list on the right, I definitely don't want to be modifying them if they're just being sorted.
Is there any way to access and change the target html in a connected sortable()
list receive event? Are there any other strategies that might solve my challenge?
The Code:
<div class="grid_3 mainwindow formfields">
<h3>Available Fields</h3>
<div id="accordion">
<ul>
<li>First Name</li>
<li>Last Name</li>
<li>Company</li>
</ul>
</div>
</div>
</div>
<div class="grid_12 formcontainer formfields">
<h3>Webform</h3>
<form id="form" action="http://responses.smarttracks.com" method="post">
<input type="hidden" name="webform_id" id="webform_id" value="<?php echo $webform_id ?>"></input>
<ul id="webform_list"></ul>
</form>
</div>
And the jQuery
/***** Make webform fields draggable *****/
$( ".master_list li" ).draggable({
connectToSortable: "#webform_list",
helper: "clone",
revert: "invalid"
});
/***** Make form elements sortable *****/
$( "#webform_list" ).sortable({
revert: true,
cursor: 'pointer',
placeholder: "placeholderdiv",
receive: function(event, ui) {
$(this).data('id', ui.item[0].id);
var element = event.target
},
update: function(event, ui) {
var fieldname = ui.item.text();
if ($(this).data('id')) {
$.ajax({
url: "/webform/getFieldAttributes",
timeout: 30000,
type: "POST",
data: 'id='+$(this).data('id'),
dataType: 'json',
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert("An error has occurred making the request: " + errorThrown)
},
success: function(data){
switch (data.control_type) {
case 'text':
var inputfield = $('<input type="text">').attr('id', 'fieldname');
var field = (ui.item).text();
switch (field) {
case 'Email Address':
inputfield.addClass('validate[optional,custom[email]]');
break;
default:
inputfield.addClass('validate[required]');
break;
}
break;
case 'textarea':
var inputfield = $('<textarea>');
break;
case 'Dropdown Menu (Single Select)':
var inputfield = $('<select>');
$.each(data.field_options, function(name, value) {
inputfield.append($("<option></option>").attr("value",name).text(value))
});
inputfield.addClass('validate[required]');
break;
case 'Radio Buttons (Single Select)':
var inputfield = $('<div class="webform_radiogroup">');
$.each(data.field_options, function(name, value) {
var container = $('<div class="webform_radio_option">');
var radio = $('<input type="radio">').attr({ name: name,value: value,id: name });
radio.appendTo(container);
$('<label for="'+name+'">'+name+'</label>').appendTo(container);
$('<div class="clear">').appendTo(container);
container.appendTo(inputfield);
});
break;
}
if (data.control_type == 'Radio Buttons (Single Select)') {
ui.item.html('<div class="webform_radiogroup_label">'+fieldname+'</div>').append(inputfield).append('<div class="clear">').wrapInner('<div class="webform_questiongroup">').wrapInner('<div class="hoverdiv" />');
} else {
ui.item.html('').append('<label for="'+fieldname+'">'+fieldname+'</label>').append(inputfield).wrapInner('<div class="hoverdiv" />');
}
}
});
}
}
});