diff --git a/README.md b/README.md index 2f13e5d..64d388a 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ Register provider and facade on your config/app.php file. This is necessary for The jQuery code required by this package is in the file multiselect.js. If you use Laravel Mix, you can include it in your mix.js. Otherwise, copy it to your public folder and source it directly in the app layout. -Remember to do it after you include jquery. +Remember to do it after you include jQuery. Example: @@ -152,6 +152,11 @@ of the `span` function (strict mode). ) !!} ``` +(4) You can also use an autocomplete input instead of a select element! To do so, import +[devbridge's Autocomplete plugin](https://github.com/devbridge/jQuery-Autocomplete), replace the calls to +`Multiselect::select()` to `Multiselect::autocomplete()`, and include a `Multiselect::scripts()` call after +jQuery is loaded. + ## Change log Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. diff --git a/resources/assets/js/multiselect.js b/resources/assets/js/multiselect.js index 75f2590..e19a78f 100644 --- a/resources/assets/js/multiselect.js +++ b/resources/assets/js/multiselect.js @@ -4,8 +4,8 @@ $(document).ready(function(){ // The elements are tied by the NAME, CLASS AND ID attributes, use them as // span: ID specialist-span // select: ID specialist-ms CLASS .multiselect - // inputs: ID specialists[] NAME specialist[] CLASS .multiselector - $(".multiselect").change(function() + // inputs: ID specialist[] NAME specialist[] CLASS .multiselector + $("select.multiselect").change(function() { var $name = $(this).attr('id'); $name = $name.substring(0, $name.length-3); @@ -20,4 +20,46 @@ $(document).ready(function(){ $(this).find('option:selected').text() + ''); } }); + // chainable custom autocomplete with some global defaults + $.fn.lmsAutocomplete = function(url, params) { + // forces the tied-together names (input, span, hidden inputs) + var name = $(this).attr('id'); + name = name.substring(0, name.length-3); + // provides some default parameters + var autocomplete_params = { + serviceUrl: url, + onSelect: function (suggestion) { + var $span = $("#" + name + "-span"); + if ( $(this).val() === "") { + return; + } + if ($span.find('input[value=' + suggestion.data + ']').length == 0) { + $span.append('' + + ' ' + + suggestion.value + ''); + } + }, + minChars: 3, + onSearchStart: function() { + $(".minispinner").remove(); + $(this).after("
"); + }, + onSearchComplete: function() { + $(".minispinner").remove(); + } + }; + // Merges the received params + if (typeof params === "object") { + // this is probably intended: + if (typeof params.noSuggestionNotice !== "undefined") { + params.showNoSuggestionNotice = true; + } + autocomplete_params = Object.assign(autocomplete_params, params); + } + if (!$.fn.devbridgeAutocomplete) { + throw 'Library laravel-multiselect is using autocomplete, but devbridgeAutocomplete is not available!'; + } + return this.devbridgeAutocomplete(autocomplete_params); + }; }); diff --git a/src/Multiselect.php b/src/Multiselect.php index 823cd3d..9fd70e6 100644 --- a/src/Multiselect.php +++ b/src/Multiselect.php @@ -140,6 +140,65 @@ protected function option($display, $value, array $attributes = []) return $this->toHtmlString(''); } + /** + * Create the multi-select autocomplete field and optionally the already selected span field. + * This method interface mimicks LaravelCollective\html select method. + * + * @param string $name The name of the select element. Will be used by the JS to add hidden inputs + * @param array $list A Laravel collection or list of key => values + * @param array $selected A laravel collection or list of keys + * @param array $inputAttributes + * @param array $spanAttributes + * @param boolean $inputOnly + * + * @return \Illuminate\Support\HtmlString + */ + public function autocomplete( + $name, + $list = [], + $selected = [], + array $inputAttributes = [], + array $spanAttributes = [], + $inputOnly = false + ) { + // Forces the ID attribute + $inputAttributes['id'] = $name . "-ms"; + if (!isset($inputAttributes['class'])) { + $inputAttributes['class'] = "multiselect"; + } + + // We will concatenate the span html unless $selectOnly is passed as false + $spanHtml = $inputOnly ? "" : $this->span($name, $list, $selected, $spanAttributes); + + $inputAttributes = $this->attributes($inputAttributes); + + return $this->toHtmlString($spanHtml . ""); + } + + /** + * Create the javaScript scripts required for the multi-select autocomplete plugin. + * Notice that this should be called *after* jQuery has been imported + * + * @param string $name The name of the select element. + * @param string $url The URL to be used for getting the autocomplete responses + * @param array $params Further parameters to be passed to devbridgeAutocomplete + * + * @return \Illuminate\Support\HtmlString + */ + public function scripts( + $name, + $url, + array $params = [] + ) { + $inputName = $name . "-ms"; + + return $this->toHtmlString( + ''); + } + /** * Create the multi-select select box field and optionally the already selected span field. * This method interface mimicks LaravelCollective\html select method. diff --git a/tests/MultiselectTest.php b/tests/MultiselectTest.php index b6cbf9e..391d363 100644 --- a/tests/MultiselectTest.php +++ b/tests/MultiselectTest.php @@ -112,4 +112,31 @@ public function testSelectWithPlaceholder() $element = $select->select('name', [], [], ['placeholder' => 'placeholder-text'], [], [], true)->toHtml(); $this->assertSame('', $element); } + + ///////////////////////////////////////////////// + // Tests for generating the autocomplete input // + ///////////////////////////////////////////////// + public function testInputEmpty() + { + $select = new Multiselect(); + $element = $select->autocomplete('name', [], [], [], [], true)->toHtml(); + $this->assertSame('', $element); + } + + /////////////////////////////////////////////////// + // Tests for generating the autocomplete scripts // + /////////////////////////////////////////////////// + public function testScriptsSimple() + { + $select = new Multiselect(); + $element = $select->scripts('name', 'http://url/', [])->toHtml(); + $this->assertSame('', $element); + } + + public function testScriptsParams() + { + $select = new Multiselect(); + $element = $select->scripts('name', 'http://url/', ['minChars' => 5, 'showNoSuggestionNotice' => true])->toHtml(); + $this->assertSame('', $element); + } }