Icons in Custom jQuery Mobile Select Menu - jquery-mobile

I'm using a custom select menu from jQuery Mobile, and I'd like to put icons into the custom pop-up menu to accompany each option. I'm applying the data-icon attribute to each option, like so:
<select name='mySelect' id='mySelect' data-icon='gear'>
<option value='0' data-icon='star'>Option 0</option>
<option value='1' data-icon='star'>Option 1</option>
<option value='2' data-icon='star' selected="selected">Option 2</option>
</select>
FWIW, I've already verified that my custom icons work in the select button itself. Am I just completely wrong in expecting icons to appear in the custom menu?

This is not supported by default but here is a quick piece of code to make it possible:
//wait for the correct page to initialize
$(document).delegate('#home', 'pageinit', function () {
//loop through each of the SELECT elements in this page
$.each($(this).find('select'), function () {
//get the ID of this select because it's menu's ID is based off of it
var currentID = this.id;
//iterate through each of the OPTION elements for this SELECT element
$.each($(this).find('option'), function (index, element) {
//if the OPTION element has the `data-icon` attribute
if ($(element).attr('data-icon') != undefined) {
//update the menu for this SELECT by adding an icon SPAN element
//to each of the OPTION elements that has a `data-icon` attribute
$('#' + currentID + '-menu').children().eq(index).find('.ui-btn-inner').append('<span class="ui-icon ui-icon-' + $(element).attr('data-icon') + ' ui-icon-shadow" />');
}
});
});
});​​
Here is a demo: http://jsfiddle.net/NHQGD/

Related

Always display placeholder select2

I would like to build a selector that displays a "Check one or more or options" placeholder and, after selecting 1-N options, the placeholder is still displayed instead of the checked results.
In short, the component should always display the placeholder, regardless of having 0, 1 or N options checked.
I have been searching but I can't find any way to do it:
Html:
<select multiple id="e1" style="width:300px">
<option value="AL">Alabama</option>
<option value="Am">Amalapuram</option>
<option value="An">Anakapalli</option>
<option value="Ak">Akkayapalem</option>
<option value="WY">Wyoming</option>
</select>
Js
$('select').select2({
placeholder: "Select a state",
templateSelection: function (data) {
return 'Select a state';
}
});
http://jsfiddle.net/91nqgkuy/2/
Finally, I have chosen to overwrite the results template and insert the desired text.
// Set the default option.
$(select, context).each(function (e) {
setTemplateResults($(this));
});
// Override select2 default work flow.
$(select, context).on('select2:select select2:unselect', function (evt) {
setTemplateResults($(this));
});
// Method.
function setTemplateResults(selector) {
let container = selector.siblings('span.select2').find('ul')
container.html('<li>' + Drupal.t('Select category(ies)') + '</li>');
}

How to pass option tags to a custom element as distributed nodes (aka <slot></slot>)

I have a web component custom element defined like so.
<template id="dropdown-template">
<select>
<slot></slot>
</select>
</template>
<script>
class Dropdown extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({mode: 'open'});
let template = document.getElementById('dropdown-template');
shadowRoot.appendChild(template.content.cloneNode(true));
}
}
customElements.define("drop-down", Dropdown);
</script>
When trying to use it, I try and pass option tags with values into the custom element.
<drop-down>
<option>one</option>
<option>two</option>
<option>three</option>
</drop-down>
This doesn't work. The select element is shown to have a <slot> element as its direct child, and it doesn't render the options. Is this not possible to do with the <select> tag?
It not possible to do it like that because the parent element of an <option> tag must be a <select> tag. So you can use with Shadow DOM because the <slot> element will break the parent/child hierachy.
Solution 1 : move elements
A workaround is to move the content of the light DOM inside the <select> element in the template.
class Dropdown extends HTMLElement {
constructor() {
super()
const shadowRoot = this.attachShadow( {mode: 'open'} )
let template = document.getElementById( 'dropdown-template' )
shadowRoot.appendChild( template.content.cloneNode(true) )
const select = shadowRoot.querySelector( 'select' )
shadowRoot.addEventListener( 'slotchange', ev => {
let node = this.querySelector( 'option' )
node && select.append( node )
} )
}
}
customElements.define("drop-down", Dropdown);
<template id="dropdown-template">
<select></select>
<slot></slot>
</template>
<drop-down>
<option>one</option>
<option>two</option>
<option>three</option>
</drop-down>
Solution 2: customized <select>
Another possibility is to avoid Shadow DOM and define your drop-down list as a customized built-in <select> element. Maybe this won't fit your needs if you want to customize the layout.
<select is="drop-down">
<option>one</option>
<option>two</option>
<option>tree</option>
</select>

Add button inside Kendo MVC DatePicker

I have a Kendo MVC DatePicker as belowed, it will render as a textbox with a button (with calendar icon) within it which can trigger the date picker UI.
In my scenario, I need to insert a button to clear the value of the textbox, just on the left of the calendar button.
What my problem is that, is it possible (and how can I) insert another custom button inside the textbox rendered?
<div class="col-md-2 ">
#(Html.Kendo().DatePicker()
.Name("InspecitonDate")
.Value(DateTime.Now.AddMonths(-3)).Format("dd/MM/yyyy")
.HtmlAttributes(new { style = "width: 100%" })
)
</div>
Kendo date picker adds attribute data-role so select all the controls through jQuery on page with attribute data-role = datepicker
<script>
$(document).ready(function () {
var dt = $("[data-role='datepicker']");
//For each control insert an icon button calling js function clearDate to clear date input
$.each(dt,
function (i, d) {
$("#" + d.id).before("<span class='fa fa-times' onclick=\"clearDate('" + d.id + "')\"></span>");
});
});
function clearDate(inputId) {
$("#"+inputId).data("kendoDatePicker").value(null);
}
I would suggest to write this code in some common js file so that all kendo date controls in every page can be changed. You may add some style too to move icon to right
.k-picker-wrap > span.fa-times {
position: absolute;
right: 35px;
top: 8px;
color:#01ace4;
cursor: pointer;
}
There is no such built-in option, so you need to do it yourself. So you need to append the needed extra button on document.ready

JQuery multiple select filter bug

I have a multiple select with a filter. Filtering works properly, but when you select a filtered item it does not change to the selected state (there is no tick in the box of the selected item).
I followed the instructions of the offical JQuery Mobile page. The only difference is that they do not use a multiple select. Is there a workaround to have the filter functionality with multiple select boxes?
JQuery Mobile filterable select
My select:
<form>
<div class="ui-field-contain">
<label for="title-filter-menu">Placeholder:</label>
<select id="title-filter-menu" multi data-native-menu="false" class="filterable-select">
<option>Select fruit...</option>
<option value="orange">Orange</option>
<option value="apple">Apple</option>
<option value="peach">Peach</option>
<option value="lemon">Lemon</option>
</select>
</div>
</form>
JS
( function( $ ) {
function pageIsSelectmenuDialog( page ) {
var isDialog = false,
id = page && page.attr( "id" );
$( ".filterable-select" ).each( function() {
if ( $( this ).attr( "id" ) + "-dialog" === id ) {
isDialog = true;
return false;
}
});
return isDialog;
}
$.mobile.document
// Upon creation of the select menu, we want to make use of the fact that the ID of the
// listview it generates starts with the ID of the select menu itself, plus the suffix "-menu".
// We retrieve the listview and insert a search input before it.
.on( "selectmenucreate", ".filterable-select", function( event ) {
var input,
selectmenu = $( event.target ),
list = $( "#" + selectmenu.attr( "id" ) + "-menu" ),
form = list.jqmData( "filter-form" );
// We store the generated form in a variable attached to the popup so we avoid creating a
// second form/input field when the listview is destroyed/rebuilt during a refresh.
if ( !form ) {
input = $( "<input data-type='search'></input>" );
form = $( "<form></form>" ).append( input );
input.textinput();
list
.before( form )
.jqmData( "filter-form", form ) ;
form.jqmData( "listview", list );
}
// Instantiate a filterable widget on the newly created selectmenu widget and indicate that
// the generated input form element is to be used for the filtering.
selectmenu
.filterable({
input: input,
children: "> option[value]"
})
// Rebuild the custom select menu's list items to reflect the results of the filtering
// done on the select menu.
.on( "filterablefilter", function() {
selectmenu.selectmenu( "refresh" );
});
})
// The custom select list may show up as either a popup or a dialog, depending on 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.
.on( "pagecontainerbeforeshow", function( event, data ) {
var listview, form;
// We only handle the appearance of a dialog generated by a filterable selectmenu
if ( !pageIsSelectmenuDialog( data.toPage ) ) {
return;
}
listview = data.toPage.find( "ul" );
form = listview.jqmData( "filter-form" );
// Attach a reference to the listview as a data item to the dialog, because during the
// pagecontainerhide handler below the selectmenu widget will already have returned the
// listview to the popup, so we won't be able to find it inside the dialog with a selector.
data.toPage.jqmData( "listview", listview );
// Place the form before the listview in the dialog.
listview.before( form );
})
// After the dialog is closed, the form containing the filter input is returned to the popup.
.on( "pagecontainerhide", function( event, data ) {
var listview, form;
// We only handle the disappearance of a dialog generated by a filterable selectmenu
if ( !pageIsSelectmenuDialog( data.prevPage ) ) {
return;
}
listview = data.prevPage.jqmData( "listview" ),
form = listview.jqmData( "filter-form" );
// Put the form back in the popup. It goes ahead of the listview.
listview.before( form );
});
})( jQuery );
CSS
.ui-selectmenu.ui-popup .ui-input-search {
margin-left: .5em;
margin-right: .5em;
}
.ui-selectmenu.ui-dialog .ui-content {
padding-top: 0;
}
.ui-selectmenu.ui-dialog .ui-selectmenu-list {
margin-top: 0;
}
.ui-selectmenu.ui-popup .ui-selectmenu-list li.ui-first-child .ui-btn {
border-top-width: 1px;
-webkit-border-radius: 0;
border-radius: 0;
}
.ui-selectmenu.ui-dialog .ui-header {
border-bottom-width: 1px;
}
I found out, that the right option is selected, but the shown selected state in the filtered list is wrong.
If you have the options
a1
b1
c2
d2
with an filter "1" you get
a1
b1
you can correctly select each of them.
If you filter "2"
you get
c2
d2
if you select c2 (which is the first option of the selected list and the third of the original list) jquerymobile tries to show selected state on the !third! option of the !filtered list". thats the bug.
However, with the basic filtered select example ist works (first one in http://view.jquerymobile.com/master/demos/selectmenu-custom-filter/)
Problem here: The filter bar (search input) is above the select Header (Closing icon + Label).

JQM Change Select icon to Notext

In trying to keep website responsive I want to hide the text from a select menu when the screen is below a certain size.
I use something similar to remove button text.
function resizeBtn() {
var activePage = $.mobile.pageContainer.pagecontainer("getActivePage");
if ($(window).width() <= 490) {
$("#opt_user_btn.ui-btn-icon-left", activePage).toggleClass("ui-btn-icon-notext ui-btn-icon-left");
$( "#storeselect", activePage ).selectmenu( "option", "iconpos", "notext" );
} else {
$("#opt_user_btn.ui-btn-icon-notext", activePage).toggleClass("ui-btn-icon-left ui-btn-icon-notext");
$( "#storeselect", activePage ).selectmenu( "option", "iconpos", "notext" );
}
}
And the html is along the lines of:
<form><select name="storeselect" id="storeselect" data-native-menu="true" data-iconpos="left" onChange="this.form.submit();" >
<option value="1">1</option>
<option value="2">2</option>
</select>
</form>
I've looked at JQM info but not figured it out yet. Help would be appreciated. Thank you. :)
Inspecting the select bar the text for the selected option is in a span tag. One solution is to add a class with opacity:0 to the span
<div id="storeselect-button" class="ui-btn ui-icon-carat-d ui-btn-icon-left ui-corner-all ui-shadow"><span>Option 1</span><select name="storeselect" id="storeselect" data-native-menu="true" data-iconpos="left">
<option value="1">Option 1</option>
<option value="2">Option 2</option>
</select></div>
Demo
http://jsfiddle.net/mjk0f0t7/
Jquery
$(window).on('resize change', function () {
if ($(window).width() <= 490) {
$("#storeselect-button").find("span").addClass("noshow")
} else {
$("#storeselect-button").find("span").removeClass("noshow");
}
});
Css
.noshow {
opacity:0;
}
To hide or style the icon also
$("#storeselect").append('<style>.ui-btn-icon-left:after{opacity:0}</style>');
Demo
http://jsfiddle.net/wuLccyda/
To add ui-btn-icon-notext class simply use addClass and refresh the select menu
$(window).on('resize', function () {
if ($(window).width() <= 490) {
$("#storeselect").addClass("ui-btn-icon-notext")
$('#storeselect').selectmenu('refresh', true);
} else {
$("#storeselect").removeClass("ui-btn-icon-notext")
$('#storeselect').selectmenu('refresh', true);
}
});
Demo
http://jsfiddle.net/ywp70xtc/

Resources