On my jQuery Mobile page I would like to implement multiple filter select menus. It works totally fine with only one select menu and an id, but not with multiple.
JSFiddle with my problem:
http://jsfiddle.net/asvyY/40/
(By contrast, my fiddle with ONLY ONE select menu and a select menu id works: http://jsfiddle.net/asvyY/41/)
Error message:
Uncaught Error: cannot call methods on selectmenu prior to initialization; attempted to call method 'refresh'
My code:
HTML:
<div data-role="page" id="page1">
<div data-role="header">
<h1>My page</h1>
</div>
<div role="main" class="ui-content">
<form>
<select class="filter-menu" data-native-menu="false">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<select class="filter-menu" data-native-menu="false">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<select class="filter-menu" data-native-menu="false">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
</form>
</div>
</div>
JS:
$(document).on("pagecreate", "#page1", function(){
$(".filter-menu").selectmenu( "refresh", true );
});
$.mobile.document
.on("listviewcreate", "#filter-menu-menu", function (e) {
var input,
listbox = $("#filter-menu-listbox"),
form = listbox.jqmData("filter-form"),
listview = $(e.target);
if (!form) {
input = $("<input data-type='search'></input>");
form = $("<form></form>").append(input);
input.textinput();
$("#filter-menu-listbox")
.prepend(form)
.jqmData("filter-form", form);
}
listview.filterable({
input: input
});
})
// The custom select list may show up as either a popup or a dialog,
// depending how much vertical room there is on the screen. If it shows up
// as a dialog, then the form containing the filter input field must be
// transferred to the dialog so that the user can continue to use it for
// filtering list items.
//
// After the dialog is closed, the form containing the filter input is
// transferred back into the popup.
.on("pagebeforeshow pagehide", "#filter-menu-dialog", function (e) {
var form = $("#filter-menu-listbox").jqmData("filter-form"),
placeInDialog = (e.type === "pagebeforeshow"),
destination = placeInDialog ? $(e.target).find(".ui-content") : $("#filter-menu-listbox");
form.find("input")
// Turn off the "inset" option when the filter input is inside a dialog
// and turn it back on when it is placed back inside the popup, because
// it looks better that way.
.textinput("option", "inset", !placeInDialog)
.end()
.prependTo(destination);
});
Here is my working JSFiddle: http://jsfiddle.net/asvyY/46/
I deleted the following lines, because jqm automatically transforms the select-tag into a select-menu
$(document).on("pagecreate", "#page1", function(){
$(".filter-menu").selectmenu( "refresh", true );
});
The correct syntax for the listviewcreate event is:
$( ".selector" ).on( "listviewcreate", function( event ) {} );
In the listviewcreate event i changed the id's to classes and initiated the listbox
listbox = $("<ul class='.filter-menu-listbox'></ul>");
I hope i could help you and sry for my bad english :)
You are running into problems because with multiple selectmenus you are using class names and no ids.
Give your selectmenus unique ids as well as the common class name. For the listviewcreate you can use the classnames and find other dom elements using closest()/find().etc.
$.mobile.document.on("listviewcreate", ".ui-selectmenu-list", function (e) {
var input,
listbox = $(this).closest(".ui-selectmenu"),
form = listbox.jqmData("filter-form"),
listview = $(this);
if (!form) {
input = $("<input data-type='search'></input>");
form = $("<form></form>").append(input);
input.textinput();
listbox
.prepend(form)
.jqmData("filter-form", form);
}
listview.filterable({
input: input
});
})
In the case of a long list showing as a dialog. I am retrieving the base ID of the selectmenu and then using it to build selectors as needed:
.on("pagebeforeshow pagehide", ".ui-selectmenu.ui-dialog", function (e) {
var id=$(this).prop("id").replace("-dialog","");
var form = $("#" + id + "-listbox").jqmData("filter-form"),
placeInDialog = (e.type === "pagebeforeshow"),
destination = placeInDialog ? $(this).find(".ui-content") : $("#" + id + "-listbox");
form.find("input")
// Turn off the "inset" option when the filter input is inside a dialog
// and turn it back on when it is placed back inside the popup, because
// it looks better that way.
.textinput("option", "inset", !placeInDialog)
.end()
.prependTo(destination);
});
Updated FIDDLE
Related
Goal: Have a select whose option have nested structure when user clicks on the select, but when user selects an option the option should be displayed "normally" (ie with no leading spaces).
Attempted solution using JS and Jquery: My JS is far from sophisticated so I apologize in advance :)
I attempted to use .on("change") and .on("click") to change the selected option value (by calling .trim() since I achieve the "nested" structure with ). I'm also storing the original value of the selected option because I want to revert the select menu to its original structure in case the user selects another option.
The problem: The function registered for .on("click") is called twice, thus the select value immediately resets itself to its original value.
I suspect there is a much, much easier solution using CSS. I will be happy to accept an answer that will suggest such solution.
JSFiddle: https://jsfiddle.net/dv6kky43/9/
<form>
<select id="select">
<option value=""></option>
<option value="a"> a</option>
<option value="b"> b</option>
</select>
</form>
<textarea id="output"/>
var orig;
var output = $("#output");
output.val("");
function onDeviceSelection(event){
output.val(output.val() + "\nonDeviceSelection");
var select = event.target;
orig = select.selectedOptions[0].text;
select.selectedOptions[0].text = select.selectedOptions[0].text.trim()
}
function resetDeviceSelectionText(event) {
output.val(output.val() + "\nresetDeviceSelectionText");
var select = event.target;
if (orig !== undefined){
select.selectedOptions[0].text = orig;
}
}
$("#select").on("change", onDeviceSelection);
$("#select").on("click", resetDeviceSelectionText);
If you are already using jQuery, why not utilize data function to store the original value. This way you will also be able to specify different nest levels.
(function($){
$(document).on('change', 'select', function(event) {
$(this).find('option').each(function(index, element){
var $option = $(element);
// Storing original value in html5 friendly custom attribute.
if(!$option.data('originalValue')) {
$option.data('originalValue', $option.text());
}
if($option.is(':selected')) {
$option.html($option.data('originalValue').trim());
} else {
$option.html($option.data('originalValue'));
}
})
});
})(jQuery);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
<select id="select">
<option value=""></option>
<option value="a"> a</option>
<option value="b"> b</option>
</select>
</form>
Once caveat I see is, the selected option will appear trimmed on the list as well, if dropdown is opened after a previous selection has been made:
Will it still work for you?
Instead of keeping the state of the selected element i would simply go over all options and add the space if that option is not selected:
function onDeviceSelection(event){
// Update textarea
output.val(output.val() + "\nonDeviceSelection");
// Higlight the selected
const {options, selectedIndex} = event.target;
for(let i = 0; i < options.length; i++)
options[i].innerHTML = (i === selectedIndex ? "":" ") + options[i].text.trim();
}
$("#select").on("change", onDeviceSelection);
Note that you need to use innerHTML to set the whitespace...
I have an array of select boxes, with a class "taskcompleted". I want to be able to do something when a box is changed.
<select class = "taskcompleted" >
<option value="No">No</option>
<option value="Yes">Yes</option>
</select>
I have used this javascript code
function initselects() {
var myselects = $('.taskcompleted');
myselects.each( function(){ // any select that changes.
console.log( $(this).val() );
}).change();
}
When the page loads, it is logging a change for each select box. I do not want this to happen. I want to only log a change after the page as has loaded.
You can use change() to attach the event to each select, like this:
function initselects() {
$('.taskcompleted').change(function() {
console.log($(this).val());
});
}
Something like this you mean? This will add change handlers to all selects with class taskcompleted
The problem you have it that you're adding .change() to the end which actually triggers the change you don't want to happen - so instead, just listen for it
function initselects() {
$('select.taskcompleted').on('change', function() {
// do something
});
}
If you don't want the logging at page load, then simply remove change() from the end.
In general you can use it like that
JavaScript:
var myselects = $('.taskcompleted');
myselects.change( function(){
console.log($(this).attr('name') + ': ' + $(this).val() );
});
HTML:
<select name="1stselectbox" class = "taskcompleted" >
<option value="No">No</option>
<option value="Yes">Yes</option>
</select>
<select name="2ndselectbox" class = "taskcompleted" >
<option value="Maybe">Maybe</option>
<option value="dontknow">I don't know</option>
</select>
So you set the change listener directly on the jQuery objects, no need to use a loop (each). The example above will even print which select box was selected (might be useful). E.g. the output will be when changing the first box to Yes: 1stselectbox: Yes
JSFiddle: https://jsfiddle.net/x8jwy92h/
In my application, I want to let user select an option from the drop down menu at anytime. But when the page reloads, it goes back to the default value (the first element in the drop down list).
My HTML looks like this:
<select class="author">
<option value="aaa">aaa</option>
<option value="bbb">bbb</option>
<option value="ccc">ccc</option>
</select>
In my javascript, i use the following for letting the user select an option:
auid = $('#tabs' .author option:selected').prop('value');
I am actually retrieving the value of author that was selected before page reloads from the localstorage by:
auid = localStorage.getItem("latestAuthor");
Can someone tell me how does this all fit together with example code snippet to let me select an option from drop down menu, and the same option stays selected when the page reloads, but the user can select another option from the drop down menu at anytime as well.
On page load, once that select box exists, and once you've retrieved auid from local storage, do this:
if (auid !== null) {
$("#tabs .author").val(auid);
}
The if is there because if you've never set the value in local storage, that's what you'll get back from getItem.
Side note: When getting the value, don't use prop('value'). Use .val:
auid = $("#tabs .author").val();
Complete example on jsFiddle (since Stack Snippets don't allow local storage ☹ ). This assumes it's in a script tag at the end of the HTML, just before the closing </body> tag (which is where you should put them unless you have a good reason not to).
// Scoping function to avoid global vars
(function() {
var auid = localStorage.getItem("latestAuthor");
if (auid !== null) {
$("#tabs .author").val(auid);
}
$("#tabs .author").on("change", function() {
auid = $(this).val();
localStorage.setItem("latestAuthor", auid);
});
})();
If for some reason you can't put the script tag at the very end, you can use jQuery's "DOM ready" callback:
jQuery(function() {
var auid = localStorage.getItem("latestAuthor");
if (auid !== null) {
$("#tabs .author").val(auid);
}
$("#tabs .author").on("change", function() {
auid = $(this).val();
localStorage.setItem("latestAuthor", auid);
});
});
(You can cache the result of $("#tabs .author") in a variable if you want to avoid doing it twice, but doing it twice on page load is nothing.)
Works fine for me.
Possible typo error
auid = $('#tabs' .author option:selected').prop('value');
^
Sample:
$(".btn").on("click", function() {
var auid = $('#tabs .author option:selected').prop('value');
console.log(auid);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div id="tabs">
<select class="author">
<option value="aaa">aaa</option>
<option value="bbb">bbb</option>
<option value="ccc">ccc</option>
</select>
</div>
<button class="btn">Click Me</button>
Also for sample of integrating with LocalStorage, check following code:
Note: Stackoverflow does not allows to access localStorage and you should test it on fiddle.
JSFiddle
var _lsKey = "test";
function registerEvents(){
$(".btn").on("click", function() {
var auid = $('#tabs .author option:selected').prop('value');
saveValueToLS(_lsKey, auid);
});
}
function saveValueToLS(key, value){
localStorage.setItem(key, value);
}
function getValueFromLS(key){
return localStorage.getItem(key);
}
function initializeSelect(){
var lsVal = getValueFromLS(_lsKey);
$(".author").val(lsVal);
}
function initializePage(){
registerEvents();
initializeSelect();
}
initializePage();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div id="tabs">
<select class="author">
<option value="aaa">aaa</option>
<option value="bbb">bbb</option>
<option value="ccc">ccc</option>
</select>
</div>
<button class="btn">Click Me</button>
I applied the modal function I found in this article. It is a jQuery modal that puts the source file in an <iframe> and display as modal. Now, the problem is that I need to return to value to the background page from the modal after the user selected an item.
Here is some jQuery code: (This is were the page is loaded)
var openMyModal = function(source)
{
modalWindow.windowId = "myModal";
modalWindow.width = 480;
modalWindow.height = 405;
modalWindow.content = "<iframe width='480' height='405' frameborder='0' scrolling='no' allowtransparency='true' src='" + source + "'></iframe>";
modalWindow.open();
};
Posible code in Modal:
<select name="selItem">
<option value="item1">Item 1</option>
<option value="item2">Item 2</option>
<option value="item3">Item 3</option>
<option value="item4">Item 4</option>
</select>
<input type="button" id="btnSel" name="btnSel" value="Select" />
There is a button in the modal display which when clicked, it will pass the value to an input text back to the background page then remove the modal.
How can I achieve this? Thank you very much!
Possible solution is to add click listener on the button of the model after it opens. here is some code:
modalWindow.open(function()
{
//callback
$('#btnSel').on('click', function()
{
//do what you need here.
});
});
Note:
Make sure there is some way to run a callback function like I suggested.
from the documentation you can add your logic in the open option:
var modalWindow = {
....
open:function()
{
//your stuff - click listener
}
};
I have a form that has two drop down fields lets say A is one and B is another. I want the drop down box B to be disabled until one of the value in the drop down A is selected .
How should I write a Java script?
Use the onchange event of dropdown A to check it's value and change the disabled property of dropdown B:
document.getElementById("dropdown_A").onchange = function ()
{
if (this.selectedIndex == 2) // if the 3rd option is selected
document.getElementById("dropdown_B").disabled = true;
}
Note this code needs to run after the dropdown A element (or the entire document) has been parsed.
For your dropdown_b, make the disabled property = "disabled"
for your dropdown_a, make the onchange to a function that will change dropdown_b's disabled property.
<html>
<head>
window.onload = function()
{
dda = document.getElementById("dropdown_A");
ddb = document.getElementById("dropdown_b");
dda.onchange = function()
{
if(dda.options[dda.selectedIndex] != "")
ddb.disabled = "";
};
}
</head>
<body>
<select id="dropdown_A">
<option value="" selected="selected"></option>
<option value="asdf">asdf</option>
<option value="12345">12345</option>
</select>
<select id="dropdown_B">
..
</select>
</body>
</html>
Basically, until the user selects an actual option nothing will happen... so the blank option [""] won't deselect the other select.