I have a relatively simple search of a section called articles
. Each entry within articles has a category assigned. I've named the category animal
.
Layout is as follows:
- Header
- Search/filtering section
- Articles container
- Pagination container
The problem I'm having, is that the search field gets replaced whenever the sprigboard updates. The only way to stop this, is to wrap the #articleContainer
and #articlePagination
into a div (#articles-and-pagination
) and use s-replace="#articles-and-pagination"
. However, this doesn't work in this case because I need to also replace the contents of the Header, which is above the search field.
So the next solution was to use s-preserve="true"
on the search field itself, but that seems to have absolutely no effect because it still gets replaced on each ajax load.
Below is the full code I've written thus far. I realise that parts of it is quite messy. I haven't gotten near to finalizing this :).
{% set section = 'articles' %}
{% set search = search ?? '' %}
{% set animal = animal ?? '' %}
{% set page = page ?? 1 %}
{% set filters = {
search: search,
relatedTo: animal,
} %}
{% set entryQuery = craft.entries(filters|merge({
section: section,
limit: 21,
})) %}
{% set animals = craft.categories.group('animal').all() %}
{% set pageInfo = sprig.paginate(entryQuery, page) %}
{% set entries = pageInfo.pageResults %}
{% do sprig.pushUrl('?' ~ filters|merge({
page: page
})|url_encode) %}
{% set pageTitle = '<h1>' ~ 'Articles and Guides'|t ~ '</h1>' %}
{% if animal is defined and animal != '' %}
{% set animalObject = craft.categories.id(animal).one() %}
{% set pageTitle = '<h1>' ~ animalObject.title ~ '</h1>' %}
{% if animalObject.textArea|length %}
{% set supportingText = '<p class="text-lg m-auto max-w-xl">' ~ animalObject.textArea ~ '</p>' %}
{% endif %}
{% else %}
{% if entry is defined and entry.redactorSimple|length %}
{% set pageTitle = entry.redactorSimple %}
{% endif %}
{% endif %}
<div>
<section class="pt-5 pb-5 bg-fv-vlight-beige relative">
<header class="container text-center relative z-10">
<div id="articleTitleContainer" class="max-w-xl m-auto c-redactor">
{{ pageTitle|raw }}
{{ supportingText is defined ? supportingText|raw : '' }}
</div>
</header>
</section>
{# ARTICLES SEARCH BAR #}
<section class="bg-fv-white py-4">
<div class="max-w-2xl mx-auto px-3">
<form class="flex justify-center flex-wrap">
<div class="article-search-category-wrapper" id="animal" sprig >
<div class="item category-all">
<label>
<input type="radio" id="c_all" name="animal" value="" {% if animal == '' %} checked {% endif %} >
<div class="icon category-all"></div>
<span>{{ 'All'|t }}</span>
</label>
</div>
{% for categoryOption in animals %}
{% if categoryOption.id is not null %}
{% set categoryUrl = siteUrl ~ categoryOption.uri %}
{% set catID = categoryOption.id %}
<div class="item category-{{ catID }}">
<label>
{% set entryCount = craft.entries.relatedTo(categoryOption).count() %}
{% if entryCount > 0 %}
<input
class="filter-button"
type="radio"
id="c_{{ catID }}"
name="animal"
value="{{ catID }}"
>
<div class="icon category-{{ categoryOption.id }}"></div>
<span>{{ categoryOption.title }}</span>
{% endif %}
</label>
</div>
{% endif %}
{% endfor %}
</div>
<div class="article-search-input" id="article-search-input-wrapper">
{% set placeholder = 'Search for'|t ~ '...' %}
{% set searchPrefix = '' %}
<input
sprig
s-trigger="keyup changed delay:300ms"
s-preserve="true"
name="search"
id="search"
class="p-3 text-xl border-2 rounded w-full md:h-full mb-2 md:mb-0 outline-none focus:border-fv-pink"
placeholder="{{ placeholder }}"
value="{{ search ?? '' }}"
aria-label="{{ 'Search articles'|t }}"
>
</div>
<div class="article-search-button">
<button type="submit" class="bg-fv-pink hover:bg-fv-more-pink transition-all w-full text-white md:h-full p-3 rounded text-xl ">
<span class="font-bold">{{ 'Search'|t }}</span>
</button>
</div>
</form>
</div>
</section>
{# LISTING SECTION #}
<div id="articles-and-pagination">
<section class="pb-4 md:pb-5 pt-4 relative">
<div class="container">
<div class="articles articlesContainer max-w-2xl mx-auto" id="articleContainer">
{% for article in entries %}
<a href="{{ article.url }}" class="article-card">
<div class="article-card__image" style="position: relative; overflow:hidden;">IMAGE HERE</div>
<div class="article-card__inner">
<div>
<h2 class="article-card__title text-lg">{{ article.title }}</h2>
{% if article.articleIntro|length >= 200 %}
<p class="article-card__intro">{{ article.articleIntro|slice(0, 200) ~ '...' }}</p>
{% else %}
<p class="article-card__intro">{{ article.articleIntro }}</p>
{% endif %}
</div>
<span class="article-card__link">{{ 'Read article'|t }}</span>
</div>
</a>
{% endfor %}
</div>
</div>
</section>
<section class="mb-4 mt-4">
<div class="max-w-2xl mx-auto px-3" id="articlePagination">
<div class="text-center text-sm ">
{{ 'Showing page'|t }}
{{ pageInfo.currentPage }}
{{ 'of'|t }}
{{ pageInfo.totalPages }}
</div>
<ul class="flex flex-wrap justify-center w-auto font-sans">
{% if page > 1 %}
<li>
<a sprig s-val:page="{{ page - 1 }}" href="#"
class="block m-1 border rounded px-0 py-2 border-transparent">
PREVIOUS
</a>
</li>
{% endif %}
{% for pageNumber in pageInfo.dynamicRange(5) %}
<li>
<a sprig s-val:page="{{ pageNumber }}" href="#"
class="block m-1 border rounded px-3 py-2 {{ pageNumber == page ? 'border-fv-blue text-white font-bold bg-fv-blue' : 'border-fv-grey' }} ">
{{ pageNumber }}
</a>
</li>
{% endfor %}
{% if page < pageInfo.totalPages %}
<li>
<a sprig s-val:page="{{ page + 1 }}" href="#"
class="block m-1 border rounded px-0 py-2 border-transparent">
NEXT
</a>
</li>
{% endif %}
</ul>
</div>
</section>
</div>
</div>
Edit: To clarify the question; Why doesn't s-preserve
work? Where have I gone wrong? I realize it's difficult to test of course, but I'm hoping someone with more experience with sprig can see some glaring mistake :)
s-preserve
attribute should do the trick. You haven't asked a question though, so it's impossible to give you an answer...