Last active
April 21, 2022 01:37
-
-
Save jlainezs/5ae009d230eb39fa4393034076059b19 to your computer and use it in GitHub Desktop.
Joomla 3.X custom field which implements chained dropdown controls with ajax autocomplete capabilities.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* You should have received a copy of the GNU General Public License | |
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |
* | |
* @author Pep Lainez <[email protected]> | |
* @copyright Copyright (C) 2018 CloudConceptes | |
* @license GNU/GPL https://www.gnu.org/licenses/gpl-3.0.html | |
*/ | |
defined('JPATH_PLATFORM') or die; | |
JFormHelper::loadFieldClass('list'); | |
/** | |
* Base class. | |
* Strictly not needed, but it allows to focus important tasks in descendants. | |
*/ | |
abstract class BasicFormFieldList extends JFormFieldList | |
{ | |
protected $placeholder = false; | |
protected $style; | |
/** | |
* Gets the data | |
* | |
* @return mixed | |
* | |
* @since version | |
*/ | |
protected function getDbOptions() | |
{ | |
return []; | |
} | |
/** | |
* Gets the options | |
* | |
* @see JFormFieldList::getOptions() | |
* | |
* @return array | |
*/ | |
protected function getOptions() | |
{ | |
$options = parent::getOptions(); | |
$dbOptions = $this->getDbOptions(); | |
if (count($dbOptions)) | |
{ | |
foreach ($dbOptions as $dbOption) | |
{ | |
$tmp = JHtml::_('select.option', $dbOption->id, $dbOption->title); | |
$options[] = $tmp; | |
} | |
} | |
return $options; | |
} | |
/** | |
* Method to attach a JForm object to the field. | |
* | |
* @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. | |
* @param mixed $value The form field value to validate. | |
* @param string $group The field name group control value. This acts as as an array container for the field. | |
* For example if the field has name="foo" and the group value is set to "bar" then the | |
* full field name would end up being "bar[foo]". | |
* | |
* @return boolean True on success. | |
* | |
* @since 11.1 | |
*/ | |
public function setup(\SimpleXMLElement $element, $value, $group = null) | |
{ | |
$this->style = (isset($element['style']) ? (string) $element['style'] : ''); | |
return parent::setup($element, $value, $group); // TODO: Change the autogenerated stub | |
} | |
/** | |
* Method to get the field input markup. | |
* | |
* @return string The field input markup. | |
* | |
* @since 11.1 | |
*/ | |
protected function getInput() | |
{ | |
$attr = ''; | |
// Initialize some field attributes. | |
$attr .= !empty($this->class) ? ' class="' . $this->class . '"' : ''; | |
$attr .= $this->disabled ? ' disabled' : ''; | |
$attr .= !empty($this->size) ? ' size="' . $this->size . '"' : ''; | |
$attr .= $this->multiple ? ' multiple' : ''; | |
$attr .= $this->required ? ' required aria-required="true"' : ''; | |
$attr .= $this->autofocus ? ' autofocus' : ''; | |
$attr .= !empty($this->style) ? ' style="' . $this->style . '"' : ''; | |
if ($this->getAttribute('placeholder')) | |
{ | |
$attr .= ' data-placeholder = "' . JText::_($this->getAttribute('placeholder')) . '"'; | |
} | |
// Initialize JavaScript field attributes. | |
$attr .= $this->onchange ? ' onchange="' . $this->onchange . '"' : ''; | |
// Get the field options. | |
$options = $this->getOptions(); | |
return JHtml::_('select.genericlist', $options, $this->name, trim($attr), 'value', 'text', $this->value, $this->id); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* You should have received a copy of the GNU General Public License | |
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |
* | |
* @author Pep Lainez <[email protected]> | |
* @copyright Copyright (C) 2018 CloudConceptes | |
* @license GNU/GPL https://www.gnu.org/licenses/gpl-3.0.html | |
*/ | |
defined('JPATH_PLATFORM') or die; | |
use \Joomla\CMS\Factory; | |
require_once __DIR__ . '/basicformfieldlist.php'; | |
/** | |
* Form Field class for chaining drop downs | |
* | |
* @since 1.0.1 | |
*/ | |
class FormFieldChainedList extends BasicFormFieldList | |
{ | |
protected $placeholder = false; | |
protected $watch = ''; | |
protected $option = ''; | |
protected $task = ''; | |
protected $format; | |
/** | |
* Configures the control | |
* | |
* @param SimpleXMLElement $element | |
* @param mixed $value | |
* @param null $group | |
* | |
* @return bool | |
* | |
* @since 1.0.1 | |
* @throws Exception | |
*/ | |
public function setup(\SimpleXMLElement $element, $value, $group = null) | |
{ | |
$input = Factory::getApplication()->input; | |
$this->watch = ((isset($element['watch']) && !empty($element['watch'])) ? (string) $element['watch'] : ''); | |
$this->option = (isset($element['option']) ? (string) $element['option'] : $input->get('option')); | |
$this->task = (isset($element['task']) ? (string) $element['task'] : ''); | |
$this->format = (isset($element['format']) ? (string) $element['format'] : ''); | |
return parent::setup($element, $value, $group); | |
} | |
private static $commonScriptsLoaded = false; | |
protected function getInput() | |
{ | |
$watch_at = '#' . $this->watch; | |
$me = '#' . $this->id; | |
if (!self::$commonScriptsLoaded) | |
{ | |
self::$commonScriptsLoaded = true; | |
Factory::getDocument()->addScriptDeclaration(' | |
function chainedlist_updateValues(who, data, fullUpdate) | |
{ | |
jQuery(who).children("option:not(:selected)").remove(); | |
jQuery(who).prop("selectedIndex", -1); | |
for (i=0; i < data.length; i++){ | |
let option = jQuery("<option>").prop("value", data[i].id).html(data[i].title); | |
jQuery(who).append(option); | |
} | |
let ChosenInputValue = jQuery(who + "_chzn input").val(); | |
jQuery(who).trigger("liszt:updated"); | |
jQuery(who + "_chzn input").val(ChosenInputValue); | |
jQuery(who + "_chzn").removeClass("chzn-container-single-nosearch"); | |
jQuery(who + "_chzn input").prop("readonly", false); | |
} | |
function chainedlist_getItems(me, selected_value, option, task, initial_value, like, format, token){ | |
jQuery.ajax({ | |
url: "index.php?" + token + "=1", | |
data:{ | |
option : option, | |
task : task, | |
parent_value : selected_value, | |
initial_value : initial_value, | |
like : like, | |
format : format, | |
}, | |
method: "get", | |
dataType: "json" | |
}) | |
.done(function(data, textStatus, xhqr){ | |
chainedlist_updateValues(me, data); | |
}); | |
} | |
function prepareUpdateFor(who){ | |
jQuery(who).on("change", function(){ | |
jQuery(document).trigger("update_chained", who); | |
}); | |
} | |
'); | |
} | |
$script = ' | |
jQuery(document).ready(function(){ | |
let token = "' . JSession::getFormToken() . '";'; | |
if (!empty($this->watch)) | |
{ | |
$script .= ' | |
prepareUpdateFor("' . $watch_at . '"); | |
jQuery(document).on("update_chained", function(e, sender){ | |
let selected_value = jQuery("' . $watch_at . '").val(); | |
if (sender !== "' . $watch_at . '") return; | |
chainedlist_getItems( | |
"' . $me . '", | |
selected_value, | |
"' . $this->option . '", | |
"' . $this->task . '", | |
' . (int) $this->value . ', | |
"", | |
"json", | |
token | |
); | |
});'; | |
} | |
else | |
{ | |
$script .= 'let selected_value = 0;'; | |
} | |
$script .= ' | |
let timeOut'.$this->id.' = null; | |
jQuery("' . $me . '_chzn input").on("keyup", function(e){ | |
let like = jQuery(this).val(); | |
let selected_value = jQuery("' . $watch_at . '").val(); | |
clearTimeout(timeOut'.$this->id.'); | |
timeOut'.$this->id.' = setTimeout(function(){ | |
chainedlist_getItems( | |
"' . $me . '", | |
selected_value, | |
"'. $this->option .'", | |
"' . $this->task . '", | |
' . (int) $this->value . ', | |
like, | |
"json", | |
token | |
); | |
}, 350); | |
}); | |
jQuery("' . $me . '").chosen({disable_search_threshold : 0}).trigger("liszt:updated"); | |
jQuery("' . $me . '_chzn").removeClass("chzn-container-single-nosearch"); | |
jQuery("' . $me . '_chzn input").prop("readonly", false); | |
});'; | |
Factory::getDocument()->addScriptDeclaration($script); | |
return parent::getInput(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<form> | |
<fieldset name="COM_MM_DETAILS" addfieldpath="administrator/components/com_yourcomponent/models/fields"> | |
<field name="country_id" type="country" | |
label="COM_MM_COUNTRY_LABEL" | |
description="COM_MM_PROVINCE_COUNTRY_TITLE_DESCR" | |
option="com_yourcomponent" | |
task="the_controller.ajaxsearch" | |
format="json" | |
class="inputbox input-medium" required="true"> | |
</field> | |
<field name="province_id" type="province" | |
watch="jform_country_id" | |
label="COM_MM_PROVINCE_TITLE_LABEL" | |
description="COM_MM_CITY_PROVINCE_TITLE_DESCR" | |
option="com_yourcomponent" | |
task="anothercontroller.ajaxsearch" | |
format="json" /> | |
<field name="city_id" type="city" | |
watch="jform_province_id" | |
label="COM_MM_CITY_TITLE_LABEL" | |
description="COM_MM_CITY_PROVINCE_TITLE_DESCR" | |
option="com_yourcomponent" | |
task="evenanothercomponent.ajaxsearch" | |
format="json" /> | |
</fielfset> | |
</form> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment