Making first steps with Svelte and already loving it , noob question but I guess Svelte can not track such an update?
What would be Svelte way of writing this?
Uncommenting 2 would work, but even though I see different values in
when I click Weeks , Weeks in #each do not receive "new" selected updates
<script lang="ts">
import { getDays } from '$lib/calendar';
import Week from './Week.svelte';
let days = getDays(new Date());
let selected = 2;
function handleSelect(week_n) {
// console.log(week_n);
selected = week_n;
}
</script>
<p>Select {selected}</p>
<div class="isolate mt-2 grid grid-rows-5 gap-px rounded-lg text-sm shadow ring-1 ring-gray-200">
{#each [0, 1, 2, 3, 4] as week_n, i}
<Week
week={week_n === selected // 2
? days.slice(week_n * 7, week_n * 7 + 7).map((d) => ({ ...d, selected: true }))
: days.slice(week_n * 7, week_n * 7 + 7)}
on:select={(ev) => handleSelect(week_n)}
/>
{/each}
</div>
and the Week component
<script lang="ts">
import { createEventDispatcher } from 'svelte';
import WeekDay from './WeekDay.svelte';
export let week;
const dispatch = createEventDispatcher();
function select() {
dispatch('select', {
text: 'Hello!'
});
}
</script>
<button
type="button"
class="rounded-tl-lg py-1.5 text-gray-400 hover:bg-gray-100 focus:z-10"
on:click={select}
>
<div class="mx-auto flex">
{#each week as { datetime, dd, isToday, thisMonth, selected }, i}
<WeekDay {datetime} {dd} {isToday} {thisMonth} {selected} />
{/each}
</div>
</button>
including leaf WeekDay also for completeness
<script lang="ts">
export let datetime;
export let dd;
export let isToday;
export let thisMonth;
export let selected; // = false;
export let topLeft;
export let topRight;
export let bottomLeft;
export let bottomRight;
let timeClass = 'mx-auto flex h-7 w-7 items-center justify-center rounded-full';
if (selected || isToday) {
timeClass += ' font-semibold';
}
if (!selected && !isToday && thisMonth) timeClass += ' bg-white text-gray-900';
if (!selected && !isToday && !thisMonth) timeClass += ' bg-gray-50';
if (isToday && !selected) timeClass += ' text-indigo-600';
if (selected && isToday) timeClass += ' bg-indigo-600 text-white';
if (selected && !isToday) timeClass += ' bg-gray-900 text-white';
</script>
<time {datetime} class={timeClass}>{dd}</time>
Your code is not reactive the whole way, the properties get changed but the changes don't propagate.
The let timeClass
in WeekDay
and all the subsequent if
statements only happen once.
To fix that, it should be $: timeClass = ...
and $: if (...) ...
, but that could be done more functionally. Something like:
$: classes = [
['mx-auto flex h-7 w-7 items-center justify-center rounded-full', true],
['font-semibold', selected || isToday],
...
]
.filter(x => x[1]).map(x => x[0])
.join(' ')
Also, the week
property should not require a ternary:
week={days.slice(week_n * 7, week_n * 7 + 7)
.map(d => ({ ...d, selected: week_n === selected }))}