How to add a datalist to an input form

asinkan
Member | 38
+
0
-

Hi,

I have a form in my presenter

protected function createComponentPickChildForm()
	{
		$form = new Form;
		$form->addText('child', 'Dítě:')
			->setRequired('Prosím vyplňte jméno.');

		$form->addProtection();
		return $form;
	}

how can I add there a datalist? Like in HTML:

 <input list="browsers">

<datalist id="browsers">
  <option value="Internet Explorer">
  <option value="Firefox">
  <option value="Chrome">
  <option value="Opera">
  <option value="Safari">
</datalist>

The question is: How to add attribute list=“browsers” to my input form. I can do other things in default.latte
Thx very much
++++++++++++++++++++++++++++++++++++++++++++++
OK I found nice solution. Everything is in the presenter

		$form->addText('userId', 'Rodič (Parent):')->setRequired('Prosím vyplňte rodiče. (Please select the parent).')
				->setAttribute('list', 'parentList')
				->setAttribute('autocomplete', 'off');
		$parents = $this->userRepository->findAllActiveUsers();
		$dataList = Html::el('datalist id="parentList"');
		foreach ($parents as $value) {
			$dataList->create('option value="'.$value->lastname.' '.$value->firstname.'"');
		}
		echo $dataList;

Do not forget to add

use Nette\Utils\Html;

Last edited by asinkan (2018-11-27 23:17)

Ondřej Kubíček
Member | 494
+
+1
-

nette doesnt support datalist, so the eastest way is manual rendering

<form n:name="pickChildForm">
 <input list="browsers" n:name="child">

<datalist id="browsers">
  <option value="Internet Explorer">
  <option value="Firefox">
  <option value="Chrome">
  <option value="Opera">
  <option value="Safari">
</datalist>
</form>
Martin
Member | 171
+
+1
-

Simpliest way, usable to standard renderer:

<?php
class DataList extends Nette\Forms\Controls\BaseControl
{
	protected $values;

	public function __construct($label = NULL, $values = NULL)
	{
		parent::__construct($label);
		$this->values = $values;
	}

    function getControl()
    {
		$datalist = Nette\Utils\Html::el('datalist')->addAttributes([
			'id' => $this->getHtmlId(),
		]);
		foreach ($this->values as $value) {
			$datalist->addHtml(Nette\Utils\Html::el('option')->addAttributes([
					'value' => $value,
				])
			);
		}
		return $datalist;
    }
}

Nette\Object::extensionMethod('Nette\Forms\Container::addDataList', function($form, $name, $values = NULL){
    $form[$name] = new DataList(NULL, $values);
    return $form[$name];
});

Nette\Object::extensionMethod('Nette\Forms\Container::addDataListWithVisibleLabel', function($form, $name, $label = NULL, $values = NULL){
    $form[$name] = new DataList($label, $values); // for testing only ...
    return $form[$name];
});
?>

Using:

<?php
			$dataList = $form->addDataList('dataListExample', ['Value 1', 'Value 2']);
			$form->addText('textWithDataList', 'Text with DataList')
				->setAttribute('list',$dataList->getHtmlId());
?>

Result:
Nette DataList example

You can also add extension method addDataList to TextBox or method to its descendant.
Or define class TextBoxWithDatalist, but one DataList belongs to one TextBox in this case, which could not be right way.
Or use more complex solution by deep Nette OOP and DI, but they are more desirable ones to do it then me.

Last edited by Martin (2018-01-25 22:06)

David Matějka
Moderator | 6445
+
+2
-

@Martin the way you are building the html is insecure and may result in xss. you should at least use Nette\Utils\Html

Martin
Member | 171
+
0
-

David Matějka wrote:

@Martin the way you are building the html is insecure and may result in xss. you should at least use Nette\Utils\Html

Thank you. I am sorry, I din not use Nette last 6 years. Do you mean to check $value only, or full result, or another way? I will repaire code above.

David Matějka
Moderator | 6445
+
+2
-

@Martin yes, i mean $value. it should look like this:

$datalist = Nette\Utils\Html::el('datalist')->addAttributes([
	'id' => $this->getHtmlId(),
]);
foreach ($this->values as $value) {
	$datalist->addHtml(Nette\Utils\Html::el('option')->addAttributes([
		'value' => $value,
	]);
}
Martin
Member | 171
+
0
-

Thanks, I repaired a code. Hovewer, cutting off is not working probably in <?php code ?> here, then I removed wrong code part. I will try it when I am near my computer.

After adding one parenthesis the code is working. Thank you for the correction.

Last edited by Martin (2018-01-25 22:35)