I'm trying to create a custom select menu with filter like on the demo page:
http://demos.jquerymobile.com/1.4.5/selectmenu-custom-filter/
It works fine for short list:
But it's not working for long lists:
https://jsfiddle.net/pppzLbfu/
I keep getting the error:
SCRIPT5007: Unable to get property 'jqmData' of undefined or null reference
My full code is
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Filterable inside custom select - jQuery Mobile Demos</title>
<link rel="shortcut icon" href="../favicon.ico">
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Open+Sans:300,400,700">
<link rel="stylesheet" href="jquery.mobile/css/themes/default/jquery.mobile-1.4.5.min.css">
<link rel="stylesheet" href="jquery.mobile/_assets/css/jqm-demos.css">
<script src="jquery.mobile/js/jquery.js"></script>
<script src="jquery.mobile/_assets/js/index.js"></script>
<script src="jquery.mobile/js/jquery.mobile-1.4.5.min.js"></script>
<script>
( 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.toPage ) ) {
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 );
</script>
<style>
.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;
}
</style>
</head>
<body>
<div data-role="page" class="jqm-demos" id="pageMainForm">
<div data-role="header" class="jqm-header">
<h2><a href="../" title="jQuery Mobile Demos home"><img src="../_assets/img/jquery-logo.png" alt="jQuery Mobile"></a></h2>
<p>Demos <span class="jqm-version"></span></p>
<a href="#" class="jqm-navmenu-link ui-btn ui-btn-icon-notext ui-corner-all ui-icon-bars ui-nodisc-icon ui-alt-icon ui-btn-left">Menu</a>
<a href="#" class="jqm-search-link ui-btn ui-btn-icon-notext ui-corner-all ui-icon-search ui-nodisc-icon ui-alt-icon ui-btn-right">Search</a>
</div><!-- /header -->
<div data-role="content" class="ui-content jqm-content">
<h1>Filterable inside custom select</h1>
<div data-demo-html="true" data-demo-js="true" data-demo-css="true">
<form>
<select id="filter-menu" class="filterable-select" data-native-menu="false">
<option value="Option 1">Option 1</option>
<option value="Option 2">Option 2</option>
<option value="Option 3">Option 3</option>
<option value="Option 4">Option 4</option>
<option value="Option 5">Option 5</option>
<option value="Option 6">Option 6</option>
<option value="Option 7">Option 7</option>
<option value="Option 8">Option 8</option>
<option value="Option 9">Option 9</option>
<option value="Option 10">Option 10</option>
<option value="Option 11">Option 11</option>
<option value="Option 12">Option 12</option>
<option value="Option 13">Option 13</option>
<option value="Option 14">Option 14</option>
<option value="Option 15">Option 15</option>
<option value="Option 16">Option 16</option>
<option value="Option 17">Option 17</option>
<option value="Option 18">Option 18</option>
<option value="Option 19">Option 19</option>
<option value="Option 20">Option 20</option>
<option value="Option 21">Option 21</option>
<option value="Option 22">Option 22</option>
</select>
</form>
</div>
</div><!-- /content -->
</div><!-- /page -->
</body>
</html>
Here's the solution if you still need it: The demo itself has some errors. Here is a way to do it:
// demo-dialog is ID of selectmenu (demo) + (-dialog) which is added // by jQM dynamically upon creating a custom selectmenu
$(document).on("pagecreate", "#demo-dialog", function (e) {
var form = $("<form><input data-type='search'/></form>"),
page = $(this);
$(".ui-content", this)
.prepend(form);
form.enhanceWithin()
.on("keyup", "input", function () {
var data = $(this).val().toLowerCase();
$("li", page).addClass("ui-screen-hidden")
.filter(function (i, v) {
return $(this).text().toLowerCase().indexOf(data) > -1;
}).removeClass("ui-screen-hidden");
});
$(document).on("pagecontainerhide", function () {
$("#demo-menu li").removeClass("ui-screen-hidden");
$("input", form).val("");
});
});
For reference: https://forum.jquery.com/topic/cannot-read-property-jqmdata-of-undefined