mirror of https://github.com/kcal-app/kcal.git
Use node cloning instead of `x-for` for journal entry lines
This commit is contained in:
parent
76f29739e7
commit
d8ddaf611d
|
|
@ -9,27 +9,85 @@
|
|||
<div class="p-6 bg-white border-b border-gray-200">
|
||||
<form method="POST" action="{{ route('journal-entries.store') }}">
|
||||
@csrf
|
||||
<div x-data="{ ingredients: {{ $ingredients ? 0 : 1 }} }">
|
||||
<div class="space-y-4">
|
||||
@foreach($ingredients as $ingredient)
|
||||
@include('journal-entries.partials.entry-item-input', $ingredient)
|
||||
@endforeach
|
||||
<template x-if="ingredients > 0" x-for="i in ingredients">
|
||||
@include('journal-entries.partials.entry-item-input', ['template' => true, 'default_date' => $default_date])
|
||||
</template>
|
||||
<div x-data x-init="initJournalEntries($el);" class="space-y-4">
|
||||
@foreach($ingredients as $ingredient)
|
||||
@include('journal-entries.partials.entry-item-input', $ingredient)
|
||||
@endforeach
|
||||
<div class="journal-entry-template hidden">
|
||||
@include('journal-entries.partials.entry-item-input', ['default_date' => $default_date])
|
||||
</div>
|
||||
<x-inputs.icon-button type="button" color="green" x-on:click="ingredients++">
|
||||
<svg class="h-10 w-10" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
||||
<x-inputs.icon-button type="button" color="green" x-on:click="addEntryNode($el);">
|
||||
<svg class="h-10 w-10 pointer-events-none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-11a1 1 0 10-2 0v2H7a1 1 0 100 2h2v2a1 1 0 102 0v-2h2a1 1 0 100-2h-2V7z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</x-inputs.icon-button>
|
||||
</div>
|
||||
<div class="flex items-center justify-end mt-4">
|
||||
<x-inputs.button class="ml-3">Add entries</x-inputs.button>
|
||||
<div class="flex items-center justify-end mt-4">
|
||||
<x-inputs.button class="ml-3" x-on:click="removeTemplate($el);">Add entries</x-inputs.button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@once
|
||||
@push('scripts')
|
||||
<script type="text/javascript">
|
||||
/**
|
||||
* Adds an initial journal entry line.
|
||||
*
|
||||
* Add decision is based on number of direct descendent divs --
|
||||
* there should be two (the template and the add button) if no
|
||||
* journal entry lines have been added.
|
||||
*
|
||||
* @param {object} $el Journal entry lines parent element.
|
||||
*/
|
||||
let initJournalEntries = ($el) => {
|
||||
if ($el.querySelectorAll(':scope > div').length === 2) {
|
||||
addEntryNode($el);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a set of entry line form fields from the template.
|
||||
*
|
||||
* @param {object} $el Journal entry lines parent element.
|
||||
*/
|
||||
let addEntryNode = ($el) => {
|
||||
// Create clone of template entry.
|
||||
let template = $el.querySelector(':scope .journal-entry-template');
|
||||
let newEntry = template.cloneNode(true).firstElementChild;
|
||||
|
||||
// Set new entry's date and meal from the previous element.
|
||||
let previousEntry = template.previousElementSibling;
|
||||
if (previousEntry) {
|
||||
let newEntryDate = newEntry.querySelector(':scope input[name="ingredients[date][]"]');
|
||||
let newEntryMeal = newEntry.querySelector(':scope select[name="ingredients[meal][]"]');
|
||||
let previousDate = previousEntry.querySelector(':scope input[name="ingredients[date][]"]');
|
||||
let previousMeal = previousEntry.querySelector(':scope select[name="ingredients[meal][]"]');
|
||||
if (newEntryDate && newEntryMeal && previousDate && previousMeal) {
|
||||
newEntryDate.value = previousDate.value;
|
||||
newEntryMeal.value = previousMeal.value;
|
||||
}
|
||||
}
|
||||
|
||||
// Insert new entry before add button.
|
||||
$el.insertBefore(newEntry, template);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the hidden template before form submit.
|
||||
*
|
||||
* This is necessary because the template has required fields.
|
||||
*
|
||||
* @param {object} $el Journal entry lines parent element.
|
||||
*/
|
||||
let removeTemplate = ($el) => {
|
||||
$el.querySelector(':scope .journal-entry-template').remove();
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
@endonce
|
||||
|
||||
</x-app-layout>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<div x-data @isset($template)x-init="setDefaultsFromPrevious($el);"@endisset class="flex items-center space-x-2">
|
||||
<div x-data class="flex items-center space-x-2">
|
||||
<div class="flex flex-col space-y-4 w-full">
|
||||
<div class="flex flex-col space-y-4 md:flex-row md:space-x-4 md:space-y-0 w-full">
|
||||
<!-- Date -->
|
||||
|
|
@ -68,33 +68,3 @@
|
|||
</x-inputs.icon-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@once
|
||||
@push('scripts')
|
||||
<script type="text/javascript">
|
||||
let setDefaultsFromPrevious = ($el) => {
|
||||
let previousEl = $el.previousElementSibling;
|
||||
|
||||
// Skip the <template> node.
|
||||
if (previousEl && previousEl.nodeName === 'TEMPLATE') {
|
||||
previousEl = previousEl.previousElementSibling;
|
||||
}
|
||||
|
||||
// Do not continue if there is no previous element.
|
||||
if (!previousEl) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set date and meal from the previous element.
|
||||
let currentDateEl = $el.querySelector('input[name="ingredients[date][]"]');
|
||||
let currentMealEl = $el.querySelector('select[name="ingredients[meal][]"]');
|
||||
let previousDateEl = previousEl.querySelector('input[name="ingredients[date][]"]');
|
||||
let previousMealEl = previousEl.querySelector('select[name="ingredients[meal][]"]');
|
||||
if (currentDateEl && currentMealEl && previousDateEl && previousMealEl) {
|
||||
currentDateEl.value = previousDateEl.value;
|
||||
currentMealEl.value = previousMealEl.value;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
@endonce
|
||||
|
|
|
|||
Loading…
Reference in New Issue