diff --git a/autocomplete/autocomplete.py b/autocomplete/autocomplete.py
index ff0b6cf..964878e 100644
--- a/autocomplete/autocomplete.py
+++ b/autocomplete/autocomplete.py
@@ -75,6 +75,8 @@ class Meta:
placeholder (str or None): The placeholder text used on the component
Defaults to None.
+ required (bool): If set the control is marked as required.
+
no_result_text (str): The string displayed when no results are found.
Defaults to "No results found."
@@ -108,6 +110,9 @@ class Meta:
# The placeholder text. (Typically something like "Type to search...")
placeholder = None
+ # If set to True the HTML control will be marked as required
+ required = False
+
# The minimum search length to perform a search and show the dropdown.
minimum_search_length = 3
@@ -428,11 +433,12 @@ def put(self, request, method):
template.render(
{
"name": self.name,
+ "required": self.required,
"no_result_text": self.no_result_text,
"narrow_search_text": self.narrow_search_text,
"route_name": self.get_route_name(),
"multiselect": self.multiselect,
- "values": self.item_values(items, True),
+ "values": list(self.item_values(items, True)),
"item": target_item,
"toggle": items,
"swap_oob": data.get("remove", False),
@@ -497,12 +503,13 @@ def get(self, request, method):
template.render(
{
"name": self.name,
+ "required": self.required,
"route_name": self.get_route_name(),
"label": self.label,
"placeholder": self.placeholder,
"multiselect": self.multiselect,
- "values": self.item_values(selected_options),
- "selected_items": selected_options,
+ "values": list(self.item_values(selected_options)),
+ "selected_items": list(selected_options),
"no_result_text": self.no_result_text,
"narrow_search_text": self.narrow_search_text,
},
@@ -527,11 +534,12 @@ def get(self, request, method):
template.render(
{
"name": self.name,
+ "required": self.required,
"no_result_text": self.no_result_text,
"narrow_search_text": self.narrow_search_text,
"route_name": self.get_route_name(),
"show": show,
- "items": items,
+ "items": list(items),
"total_results": total_results,
},
request,
diff --git a/autocomplete/static/autocomplete/css/autocomplete.css b/autocomplete/static/autocomplete/css/autocomplete.css
index 0e72f77..1b9b84c 100644
--- a/autocomplete/static/autocomplete/css/autocomplete.css
+++ b/autocomplete/static/autocomplete/css/autocomplete.css
@@ -101,6 +101,11 @@
border-radius: 0;
}
+.phac_aspc_form_autocomplete .ac_required_input {
+ opacity: 0;
+ position: absolute;
+}
+
.phac_aspc_form_autocomplete ul.ac_container li.search-indicator svg{
max-width:25px;
max-height:25px;
diff --git a/autocomplete/static/autocomplete/js/autocomplete.js b/autocomplete/static/autocomplete/js/autocomplete.js
index ae656fc..f54ed9c 100644
--- a/autocomplete/static/autocomplete/js/autocomplete.js
+++ b/autocomplete/static/autocomplete/js/autocomplete.js
@@ -7,9 +7,7 @@ function phac_aspc_autocomplete_blur_handler(name, sync=false) {
if (!sync) {
el.value = '';
} else {
- console.log('setting value!');
el.value = data_el.getAttribute('data-phac-aspc-autocomplete');
- console.log(el.value);
}
document.getElementById(name + '__items').classList.remove('show');
}
diff --git a/autocomplete/templates/autocomplete/chip.html b/autocomplete/templates/autocomplete/chip.html
index 69cd996..e59b153 100644
--- a/autocomplete/templates/autocomplete/chip.html
+++ b/autocomplete/templates/autocomplete/chip.html
@@ -6,8 +6,9 @@
{{ item.label }}
@@ -17,4 +18,4 @@
-
\ No newline at end of file
+
diff --git a/autocomplete/templates/autocomplete/component.html b/autocomplete/templates/autocomplete/component.html
index d179343..2cccb20 100644
--- a/autocomplete/templates/autocomplete/component.html
+++ b/autocomplete/templates/autocomplete/component.html
@@ -5,6 +5,7 @@
{# This code snippet loads the required CSS and JS if not already loaded. #}
diff --git a/autocomplete/templates/autocomplete/item.html b/autocomplete/templates/autocomplete/item.html
index 2d36f0c..3270cc4 100644
--- a/autocomplete/templates/autocomplete/item.html
+++ b/autocomplete/templates/autocomplete/item.html
@@ -1,16 +1,18 @@
+{% load autocomplete %}
{{ item.label }}
diff --git a/autocomplete/templates/autocomplete/textinput.html b/autocomplete/templates/autocomplete/textinput.html
index 04e0efb..f7e62e9 100644
--- a/autocomplete/templates/autocomplete/textinput.html
+++ b/autocomplete/templates/autocomplete/textinput.html
@@ -11,9 +11,12 @@
{% if not multiselect and selected_items|length == 1 %}
value="{{ selected_items.0.label }}"
{% endif %}
+ {% if selected_items|length == 0 %}
+ required
+ {% endif %}
hx-get="{% url route_name method='items' %}"
hx-trigger="keyup changed delay:250ms,click,focus,search"
- hx-include="#{{ route_name }} > input[name='{{ name }}']"
+ hx-include="#{{ route_name }}"
hx-target="#{{ route_name }}__items"
hx-swap="outerHTML"
{% if swap_oob %}
diff --git a/autocomplete/templates/autocomplete/values.html b/autocomplete/templates/autocomplete/values.html
index e5eda84..758735d 100644
--- a/autocomplete/templates/autocomplete/values.html
+++ b/autocomplete/templates/autocomplete/values.html
@@ -3,3 +3,6 @@
{% for value in values %}
{% endfor %}
+{% if required and values|length == 0 %}
+
+{% endif %}
\ No newline at end of file
diff --git a/autocomplete/templatetags/autocomplete.py b/autocomplete/templatetags/autocomplete.py
index 621ecda..aca5ebb 100644
--- a/autocomplete/templatetags/autocomplete.py
+++ b/autocomplete/templatetags/autocomplete.py
@@ -1,14 +1,22 @@
"""
Django template tags to facilitate rendering of the component
"""
+import hashlib
+
from django import template
from django import urls
from django.utils.html import format_html
from django.utils.http import urlencode
from django.template import loader
+from django.template.defaultfilters import stringfilter
register = template.Library()
+@register.filter
+@stringfilter
+def make_id(value):
+ """Generate an ID given a string, to use as element IDs in HTML"""
+ return hashlib.sha1(value.encode('utf-8')).hexdigest()
@register.simple_tag
def autocomplete(name, selected=None):
diff --git a/autocomplete/widgets.py b/autocomplete/widgets.py
index 945587a..57e77c6 100644
--- a/autocomplete/widgets.py
+++ b/autocomplete/widgets.py
@@ -14,6 +14,7 @@ class Autocomplete(Widget):
name (str): The name of the component (must be unique)
options (dict): See [autocomplete.py](../autocomplete.py) for more info
label (str)
+ required (bool) Defaults to false
placeholder (str)
no_result_text (str) Defaults to "No results found."
narrow_search_text (str) Defaults to
@@ -41,6 +42,7 @@ def __init__(
super().__init__(attrs)
config = {
'name': name,
+ 'required': opts.get('required', None),
'route_name': opts.get('route_name', None),
'label': opts.get('label', None),
'placeholder': opts.get('placeholder', None),
@@ -98,11 +100,12 @@ def get_context(self, name, value, attrs):
)
context['name'] = self.a_c.name
+ context['required'] = self.a_c.required
context['route_name'] = self.a_c.get_route_name()
context['label'] = self.a_c.label
context['placeholder'] = self.a_c.placeholder
context['multiselect'] = self.a_c.multiselect
- context['values'] = self.a_c.item_values(self.a_c, selected_options)
- context['selected_items'] = selected_options
+ context['values'] = list(self.a_c.item_values(self.a_c, selected_options))
+ context['selected_items'] = list(selected_options)
return context
diff --git a/setup.cfg b/setup.cfg
index 0a1f137..f3871f5 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = django-htmx-autocomplete
-version = 0.1.1
+version = 0.1.2
description = A Django autocomplete component powered by htmx
long_description = file: README.md
long_description_content_type = text/markdown