jquery get data attributes from dynamically generated options - javascript

I am creating a drop down dynamically after an ajax all and populating the fields. I am also calling jquery.data() to set some attribute which I want in future.
HTML
<input id="test" type="text" list="mylist"/>
<datalist id="mylist"></datalist>
JS
$(function() {
// assume this data is coming from ajax call
var data = [{
"name": "John",
"id": 1
}, {
"name": "Jane",
"id": 2
}, {
"name": "Judie",
"id": 3
}];
var generateDropDown = function(data) {
var datalist = $('#mylist');
for (var i = 0; i < data.length; i++) {
var value = data[i].name + ' => ' + data[i].id;
$('<option>', {
'class': 'myclass'
})
.val(value)
.data('extra', {
'newid': data[i] * 100
})
.appendTo(datalist);
}
};
generateDropDown(data);
$('.myclass').on('select', function(selected) {
console.log($(selected).data('extra'));
console.log($(this).data('extra'));
});
});
Here is the JSFiddle
My requirement is to access the selected value from drop down along with the data attribute i have added. How can I do that ?
I tried the 2 console.log options as mentioned above but they dont print anything.

In comparison to HTMLSelectElement object, HTMLDataListElement object doesn't have selectedIndex property, so it seems you have to filter the options for getting the possible selected option.
$('#test').on('change', function (/* event */) {
var val = this.value;
var data = $(this.list.options).filter(function() {
return this.value === val;
}).data('extra');
});
Here is a demo.
Also note that data[i] * 100 results in a NaN (Not a Number) value as you are multiplying an object by a number and it doesn't make any sense!

When using a datalist, think of it as just a list of suggestions for the user. The user can type whatever he/she wants. The option elements are not related to the actual selected value which is stored in the textbox. If you must use a datalist, then use an event on the textbox and select the option based on the value. Something like:
$('#test').on('change', function(selected) {
alert($("#mylist option[value='"+$(this).val()+"']").data('extra'));
});
This takes the textbox value and finds the associated datalist option. However, if I type some random gibberish, it won't and can't work since no corresponding option exists. The alternative is to use a select which forces the user to choose one of the options in the list.
If you want a select, take a look at https://jsfiddle.net/tscxyw5m/
Essentially now we can do:
$("#mylist").on('change', function() {
alert($(this).find("option:selected").data("extra"));
});
Because now the options are actually associated with the select.
Also note I think you meant:
'newid': data[i].id * 100
Not
'newid': data[i] * 100
Which yields NaN.

DEMO: https://jsfiddle.net/erkaner/9yb6km6a/21/
When you try to get the value of the selected item, you need to search through the options in the page and bring the option item that matches with the value in the input field:
$("#test").bind('input', function () {
alert($('body')
.find(
'option[value*="' + $(this).val() + '"]'
).data('extra').newid);
});

Related

priority-web-sdk: Implementing a choose-field

I'm trying to implement a choose-field with a <select> control.
<div id="container" onchange="fieldChangeHandler(event)">
...
<div class="item" >
<label>Status</label>
<select id="STATDES" onfocus="focusdiv(event)" onblur="defocusdiv(event)"></select>
</div>
In the updateFields() handler I identify the control type:
function updateFields(result) {
if (result[myForm.name]) {
var fields = result[myForm.name][1];
for (var fieldName in fields) {
var el = document.getElementById(fieldName);
if (el) {
switch (el.nodeName){
case "INPUT":
el.value = fields[fieldName];
break;
case 'SELECT':
fill(el, fields[fieldName]);
el.value = fields[fieldName];
break;
};
};
}
}
}
...And if the control is a <select> I fill in the options with a call to the form choose:
function fill(el, sel){
myForm.choose(el.id, "").then(
function (searchObj) {
var i, ch;
$('#'+el.id).empty();
for (i in searchObj.ChooseLine) {
ch = searchObj.ChooseLine[i];
if (ch.string1 == sel){
$("#"+el.id).append('<option selected value="'+ ch.string1 +'">'+ ch.string1 +'</option>');
} else {
$('#'+el.id).append('<option value="'+ ch.string1 +'">'+ ch.string1 +'</option>');
};
};
},
function (serverResponse) {
alert(serverResponse.message);
}
);
};
Subsequent calls to the fieldChangeHandler by the <select> onchange event call the fieldUpdate method on the loaded form:
function fieldChangeHandler(event) {
console.log("%s=%s", event.srcElement.id, event.target.value);
myForm.fieldUpdate(event.srcElement.id, event.target.value);
}
This all works fine till I try to save the current form record.
function saveHandler() {
myForm.saveRow(
0,
function(){
console.log("Row Saved.");
},
function(serverResponse){
console.log("%j", serverResponse);
});
}
where I get the following output:
Object {type: "error", ...}
code:"stop"
fatal:false
form:Object
message:"Status missing."
type:"error"
__proto__:Object
How do I override the saveRow function to make it retrieve it's data from the <select> control please?
You MUST specify the current value in choose parameters. It won't read it from the current record as I (mis)read the docs..
Note: If the field currently cotains a value, it will automatically be
filled in as fieldValue, even if a different fieldValue was specified.
So, the fill function should look like this...
function fill(el, sel){
myForm.choose(el.id, sel).then(
...
};
I just want to point something out. The choose method : myform.choose is not necessarily called after a field update.
I understand that in ur case the choose list gets different values for each field update and that u need to update ur select. Which is cool but in case someone uses a choose list that is not changed after fields updates it is better to call this method only once!
Just writing it here to clarify things about the choose method :)

Retrieve the disabled attributes even after page refresh using localStorage

I have an HTML code with a select tag where the options are dynamically populated. Once the onchange event occurs the option selected gets disabled. And also if any page navigation happens the options populated previously are retrieved.
In my case once options are populated and any option is selected gets disabled( intention to not allow the user to select it again). So there might be a case where out of 3 options only two are selected and disabled so once I refresh and the options not selected previously should be enabled. And the options selected previously should be disabled. But my code enables all the options after refresh. How can I fix this?
html code
<select id="convoy_list" id="list" onchange="fnSelected(this)">
<option>Values</option>
</select>
js code
//This function says what happnes on option change
function fnSelected(selctdOption){
var vehId=selctdOption.options[selctdOption.selectedIndex].disabled=true;
localStorage.setItem("vehId",vehId);
//some code and further process
}
//this function says the process on the drop-down list --on how data is populated
function test(){
$.ajax({
//some requests and data sent
//get the response back
success:function(responsedata){
for(i=0;i<responsedata.data;i++):
{
var unitID=//some value from the ajax response
if(somecondition)
{
var select=$(#convoy_list);
$('<option>').text(unitID).appendTo(select);
var conArr=[];
conArr=unitID;
test=JSON.stringify(conArr);
localStorage.setItem("test"+i,test);
}
}
}
});
}
//In the display function--on refresh how the stored are retrievd.
function display(){
for(var i=0;i<localStorage.length;i++){
var listId=$.parseJSON(localStorage.getItem("test"+i)));
var select=$(#list);
$('<option>').text(listId).appendTo(select);
}
}
In the display function the previously populated values for the drop down are retrieved but the options which were selected are not disabled. Instead all the options are enabled.
I tried the following in display function
if(localStorage.getItem("vehId")==true){
var select=$(#list);
$('<option>').text(listId).attr("disabled",true).appendTo(select);
}
But this does not work.
Elements on your page shouldn't have same ids
<select id="convoy_list" onchange="fnSelected(this)">
<option>Values</option>
</select>
In your fnSelected() function you always store item {"vehId" : true} no matter what item is selected. Instead, you should for example first assign some Id to each <option\> and then save the state only for them.
For example:
function test(){
$.ajax({
//some requests and data sent
//get the response back
success:function(responsedata){
for(i=0;i<responsedata.data;i++):
{
var unitID=//some value from the ajax response
if(somecondition)
{
var select=$("#convoy_list"); \\don't forget quotes with selectors.
var itemId = "test" + i;
$('<option>').text(unitID).attr("id", itemId) \\we have set id for option
.appendTo(select);
var conArr=[];
conArr=unitID;
test=JSON.stringify(conArr);
localStorage.setItem(itemId,test);
}
}
}
});
}
Now we can use that id in fnSelected():
function fnSelected(options) {
var selected = $(options).children(":selected");
selected.prop("disabled","disabled");
localStorage.setItem(selected.attr("id") + "disabled", true);
}
And now in display():
function display(){
for(var i=0;i<localStorage.length;i++){
var listId = $.parseJSON(localStorage.getItem("test"+i)));
var select = $("convoy_list");
var option = $('<option>').text(listId).id(listId);
.appendTo(select);
if(localStorage.getItem(listId + "disabled") == "true"){
option.prop("disabled","disabled");
}
option.appendTo(select);
}
}
Also maybe not intended you used following shortcut in your fnSelected:
var a = b = val;
which is the same as b = val; var a = b;
So your fnSelected() function was equivalent to
function fnSelected(selctdOption){
selctdOption.options[selctdOption.selectedIndex].disabled=true;
var vehId = selctdOption.options[selctdOption.selectedIndex].disabled;
localStorage.setItem("vehId",vehId); \\ and "vehId" is just a string, always the same.
}
Beware of some errors, I didn't test all of this, but hope logic is understood.

LocalStorage retrieving from arrays, confusion

Getting confused, creating a web app where people post notes, I have a field for subject and one for the actual note, when posted these should be saved into two arrays, when posted these should appear almost like a comment, with what you just entered in two fields, which did work but I want people to be able to save their notes, close the browser and return, below is the code that is not working, basically the user should be able to
Allow user to enter in values.
If local storage is available, Take values saved from arrays (which I tried converting to a string then convert back to a array using JSON, which is confusing) and fill the page
$("document").ready( function (){
//Each subjectField.value goes into array
var subjectInputArray = [];
//Each noteField.value goes into array
var noteInputArray = [];
//Color array holds color hex codes as values
var noteColourArray = [];
noteColourArray[0] = "#03CEC2";
noteColourArray[1] = "#ADC607";
noteColourArray[2] = "#ffdd00";
noteColourArray[3] = "#f7941f";
//Variable holds properties for note creation
var noteCreate =
{
noteCreateContainer : $("<article>", { id: "noteCreateContainer" }),
noteForm : $("<form>", { id: "noteFormContainer" }),
subjectField : $("<input>", { type: "text", placeholder: "Title", id: "subject"}),
noteField : $("<input>", { type: "text", placeholder: "Write a Note", id: "noteContent" }),
submitNote : $("<button>", { type: "submit", id: "post", text: "post"}).on( "click", (postNote))
}
//Variable holds properties for a note content (NOT SUBJECT);
var notePost = {}
//--------------------------------------------------------------------------------
//Test if local storage is supported
if( Modernizr.localstorage ) {
//Get current array/list
localStorage.getItem("subjectInputArray")
//Convert string back to array
var savedNoteSubjects = JSON.parse(localStorage["subjectInputArray"]);
//For each item in subject localStorage array, loop through an fill page with fields containing values
for(var i = 0; i < savedNoteSubjects.length; i++)
{
//Create container for post
//Apply noteCreateContainer's selected background color to the posted note
$("<article>").appendTo("body").addClass("notePostContainer").css("background-color", ($("#noteCreateContainer").css("background-color")));
console.log("local storage: " + [savedNoteSubjects]);
//Select last div of class notePostContainer to add input field, instead of adding 1+ input fields on each click to all classes using the same class name
$("<input>", {class: "subjectFieldPost", type: "text", value: savedNoteSubjects[savedNoteSubjects.length-1] }).appendTo(".notePostContainer:last-child").prop("disabled", true);
}
} else {
alert("Your browser does not support localStorage, consider upgrading your internet browser");
}
//--------------------------------------------------------------------------------
//Create/Set up fields required for user to input data
noteCreate.noteCreateContainer.prependTo("body");
noteCreate.noteForm.appendTo(noteCreateContainer);
//Loop through noteColourArray and append new button for each item
for (var i = 0, len = noteColourArray.length; i < len; i++) {
noteCreate.noteForm.append($("<button>", {class: "colourSelect", value: noteColourArray[i] }).css("background-color", noteColourArray[i]).click(setBackgroundColour))
}
//Change background colour on click
function setBackgroundColour()
{
$("#noteCreateContainer").css("background-color", noteColourArray[$(this).index()] )
return false;
}
noteCreate.subjectField.appendTo(noteFormContainer);
noteCreate.noteField.appendTo(noteFormContainer);
noteCreate.submitNote.appendTo(noteFormContainer);
//--------------------------------------------------------------------------------BELOW NOTE POST/OUTPUT FROM CREATING NOTE
//FUNCTION - CREATE NEW POST UPON CLICKING POST
function postNote()
{
//Add submitted value of subject field to array
subjectInputArray.push( $("#subject").val() );
//Convert array into string
localStorage["subjectInputArray"] = JSON.stringify(subjectInputArray);
//Add value of note field to array
noteInputArray.push( $("#noteContent").val() );
//Create container for post
$("<article>").appendTo("body").addClass("notePostContainer").css("background-color", ($(noteCreateContainer).css("background-color")) ) //Apply noteCreateContainer's selected background color to the posted note
//Select last div of class notePostContainer to add input field, instead of adding 1+ input fields on each click to all classes using the same class name
//Pull value from local storage subject array
$("<input>", {class: "subjectFieldPost", type: "text", value: subjectInputArray[subjectInputArray.length-1] }).appendTo(".notePostContainer:last-child").prop("disabled", true)
//Select last div of class notePostContainer to add input field, instead of adding 1+ input fields on each click to all classes using the same class name
$("<input>", {class: "noteFieldPost", type: "text", value: noteInputArray[noteInputArray.length-1] }).appendTo(".notePostContainer:last-child").prop("disabled", true)
return false;
} //End function
});
An earlier post I made in relation to my idea
button click temporarily changes div background color, not permanently as intended
var subjectInputArray = [];
...
localStorage["subjectInputArray"] = JSON.stringify(subjectInputArray);
You are setting your localStorage["subjectInputArray"] to an empty array every time your page loads.
How could you expect load anything useful from it?
Instead, try put localStorage["subjectInputArray"] = JSON.stringify(subjectInputArray); in postNote(), so every time user input something, you update the localStorage record.
Additionally,
var savedNoteSubjects = JSON.parse(localStorage["subjectInputArray"]);
this line should be inside the test local storage if block. Don't use it until it's confirmed to be available

How can I create dynamic controls and put their data into an object?

I created a div and a button. when the button clicked, there will be a group of element(included 1 select box and 2 text inputs) inserted into the div. User can add as many group as they can, when they finished type in data of all the group they added, he can hit save button, which will take the value from each group one by one into the JSON object array. But I am stuck in the part how to get the value from each group, so please help, thank you.
The code for the div and the add group button function -- AddExtra() are listed below:
<div id="roomextra">
</div>
function AddExtra() {
$('#roomextra').append('<div class=extra>' +
'<select id="isInset">' +
'<option value="Inset">Inset</option>' +
'<option value="Offset">OffSet</option>' +
'</select>' +
'Length(m): <input type="text" id="insetLength">' +
'Width(m): <input type="text" id="insetWidth">' +
'Height(m): <input type="text" id="insetHeight">' +
'</div>');
}
function GetInsetOffSetArray (callBack) {
var roomIFSDetail = [{
"IsInset": '' ,
"Length": '' ,
"Width": '' ,
"Height": ''
}];
//should get all the value from each group element and write into the array.
callBack(roomIFSDetail);
}
This should just about do it. However, if you're dynamically creating these groups, you'll need to use something other than id. You may want to add a class to them or a data-* attribute. I used a class, in this case. Add those classes to your controls so we know which is which.
var roomIFSDetail = [];
var obj;
// grab all of the divs (groups) and look for my controls in them
$(.extra).each(function(){
// create object out of select and inputs values
// the 'this' in the selector is the context. It basically says to use the object
// from the .each loop to search in.
obj = {
IsInset: $('.isInset', this).find(':selected').val() ,
Length: $('.insetLength', this).val() ,
Width: $('.insetWidth', this).val() ,
Height: $('.insetHeight', this).val()
};
// add object to array of objects
roomIFSDetail.push(obj);
});
you'd better not to use id attribute to identity the select and input, name attribute instead. for example
$('#roomextra').append('<div class=extra>' +
'<select name="isInset">' +
'<option value="Inset">Inset</option>' +
'<option value="Offset">OffSet</option>' +
'</select>' +
'Length(m): <input type="text" name="insetLength">' +
'Width(m): <input type="text" name="insetWidth">' +
'Height(m): <input type="text" name="insetHeight">' +
'</div>');
}
and then, usr foreach to iterate
$(".extra").each(function() {
var $this = $(this);
var isInset = $this.find("select[name='isInset']").val();
var insetLength = $this.find("input[name='insetLength']").val();
// ... and go on
});
A common problem. A couple things:
You can't use IDs in the section you're going to be repeating, because IDs in the DOM are supposed to be unique.
I prefer to use markup where I'm writing a lot of it, and modify it in code rather than generate it there.
http://jsfiddle.net/b9chris/PZ8sf/
HTML:
<div id=form>
... non-repeating elements go here...
<div id=roomextra>
<div class=extra>
<select name=isInset>
<option>Inset</option>
<option>OffSet</option>
</select>
Length(m): <input id=insetLength>
Width(m): <input id=insetWidth>
Height(m): <input id=insetHeight>
</div>
</div>
</div>
JS:
(function() {
// Get the template
var container = $('#roomextra');
var T = $('div.extra', container);
$('#addGroup').click(function() {
container.append(T.clone());
});
$('#submit').click(function() {
var d = {};
// Fill d with data from the rest of the form
d.groups = $.map($('div.extra', container), function(tag) {
var g = {};
$.each(['isInset', 'insetLength', 'insetWidth', 'insetHeight'], function(i, name) {
g[name] = $('[name=' + name + ']', tag).val();
});
return g;
});
// Inspect the data to ensure it's what you wanted
debugger;
});
})();
So the template that keeps repeating is written in plain old HTML rather than a bunch of JS strings appended to each other. Using name attributes instead of ids keeps with the way these elements typically work without violating any DOM constraints.
You might notice I didn't quote my attributes, took the value attributes out of the options, and took the type attributes out of the inputs, to keep the code a bit DRYer. HTML5 specs don't require quoting your attributes, the option tag's value is whatever the text is if you don't specify a value attribute explicitly, and input tags default to type=text if none is specified, all of which adds up to a quicker read and slimmer HTML.
Use $(".extra").each(function() {
//Pull info out of ctrls here
});
That will iterate through all of your extra divs and allow you to add all values to an array.

Add the "selected" attribute to a drop down option with jQuery

How do I add the attribute "selected" to a drop down menu option based on that option matching some variable?
Here is how the dropdown is populated...
loginOptions = ["First", "Second", "Third"];
var Login = $( '#Login' );
for ( var i = 0; i < loginOptions.length; i++ ) {
Login.append('<option value="'+ loginOptions[i] +'">'+ loginOptions[i] +'</option>');
}
I want to mark one option as "selected" based on whether or not its value matches another variable. so if loginOption[i] is equal to var existingLoginValue then set that option to 'selected'
Something that would do
if(loginOptions[i] === existingLoginValue){ print 'selected'; };
Thanks!
I'd use .val() at the end of your method, this sets based on value, like this:
$('#Login').val(existingLoginValue);
Similarly, to get the value, call it without any parameters like this:
var currentValue = $('#Login').val();
If you only want to do one value then yeah, the val() works. Otherwise, you can also do this:
$option=$('<option value="'+ loginOptions[i] +'">'+ loginOptions[i]+'</option>').appendTo(Login);
if (loginOptions[i] == existingLoginValue) {
$option.attr('selected',true)
}
er, someone pointed out this doesn't really make sense since that would imply multiple options with the same value. I meant to write something like this:
existingLoginValues = ['foo','bar']
$option=$('<option value="'+ loginOptions[i] +'">'+ loginOptions[i]+'</option>').appendTo(Login);
if (existingLoginValues.indexOf(loginOptions[i]) != -1) {
$option.attr('selected',true)
}
the indexOf function is supported in most browsers except (of course) IE6. See "Best way to find an item in a JavaScript Array?"
Use
$('#Login').selectedIndex = i

Categories

Resources