# Templates Templates are normal Django HTML templates, so anything you could normally do in a Django template will still work, including template tags, filters, loops, if statements, etc. ```{warning} `Unicorn` requires there to be one root element that contains the component HTML. Valid HTML and a wrapper element is required for the DOM diffing algorithm to work correctly, so `Unicorn` will try to log a warning message if they seem invalid. For example, this is an **invalid** template: :::{code} html :force: true
Name: {{ name }} ::: This template is **valid**: :::{code} html :force: true

Name: {{ name }}
::: ``` ## Unicorn attributes `Unicorn` element attributes usually start with `unicorn:`, however the shortcut `u:` is also supported. So, for example, `unicorn:model` could also be written as `u:model`. ## Accessing nested fields Fields in a `dictionary` or Django model can be accessed similarly to the Django template language with "dot notation". ```python # hello_world.py from django_unicorn.components import UnicornView from book.models import Book class HelloWorldView(UnicornView): book: Book book_ratings: dict[str[dict[str, str]]] def mount(self): book = Book.objects.get(title='American Gods') book_ratings = {'excellent': {'title': 'American Gods'}} ``` ```html
``` ```{note} [Django models](django-models.md) has many more details about using Django models in `Unicorn`. ``` ## Model modifiers ### Lazy To prevent updates from happening on _every_ input, you can append a `lazy` modifier to the end of `unicorn:model`. That will only update the component when a `blur` event happens. :::{code} html :force: true
Hello {{ name|title }}
::: ### Debounce The `debounce` modifier configures how long to wait to fire an event. The time is always specified in milliseconds, for example: `unicorn:model.debounce-1000` would wait for 1000 milliseconds (1 second) before firing the message. :::{code} html :force: true
Hello {{ name|title }}
::: ### Defer The `defer` modifier will store and save model changes until the next action gets triggered. This is useful to prevent additional network requests until an action is triggered. :::{code} html :force: true
::: ### Chaining modifiers `Lazy` and `debounce` modifiers can even be chained together. :::{code} html :force: true
Hello {{ name|title }}
::: ## Key ### Smooth updates Setting a unique `id` on elements with `unicorn:model` will prevent changes to an input from being choppy when there are lots of updates in quick succession. ```html ``` ```html !-- smooth-updates.html --> ``` The `unicorn:key` attribute can be used when multiple elements have the same `id`. ```html ``` ```html ``` ### DOM merging To merge changes in the DOM, `Unicorn` uses, in order, `unicorn:id`, `unicorn:key`, or the element's `id` to intelligently update DOM elements. ## Lifecycle events `Unicorn` provides events that fire when different parts of the lifecycle occur. ### updated The `updated` event is fired after the AJAX call finishes and the component is merged with the newly rendered component template. The callback gets called with one argument, `component`. ```html ``` ## Ignore elements Some JavaScript libraries will change the DOM (such as `Select2`) after the page renders. That can cause issues for `Unicorn` when trying to merge that DOM with what `Unicorn` _thinks_ the DOM should be. `unicorn:ignore` can be used to prevent `Unicorn` from morphing that element or its children. ```{note} When the component is initially rendered, normal Django template functionality can be used. ``` ```html
``` ```python # ignored_element.py from django_unicorn.components import UnicornView class JsView(UnicornView): states = ( "Alabama", "Alaska", "Wisconsin", "Wyoming", ) selected_state = "" def select_state(self, state_name, selected_idx): print("select_state state_name", state_name) print("select_state selected_idx", selected_idx) self.selected_state = state_name ```