Link to home
Start Free TrialLog in
Avatar of Shaye Larsen
Shaye Larsen

asked on

jQuery input elements losing value upon adding item to list

I have implemented a script to be able to add elements to a list and sort them. I can add them fine. I edited the script so that I could edit the elements name after being sent to the list by appending <input> inside the element created in the sort list..

Every time I add a new element to the list all the other input elements in the sort list lose their value.

I got the script from here:

The script here below isjquery.asmselect.js and the doc ready function on my page.
//this is the main script jquery.asmselect.js
/*
 * Alternate Select Multiple (asmSelect) 1.0.4 beta - jQuery Plugin
 * http://www.ryancramer.com/projects/asmselect/
 * 
 * Copyright (c) 2008 by Ryan Cramer - http://www.ryancramer.com
 * 
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 */
 
(function($) {
 
	$.fn.asmSelect = function(customOptions) {
 
		var options = {
 
			listType: 'ol',						// Ordered list 'ol', or unordered list 'ul'
			sortable: false, 					// Should the list be sortable?
			highlight: false,					// Use the highlight feature? 
			animate: false,						// Animate the the adding/removing of items in the list?
			addItemTarget: 'bottom',				// Where to place new selected items in list: top or bottom
			hideWhenAdded: false,					// Hide the option when added to the list? works only in FF
			debugMode: false,					// Debug mode keeps original select visible 
 
			removeLabel: 'remove',					// Text used in the "remove" link
			highlightAddedLabel: 'Added: ',				// Text that precedes highlight of added item
			highlightRemovedLabel: 'Removed: ',			// Text that precedes highlight of removed item
 
			containerClass: 'asmContainer',				// Class for container that wraps this widget
			selectClass: 'asmSelect',				// Class for the newly created <select>
			optionDisabledClass: 'asmOptionDisabled',		// Class for items that are already selected / disabled
			listClass: 'asmList',					// Class for the list ($ol)
			listSortableClass: 'asmListSortable',			// Another class given to the list when it is sortable
			listItemClass: 'asmListItem',				// Class for the <li> list items
			listItemLabelClass: 'asmListItemLabel',			// Class for the label text that appears in list items
			inputItemLabelClass: 'asmInputItemLabel',			// Class for the label text that appears in list items
			removeClass: 'asmListItemRemove',			// Class given to the "remove" link
			highlightClass: 'asmHighlight',				// Class given to the highlight <span>
			listPageTypeClass: 'asmPageType'            // Class given to page type <span> added by Dale Larsen
 
			};
 
		$.extend(options, customOptions); 
 
		return this.each(function(index) {
 
			var $original = $(this); 				// the original select multiple
			var $container; 					// a container that is wrapped around our widget
			var $select; 						// the new select we have created
			var $ol; 						// the list that we are manipulating
			var buildingSelect = false; 				// is the new select being constructed right now?
			var ieClick = false;					// in IE, has a click event occurred? ignore if not
			var ignoreOriginalChangeEvent = false;			// originalChangeEvent bypassed when this is true
 
			function init() {
 
				// initialize the alternate select multiple
 
				// this loop ensures uniqueness, in case of existing asmSelects placed by ajax (1.0.3)
				while($("#" + options.containerClass + index).size() > 0) index++; 
 
				$select = $("<select></select>")
					.addClass(options.selectClass)
					.attr('name', options.selectClass + index)
					.attr('id', options.selectClass + index); 
 
				$selectRemoved = $("<select></select>"); 
 
				$ol = $("<" + options.listType + "></" + options.listType + ">")
					.addClass(options.listClass)
					.attr('id', options.listClass + index); 
 
				$container = $("<div></div>")
					.addClass(options.containerClass) 
					.attr('id', options.containerClass + index); 
 
				buildSelect();
 
				$select.change(selectChangeEvent)
					.click(selectClickEvent); 
 
				$original.change(originalChangeEvent)
					.wrap($container).before($select).before($ol);
 
				if(options.sortable) makeSortable();
 
				if($.browser.msie) $ol.css('display', 'inline-block'); 
			}
 
			function makeSortable() {
 
				// make any items in the selected list sortable
				// requires jQuery UI sortables, draggables, droppables
 
				$ol.sortable({
					items: 'li.' + options.listItemClass,
					handle: '.' + options.listItemLabelClass,
					axis: 'y',
					update: function(e, data) {
 
						var updatedOptionId;
 
						$(this).children("li").each(function(n) {
 
							$option = $('#' + $(this).attr('rel')); 
 
							if($(this).is(".ui-sortable-helper")) {
								updatedOptionId = $option.attr('id'); 
								return;
							}
 
							$original.append($option); 
						}); 
 
						if(updatedOptionId) triggerOriginalChange(updatedOptionId, 'sort'); 
					}
 
				}).addClass(options.listSortableClass); 
			}
 
			function selectChangeEvent(e) {
				
				// an item has been selected on the regular select we created
				// check to make sure it's not an IE screwup, and add it to the list
 
				if($.browser.msie && $.browser.version < 7 && !ieClick) return;
				var id = $(this).children("option:selected").slice(0,1).attr('rel'); 
				addListItem(id); 	
				ieClick = false; 
				triggerOriginalChange(id, 'add'); // for use by user-defined callbacks
			}
 
			function selectClickEvent() {
 
				// IE6 lets you scroll around in a select without it being pulled down
				// making sure a click preceded the change() event reduces the chance
				// if unintended items being added. there may be a better solution?
 
				ieClick = true; 
			}
 
			function originalChangeEvent(e) {
 
				// select or option change event manually triggered
				// on the original <select multiple>, so rebuild ours
 
				if(ignoreOriginalChangeEvent) {
					ignoreOriginalChangeEvent = false; 
					return; 
				}
 
				$select.empty();
				$ol.empty();
				buildSelect();
 
				// opera has an issue where it needs a force redraw, otherwise
				// the items won't appear until something else forces a redraw
				if($.browser.opera) $ol.hide().fadeIn("fast");
			}
 
			function buildSelect() {
 
				// build or rebuild the new select that the user
				// will select items from
 
				buildingSelect = true; 
 
				// add a first option to be the home option / default selectLabel
				$select.prepend("<option>" + $original.attr('title') + "</option>"); 
 
				$original.children("option").each(function(n) {
 
					var $t = $(this); 
					var id; 
 
					if(!$t.attr('id')) $t.attr('id', 'asm' + index + 'option' + n); 
					id = $t.attr('id'); 
 
					if($t.is(":selected")) {
						addListItem(id); 
						addSelectOption(id, true); 						
					} else {
						addSelectOption(id); 
					}
				});
 
				if(!options.debugMode) $original.hide(); // IE6 requires this on every buildSelect()
				selectFirstItem();
				buildingSelect = false; 
			}
 
			function addSelectOption(optionId, disabled) {
 
				// add an <option> to the <select>
				// used only by buildSelect()
 
				if(disabled == undefined) var disabled = false; 
 
				var $O = $('#' + optionId); 
				var $option = $("<option>" + $O.text() + "</option>")
					.val($O.val())
					.attr('rel', optionId);
 
				if(disabled) disableSelectOption($option); 
 
				$select.append($option); 
			}
 
			function selectFirstItem() {
 
				// select the firm item from the regular select that we created
 
				$select.children(":eq(0)").attr("selected", true); 
			}
 
			function disableSelectOption($option) {
 
				// make an option disabled, indicating that it's already been selected
				// because safari is the only browser that makes disabled items look 'disabled'
				// we apply a class that reproduces the disabled look in other browsers
 
				$option.addClass(options.optionDisabledClass)
					.attr("selected", false)
					.attr("disabled", true);
 
				if(options.hideWhenAdded) $option.hide();
				if($.browser.msie) $select.hide().show(); // this forces IE to update display
			}
 
			function enableSelectOption($option) {
 
				// given an already disabled select option, enable it
 
				$option.removeClass(options.optionDisabledClass)
					.attr("disabled", false);
 
				if(options.hideWhenAdded) $option.show();
				if($.browser.msie) $select.hide().show(); // this forces IE to update display
			}
 
			function addListItem(optionId) {
 
				// add a new item to the html list
 
				var $O = $('#' + optionId); 
 
				if(!$O) return; // this is the first item, selectLabel
 
				var $removeLink = $("<a></a>")
					.attr("href", "#")
					.addClass(options.removeClass)
					.prepend(options.removeLabel)
					.click(function() { 
						dropListItem($(this).parent('li').attr('rel')); 
						return false;
					}); 
 
				var $itemInput = $('<input type="text"/>')
					.addClass(options.inputItemLabelClass)
					.val("");
 
				var $itemLabel = $('<span></span>')
					.append($itemInput)
					.addClass(options.listItemLabelClass);
 
				var $itemPageType = $('<span></span>')
					.addClass(options.listPageTypeClass)
					.html($O.html());
					
				var $item = $("<li></li>")
					.attr('rel', optionId)
					.addClass(options.listItemClass)
					.append($itemLabel)
					.append($itemPageType)
					.append($removeLink)
					.hide();
 
				if(!buildingSelect) {
					if($O.is(":selected")) return; // already have it
					$O.attr('selected', true); 
				}
 
				if(options.addItemTarget == 'top' && !buildingSelect) {
					$ol.prepend($item); 
					if(options.sortable) $original.prepend($O); 
				} else {
					$ol.append($item); 
					if(options.sortable) $original.append($O); 
				}
 
				addListItemShow($item); 
 
				disableSelectOption($("[rel=" + optionId + "]", $select));
 
				if(!buildingSelect) {
					setHighlight($item, options.highlightAddedLabel); 
					selectFirstItem();
					if(options.sortable) $ol.sortable("refresh"); 	
				}
 
			}
 
			function addListItemShow($item) {
 
				// reveal the currently hidden item with optional animation
				// used only by addListItem()
 
				if(options.animate && !buildingSelect) {
					$item.animate({
						opacity: "show",
						height: "show"
					}, 150, "swing", function() { //default 100
						$item.animate({
							height: "+=2px"
						}, 100, "swing", function() {//default 50
							$item.animate({
								height: "-=2px"
							}, 95, "swing");//default 25 
						}); 
					}); 
				} else {
					$item.show();
				}
			}
 
			function dropListItem(optionId, highlightItem) {
 
				// remove an item from the html list
 
				if(highlightItem == undefined) var highlightItem = true; 
				var $O = $('#' + optionId); 
 
				$O.attr('selected', false); 
				$item = $ol.children("li[rel=" + optionId + "]");
 
				dropListItemHide($item); 
				enableSelectOption($("[rel=" + optionId + "]", options.removeWhenAdded ? $selectRemoved : $select));
 
				if(highlightItem) setHighlight($item, options.highlightRemovedLabel); 
 
				triggerOriginalChange(optionId, 'drop'); 
				
			}
 
			function dropListItemHide($item) {
 
				// remove the currently visible item with optional animation
				// used only by dropListItem()
 
				if(options.animate && !buildingSelect) {
 
					$prevItem = $item.prev("li");
 
					$item.animate({
						opacity: "hide",
						height: "hide"
					}, 120, "linear", function() {//default 100
						$prevItem.animate({
							height: "-=2px"
						}, 70, "swing", function() {//default 50
							$prevItem.animate({
								height: "+=2px"
							}, 120, "swing"); //default 100
						}); 
						$item.remove(); 
					}); 
					
				} else {
					$item.remove(); 
				}
			}
 
			function setHighlight($item, label) {
 
				// set the contents of the highlight area that appears
				// directly after the <select> single
				// fade it in quickly, then fade it out
 
				if(!options.highlight) return; 
 
				$select.next("#" + options.highlightClass + index).remove();
 
				var $highlight = $("<span></span>")
					.hide()
					.addClass(options.highlightClass)
					.attr('id', options.highlightClass + index)
					.html(label + $item.children("." + options.listItemLabelClass).slice(0,1).text()); 
					
				$select.after($highlight); 
 
				$highlight.fadeIn(200, function() {//defalut "fast"
					setTimeout(function() { $highlight.fadeOut("slow"); }, 100);//default 50
				}); 
			}
 
			function triggerOriginalChange(optionId, type) {
 
				// trigger a change event on the original select multiple
				// so that other scripts can pick them up
 
				ignoreOriginalChangeEvent = true; 
				$option = $("#" + optionId); 
 
				$original.trigger('change', [{
					'option': $option,
					'value': $option.val(),
					'id': optionId,
					'item': $ol.children("[rel=" + optionId + "]"),
					'type': type
				}]); 
			}
 
			init();
		});
	};
 
})(jQuery); 
 
 
//this is the doc ready function that goes on my page.
$(document).ready(function() {
	$("div[multiple]").asmSelect({
		addItemTarget: 'bottom',
		animate: true,
		removeLabel: 'X',
		highlight: false,
		sortable: true
	});
 
	$("#add_blank_btn").click(function() {
		var addBlank = $("#add_blank").val();
		var $option = $("<option></option>").text(addBlank).attr("selected", true);
		$("#pages").append($option).change();
		return false;
	});
	$("#add_about_btn").click(function() {
		var addAbout = $("#add_about").val();
		var $option = $("<option></option>").text(addAbout).attr("selected", true);
		$("#pages").append($option).change();
		return false;
	});
	$("#add_articles_btn").click(function() {
		var addArticles = $("#add_articles").val();
		var $option = $("<option></option>").text(addArticles).attr("selected", true);
		$("#pages").append($option).change();
		return false;
	});
	$("#add_calendar_btn").click(function() {
		var addCalendar = $("#add_calendar, #add_contact, #add_hours, #add_jobs, #add_news, #add_press, #add_support").val();
		var $option = $("<option></option>").text(addCalendar).attr("selected", true);
		$("#pages").append($option).change();
		return false;
	});
	$("#add_contact_btn").click(function() {
		var addContact = $("#add_contact").val();
		var $option = $("<option></option>").text(addContact).attr("selected", true);
		$("#pages").append($option).change();
		return false;
	});
	$("#add_faq_btn").click(function() {
		var addFaq = $("#add_faq").val();
		var $option = $("<option></option>").text(addFaq).attr("selected", true);
		$("#pages").append($option).change();
		return false;
	});
	$("#add_hours_btn").click(function() {
		var addHours = $("#add_hours").val();
		var $option = $("<option></option>").text(addHours).attr("selected", true);
		$("#pages").append($option).change();
		return false;
	});
	$("#add_jobs_btn").click(function() {
		var addJobs = $("#add_jobs").val();
		var $option = $("<option></option>").text(addJobs).attr("selected", true);
		$("#pages").append($option).change();
		return false;
	});
	$("#add_news_btn").click(function() {
		var addNews = $("#add_news").val();
		var $option = $("<option></option>").text(addNews).attr("selected", true);
		$("#pages").append($option).change();
		return false;
	});
	$("#add_press_btn").click(function() {
		var addPress = $("#add_press").val();
		var $option = $("<option></option>").text(addPress).attr("selected", true);
		$("#pages").append($option).change();
		return false;
	});
	$("#add_support_btn").click(function() {
		var addSupport = $("#add_support").val();
		var $option = $("<option></option>").text(addSupport).attr("selected", true);
		$("#pages").append($option).change();
		return false;
	});
	
});

Open in new window

Avatar of Pawel Witkowski
Pawel Witkowski
Flag of Poland image

line 260:                        var $itemInput = $('<input type="text"/>')
                              .addClass(options.inputItemLabelClass)
                              .val("");



you have .val("")   ?? What for ? can you remove it ?



Avatar of Shaye Larsen
Shaye Larsen

ASKER

Thanks for the reply.

Sorry, that was a test I was doing to try and fix this. I now removed that line, it still has the same problem.
what about removing


.html($O.html());

?:]
thanks, but still not working with that change...
I think that the element is being refreshed or something when I append a new element to the list, or I could be wrong.

Is there a way to hold an elements value so that it is no lost, or a way that when someone appends a new element to the list it take the values of the inputs and reassigns them?
well yes you could save that value, but if values beeing removed after adding new one.. then it means that they are all removed and added again. And this should not be like this... hmm... we could also store values but this is a bad idea (like hacking instead of good programming)
Yeah, I prefer to avoid hacking.
Can you give me some example page on web with code running ? That would help me debug it ;)
Alright, I have made this test page.

Go to:
http://dalelarsen.com/fab/sort.php
Look at function buildSelect - as there in comments it just builds or rebuilds whole select element.

You just need to:

Put there (exacly in addListItem (optionId)) a proper value that will be stored before removing every elements in this list.


Removing elements is here:

function originalChangeEvent(e) {

...

$select.empty();
$ol.empty();
buildSelect();




Is this enough here for you ?
Thank you so much, but I am afraid I'm not sure what to add or delete? I'll keep looking into it but I'm a bit confused.
originalChangeEvent is a function that is fired when you trying to add new input. It just removes all inputs that you had before and create a whole new list (buildSelect function do that using an addListItem function). So what you can do is to store input values in originalChangeEvent just before removing elements and then  use this value to fill proper data inside addListItem function. Is that sount clear ? Or still have problem ?:)
Thanks, Sounds clear, I'm just not that advanced with javascript...
ASKER CERTIFIED SOLUTION
Avatar of Pawel Witkowski
Pawel Witkowski
Flag of Poland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Wow, thanks. I have implemented those changes. Now the appended element has no input field and I don't see why. I have tested it through it seems all the elements are there to create it.

When I remove:

.value = $O.attr("last");

From:

var $itemInput = $('<input type="text"/>')
.addClass(options.inputItemLabelClass)
.value = $O.attr("last");

The input fields show again but, of course, still without the desired functionality.

The updates have been made to the test page:

http://dalelarsen.com/fab/sort.php 
sorry Mine mistake

should be

var $itemInput = $('<input type="text"/>').addClass(options.inputItemLabelClass).attr("value",$O.attr("last"));
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Perfect thanks!!!
Wilq, I need help at the following question that relates to this one. I need to do the same thing but detect if the radio was checked or not.

https://www.experts-exchange.com/questions/24574082/jQuery-sort-losing-if-radio-is-checked-or-not.html