Yii 1.1: ajaxdropdown

Yii 1.1 dropdown widget with AJAX data
5 followers

AjaxDropDown allows to use dropdown menu to select one or more values in your form. Dropdown data is sent using the AJAX post method.

This widget is designed to be used with Bootstrap CSS although the option to switch it off is given ('bootstrap' => false). In case you don't want to use Bootstrap make sure to set the proper event for the AJAX data collecting ('triggerEvent').

The widget was not tested with Yiistrap, YiiBooster or any other Yii Bootstrap 3rd party library.

AjaxDropDown preview

How it works

The widget collects AJAX data and displays it as the list where every element can be clicked to select that value for the model attribute. The number of results per page is controlled by the source controller action. After first page the widget collects new page data only when the 'next' button is clicked and that target page has not been collected already. In any other case the data is present all the time and browsing through the already loaded pages takes no server time. The idea behind the input text field next to the dropdown button is to give the option to filter the source data before displaying it in the widget but there are no requirements for this so feel free to add any logic here you like.

How to install

Copy the AjaxDropDown folder to your /protected/extensions Yii folder. Then add the following inside your form view:

<?php $this->widget('ext.AjaxDropDown.AjaxDropDown', array(
  'model' => $model,
  'attribute' => 'attribute',
  'source' => $this->createUrl('controller/action'),
)); ?>

Where $model is your CModel object, 'attribute' is object's attribute and data source URL is 'controller/action'. This is just a basic widget configuration. You can find all the options described in the AjaxDropDown.php.

Full widget structure with possible options

<div id="[WIDGET_ID]" class="ajaxDropDownWidget {mainClass}" {style="{mainStyle}"}>
    <div class="ajaxDropDown {groupClass}" {style="{groupStyle}"}>
        <input type="text" name="ajaxDropDownInput" value="" class="{inputClass}" {style="{inputStyle}"}>
        <div class="{buttonsClass}" {style="{buttonsStyle}"}>
            {<button type="button" {extraButtonHtmlOptions}>{extraButtonLabel}</button>}
            <button data-page="[DATA_PAGE]" data-toggle="dropdown" type="button" class="ajaxDropDownToggle {buttonClass}" {style="{buttonStyle}"}>
                {buttonLabel}
            </button>
            <ul role="menu" class="ajaxDropDownMenu {resultsClass}" {style="{resultsStyle}"}>
                <li class="dropdown-header {headerClass}" {style="{headerStyle}"}>
                    {pagerBegin}
                        <span class="ajaxDropDownPageNumber">[CURRENT_PAGE_NUMBER]</span>/<span class="ajaxDropDownTotalPages">[TOTAL_PAGES_NUMBER]</span>
                    {pagerEnd}{local.allRecords|local.recordsContaining}
                </li>
                <li class="divider"></li>
                <li class="ajaxDropDownLoading {loadingClass}" {style="{loadingStyle}"}>{progressBar}</li>
                <li class="dropdown-header {errorClass}" {style="{errorStyle}"}>{local.error}</li>
                <li class="dropdown-header {noRecordsClass}" {style="{noRecordsStyle}"}>{local.noRecords}</li>
                <li class="ajaxDropDownPages ajaxDropDownPage[PAGE_NUMBER] ajaxDropDownRecord[RECORD_ID] {recordClass}" {style="{recordStyle}"}>
                    <a data-id="[RECORD_ID]" class="ajaxDropDownResult" href="#">{markBegin}[RECORD_VALUE]{markEnd}</a>
                </li>
                <li class="divider ajaxDropDownInfo"></li>
                <li class="ajaxDropDownInfo {switchClass}" {style="{switchStyle}"}>
                    <a class="ajaxDropDownPrev {previousClass}" {style="{previousStyle}"} href="#">
                        {previousBegin}{local.previous}{previousEnd}
                    </a>
                    <a class="ajaxDropDownNext {nextClass}" {style="{nextStyle}"} href="#">
                        {nextBegin}{local.next}{nextEnd}
                    </a>
                </li>
            </ul>
        </div>
    </div>
    <ul class="ajaxDropDownResults {selectedClass}" {style="{selectedStyle}"}>
        <li class="ajaxDropDownSelected[SELECTED_ID] {resultClass}" {style="{resultStyle}"}>
            <a class="ajaxDropDownRemove {removeClass}" {style="{removeStyle}"} href="#" data-id="[SELECTED_ID]">
                {removeLabel}
            </a>{markBegin}[SELECTED_VALUE]{markEnd}<input type="hidden" value="[SELECTED_ID]" name="[ATTRIBUTE_NAME]">
        </li>
    </ul>
</div>

Names in curly brackets are options and can be set as widget parameters. Names in square brackets are automatically set widget data.

AJAX data source

Below is the structure required by this widget:

array(
    'data' => array(
        array(
            'id' => RECORD_ID,
            'mark' => RECORD_EMPHASIS,
            'value' => RECORD_VALUE
        ),
        ...
    ),
    'page' => CURRENT_PAGE_NUMBER,
    'total' => TOTAL_PAGES_NUMBER
)

Where:
RECORD_ID is the record identificator,
RECORD_EMPHASIS is the 0|1 flag wheter this record value should be surrounded with {markBegin} and {markEnd},
RECORD_VALUE is the record actual value,
CURRENT_PAGE_NUMBER is the actual page number (starting from 1),
TOTAL_PAGES_NUMBER is the number of all available pages.

This should be JSON encoded. You can find the example in the example_data_source.php.

Preselected and post-validate data with PHP.

In case you want to display some records as already selected or simply just want to keep the selected data after validation you need to prepare the 'data' parameter which is the array almost identical to the source one.

array(
    array(
        'id' => RECORD_ID,
        'mark' => RECORD_EMPHASIS,
        'value' => RECORD_VALUE
    ),
    ...
)

This time the array shouldn't be encoded. Keep this structure even in case of single result.

You can find the form controller example in example_controller.php.

Preselected and post-validate data with JavaScript.

You can manipulate selected results by triggering the following events on AjaxDropDown object:

add
Add one or more results. In case the 'singleMode' is true only the last added result will be displayed.

jQuery({id or class of AjaxDropDown field}).trigger('add', [result1, result2, ...]);

With every result data being object with id, value, mark and additional properties (only id is required):

{id:1, value:"xxx", mark:0, additional:"xxx"}

removeOne
Remove one or more results.

jQuery({id or class of AjaxDropDown field}).trigger('removeOne', [id1, id2, ...]);

removeAll
Remove all results.

jQuery({id or class of AjaxDropDown field}).trigger('removeAll');

By default events (except 'removeAll') are calling callback methods onRemove and onSelect. You can change it by setting 'jsEventsCallback' to false.

Some parameters listed

  • additionalCode - allows to place additional HTML code in selected value row between removing link and value's label (you can overwrite it just for single row by adding 'additional' key in data parameter), default ''
  • debug - wheter to copy the asset file even if it has been already published before, default false (set to true if you modify js file in dev mode)
  • dropup - if set to true the dropdown menu appears above to button, default false (works only with 'bootstrap' set to true)
  • extraButtonHtmlOptions - HTML options of the extra button between input text field and triggering button, default array()
  • extraButtonLabel - HTML label for the extra button between input text field and triggering button, default ''
  • local - array of translated strings used in the widget, default array() (if not set it uses $defaultLocal English strings)
  • singleMode - wheter to set widget in mode that allows only one selected value or more, default false

You can find all the parameters listed here https://github.com/bizley-code/Yii-AjaxDropDown/blob/master/PARAMETERS.md

GitHub repo

https://github.com/bizley/Yii-AjaxDropDown

Yii2 version

For Yii2 version of this widget go to

Total 13 comments

#19706 report it
Bizley at 2015/12/21 06:27am
v1.3.1 released

Rendering preselected data issue fixed.

#19358 report it
Bizley at 2015/05/31 06:58am
1.3 released
  • Widget redesigned with new folder structure.
  • Rendered data moved from inline code to views.
  • New boolean parameter $jsEventsCallback for controlling the triggering callbacks in case of JS data manipulating.
  • New events added for JS: 'add' to add one or more selected results, 'removeOne' to remove one or more selected results and 'removeAll' to remove all results from AjaxDropDown field.
#18968 report it
Bizley at 2015/02/14 04:08pm
v1.2 released

New parameters:

  • delay integer Delay between last key pressed and dropdown list opened in milliseconds, default 300. This option works only for keyTrigger = true
  • keyTrigger boolean Wheter pressing the key in filter field should trigger the dropdown list to open, default true. This option works as intended only for bootstrap parameter set to true.
  • onRemove string JavaScript expression to be called when a result is removed from the list. Available js variables: id ID of the removed result, selection list of all selected results (after removing).
  • onSelect string JavaScript expression to be called when a result is selected from the list. Available js variables: id ID of the selected result, label label of the selected result, selection list of all selected results (after adding).
  • removeSingleClass string CSS class of the button removing the selection on singleMode in addition to 'ajaxDropDownSingleRemove'. Bootstrap adds 'btn dropdown-toggle btn-default'.
  • removeSingleLabel string HTML label of the button removing the selection on singleMode, default 'x'. Bootstrap sets '<span class="glyphicon glyphicon-remove text-danger"></span>'.
  • removeSingleStyle string Additional CSS style of the button removing the selection in singleMode, default 'display:none;'
  • singleModeBottom boolean Wheter to display singleMode result underneath the widget, default false.

For singleMode without additionalCode default render option now is to replace value of the filter input field with the selected label (in 'disabled' mode) and replace the dropdown trigger button with 'x' button. It can be switched to previous way by setting singleModeBottom to true.

#18950 report it
Bizley at 2015/02/09 03:21pm
v1.1.2 released
  • Unnecessary code removed
  • Docs synchronized with incoming Yii2 version
  • additionalCode {ID} and {VALUE} are finally replaced with the proper string by the JS side of the widget (it worked only for PHP $data side before)

Remember to remove your /assets folder to update the js file.

#18911 report it
Bizley at 2015/02/03 07:57am
v1.1.1
  • Short js option names for smaller output file.
  • Bootstrap default switchStyle is empty now and bootstrap default resultsStyle is now 'min-width:250px'.
  • additionalCode parameter default set to '' as it should be.
  • More precise jQuery selectors for better optimization.

Remember to remove your /assets folder to update the js file.

#18875 report it
Bizley at 2015/01/28 05:04am
Small fix

Small but important fix has been added. Please redownload v1.1. Sorry for the inconvenience.

#18871 report it
Bizley at 2015/01/27 04:23am
v1.1
  • New parameter added: additionalCode This allows to send additional HTML code to the selected value row between link to remove value and value's label.
  • You can set the new key element 'additional' in 'data' parameter to replace 'additionalCode' general parameter just for the given row.
#18852 report it
Bizley at 2015/01/23 09:13am
Version 1.0.4 released

Precaution for sending empty array in 'data' parameter.

#18850 report it
Bizley at 2015/01/23 05:50am
Version 1.0.3 released

Added 'minified' parameter to use minified version of js instead, default true.

#18843 report it
panzer_commander at 2015/01/21 10:21am
Very usefull extension

I have a list of genres in drop down, and it very help, to make it pretty, instead of long laundry

#18842 report it
Bizley at 2015/01/21 06:38am
v1.0.2

Version 1.0.2 released:

Additional check for preselected values is done in order to set active class on records list and prevent duplicated selection.

#18839 report it
Bizley at 2015/01/20 08:31am
re: used in master-detail form

Thanks, Daniel. I'm not sure if this widget can help you with your idea. For sure some additional work would be required in order to create the mechanism of adding new rows with 'plus' button. Originally this widget was created to select users from database with option to filter them by the name and additional button was triggering the modal form to add new user to db.

#18838 report it
Daniel at 2015/01/20 08:19am
used in master-detail form

Hi,

This is a great extension. I was wondering is that possible to use this in master-detail situation? My situation is I have a transaction with many details on it. The details required to select product name. I am thinking of using this extension to display the item name, but should set the selected product id not the name. When [+] button is pressed, it should add new detail row. Currently, I am using other extension. It works okay with 1-3 details, but for more than 3 details the time to load the page is exceeded. Do you think that I can use this extension?

TIA

Leave a comment

Please to leave your comment.

Create extension