Skip to content

Commit

Permalink
Correct behavior of page change
Browse files Browse the repository at this point in the history
When changing page, but in the same component, the page was not refreshed.

There was these two issues:

* No transition
* Some part of the page is not updated

The reason was because Svelte reused the exact same component (so no mount / destroy and no animation on component creation / destruction).

To correctly update the page, we change the `Page` component by adding a keyed-each block (see sveltejs/svelte#1469).

There was some issue with this solution because each time we update the component, the render is updated so the Page and create an infinite loop.
To avoid this problem, we remove the call to `Page` component from concrete pages and include it directly with the Router. To do so, we create the PageRoute component behaving as expected.
  • Loading branch information
Gaëtan Rizio committed May 17, 2020
1 parent 6490449 commit 07525df
Show file tree
Hide file tree
Showing 8 changed files with 178 additions and 172 deletions.
13 changes: 7 additions & 6 deletions src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import HomePage from "~/pages/home/HomePage.svelte"
import TwoColumns from "~/components/layout/TwoColumns.svelte"
import PageRoute from "~/components/page/PageRoute.svelte"
export let url = ""
</script>
Expand All @@ -35,16 +36,16 @@
<Menu/>

<main>
<Route path="/units" component={UnitsPage}/>
<PageRoute path="/units" component={UnitsPage}/>

<Route path="/searches" component={SearchesPage}/>
<PageRoute path="/searches" component={SearchesPage}/>


<Route path="/category/:categoryId/food/:foodId" component={FoodPage}/>
<Route path="/category/:categoryId/food" component={CreateFoodPage}/>
<Route path="/category/:categoryId" component={CategoryPage}/>
<PageRoute path="/category/:categoryId/food/:foodId" component={FoodPage}/>
<PageRoute path="/category/:categoryId/food" component={CreateFoodPage}/>
<PageRoute path="/category/:categoryId" component={CategoryPage}/>

<Route path="/" component={HomePage}/>
<PageRoute path="/" component={HomePage}/>

<div class="space"></div>
</main>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script>
function pageFade(node, {delay = 0, duration = 400, easing}) {
function pageFade(node, { delay = 0, duration = 400, easing }) {
const o = +getComputedStyle(node).opacity
return {
delay,
Expand Down
18 changes: 18 additions & 0 deletions src/components/page/PageRoute.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script>
import { Router, Route, links } from "svelte-routing"
import Page from "./Page.svelte"
/** @type {string} */
export let path
/** @type {any} */
export let component
</script>

<Route path={path} let:location={location} let:params={routeParams}>
{#each [`${Date.now()}-${Math.random()}`] as x(x)}
<Page>
<svelte:component this={component} location={location} {...routeParams} />
</Page>
{/each}
</Route>
34 changes: 16 additions & 18 deletions src/pages/category/CategoryPage.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import { onMount } from "svelte"
import i18n from "~/i18n"
import receptoStore from "~/store/ReceptoStore"
import Page from "~/components/Page.svelte"
import UpdatableSection from "~/components/updatable/UpdatableSection.svelte"
import InputText from "~/components/fields/InputText.svelte"
import { findCategory, saveCategory, deleteCategory } from "./CategoryPage"
Expand Down Expand Up @@ -30,22 +29,21 @@
}
</script>

<Page>
{#if category !== undefined}
<UpdatableSection on:save={saveName} on:cancel={cancelName}>
<div slot="view">
<h1>{ category.name }</h1>
</div>

<div slot="edit">
<InputText id="edit-category-name" name="name" label="pages.category.page.edit.name" bind:value={name}/>
</div>
</UpdatableSection>
{#if category !== undefined}
<UpdatableSection on:save={saveName} on:cancel={cancelName}>
<div slot="view">
<h1>{ category.name }</h1>
</div>

<div class="actions">
<Button danger on:click={() => deleteCategory(categoryId, $i18n)}>{$i18n.t("pages.category.page.actions.delete")}</Button>
<div slot="edit">
<InputText id="edit-category-name" name="name" label="pages.category.page.edit.name" bind:value={name}/>
</div>
{:else}
<h1>{$i18n.t("common.notFound")}</h1>
{/if}
</Page>
</UpdatableSection>

<div class="actions">
<Button danger
on:click={() => deleteCategory(categoryId, $i18n)}>{$i18n.t("pages.category.page.actions.delete")}</Button>
</div>
{:else}
<h1>{$i18n.t("common.notFound")}</h1>
{/if}
17 changes: 7 additions & 10 deletions src/pages/food/CreateFoodPage.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import i18n from "~/i18n"
import { buildPrimaryInformation, addFood } from "./CreateFoodPage"
import Page from "~/components/Page.svelte"
import Button from "~/components/buttons/Button.svelte"
import PrimaryInformationForm from "./primaryInformation/PrimaryInformationForm.svelte"
Expand All @@ -12,14 +11,12 @@
let primaryInformation = buildPrimaryInformation(categoryId)
</script>

<Page>
<h1>{$i18n.t("pages.food.create.title")}</h1>
<h1>{$i18n.t("pages.food.create.title")}</h1>

<form on:submit|preventDefault={() => addFood(primaryInformation)}>
<PrimaryInformationForm primaryInformation={primaryInformation} />
<form on:submit|preventDefault={() => addFood(primaryInformation)}>
<PrimaryInformationForm primaryInformation={primaryInformation}/>

<Button type="primary" submit>
{$i18n.t("pages.food.form.submit")}
</Button>
</form>
</Page>
<Button type="primary" submit>
{$i18n.t("pages.food.form.submit")}
</Button>
</form>
136 changes: 67 additions & 69 deletions src/pages/food/FoodPage.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import Button from "~/components/buttons/Button.svelte"
import Grid from "~/components/layout/Grid.svelte"
import RecipeCard from "~/components/card/RecipeCard.svelte"
import Page from "~/components/Page.svelte"
import Collapsable from "~/components/collapsable/Collapsable.svelte"
import SectionView from "./section/SectionView.svelte"
import UpdatableSection from "~/components/updatable/UpdatableSection.svelte"
Expand Down Expand Up @@ -99,79 +98,78 @@
}
</style>

<Page>
{#if food}
<UpdatableSection on:save={savePrimaryInformation} on:cancel={cancelPrimaryInformation}>
<div slot="view">
<PrimaryInformationSection food={food}/>
</div>

<div slot="edit">
<PrimaryInformationForm bind:primaryInformation={primaryInformation}/>
</div>
</UpdatableSection>

{#each sections as section, index}
<section>
<UpdatableSection
initialState={section.initial === undefined ? "edit" : "view"}
on:save={() => saveSection(index)}
on:cancel={() => cancelSection(index)}
>
<div slot="view">
<SectionView section={section.initial}/>
</div>

<div slot="edit">
<SectionForm
bind:section={sections[index].editing}
id={`food-section-${index}`}
name={`section[${index}]`}
/>
</div>

<span slot="actions">
{#if food}
<UpdatableSection on:save={savePrimaryInformation} on:cancel={cancelPrimaryInformation}>
<div slot="view">
<PrimaryInformationSection food={food}/>
</div>

<div slot="edit">
<PrimaryInformationForm bind:primaryInformation={primaryInformation}/>
</div>
</UpdatableSection>

{#each sections as section, index}
<section>
<UpdatableSection
initialState={section.initial === undefined ? "edit" : "view"}
on:save={() => saveSection(index)}
on:cancel={() => cancelSection(index)}
>
<div slot="view">
<SectionView section={section.initial}/>
</div>

<div slot="edit">
<SectionForm
bind:section={sections[index].editing}
id={`food-section-${index}`}
name={`section[${index}]`}
/>
</div>

<span slot="actions">
<Button danger on:click={() => removeSection(index)}>
&#x1F5D1 {$i18n.t("pages.food.page.actions.removeSection")}
</Button>
</span>
</UpdatableSection>
</section>
{/each}

{#if !hasUnsavedAddedSection}
<div class="actions">
<Button type="primary" on:click={addSection}>{$i18n.t("pages.food.page.actions.addSection")}</Button>
</div>
{/if}

{#if nonEmpty(usedFor)}
<section>
<h2>{$i18n.t("pages.food.page.usedFor")}</h2>

<Grid>
{#each usedFor as info}
<RecipeCard recipe={info.recipe} food={info.food}/>
{/each}
</Grid>
</section>
{/if}

<aside>
{#each $receptoStore.searches as search}
<Collapsable summary={$i18n.t("pages.food.page.asideSearch", { sitename: search.sitename })}>
<iframe src={search.url.replace("{s}", food.name)}
title={$i18n.t("pages.food.page.asideSearch", { sitename: search.sitename })}
width="100%"
height="500px"></iframe>
</Collapsable>
{/each}
</aside>
</UpdatableSection>
</section>
{/each}

{#if !hasUnsavedAddedSection}
<div class="actions">
<Button danger on:click={() => deleteFood(categoryId, foodId, $i18n)}>{$i18n.t("pages.food.page.actions.delete")}</Button>
<Button type="primary" on:click={addSection}>{$i18n.t("pages.food.page.actions.addSection")}</Button>
</div>
{:else}
<h1>{$i18n.t("common.notFound")}</h1>
{/if}
</Page>

{#if nonEmpty(usedFor)}
<section>
<h2>{$i18n.t("pages.food.page.usedFor")}</h2>

<Grid>
{#each usedFor as info}
<RecipeCard recipe={info.recipe} food={info.food}/>
{/each}
</Grid>
</section>
{/if}

<aside>
{#each $receptoStore.searches as search}
<Collapsable summary={$i18n.t("pages.food.page.asideSearch", { sitename: search.sitename })}>
<iframe src={search.url.replace("{s}", food.name)}
title={$i18n.t("pages.food.page.asideSearch", { sitename: search.sitename })}
width="100%"
height="500px"></iframe>
</Collapsable>
{/each}
</aside>

<div class="actions">
<Button danger
on:click={() => deleteFood(categoryId, foodId, $i18n)}>{$i18n.t("pages.food.page.actions.delete")}</Button>
</div>
{:else}
<h1>{$i18n.t("common.notFound")}</h1>
{/if}
65 changes: 31 additions & 34 deletions src/pages/searches/SearchesPage.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import receptoStore from "~/store/ReceptoStore"
import Button from "~/components/buttons/Button.svelte"
import Page from "~/components/Page.svelte"
import InputCollection from "~/components/fields/InputCollection.svelte"
import InputText from "~/components/fields/InputText.svelte"
Expand All @@ -17,36 +16,34 @@
})
</script>

<Page>
<h1>{$i18n.t("pages.searches.page.title")}</h1>

<form on:submit|preventDefault={() => updateSearches(searches)}>
<InputCollection
title={$i18n.t("pages.searches.page.groupTitle")}
addButtonLabel={$i18n.t("pages.searches.page.add")}
removeButtonLabel={$i18n.t("pages.searches.page.remove")}
rowBuilder={buildNewSearch}
bind:value={searches}

let:index={index}
>
<InputText
id={`searches-${index}-sitename`}
name={`searches[${index}].sitename`}
label={$i18n.t("pages.searches.page.sitename")}
bind:value={searches[index].sitename}
/>

<InputText
id={`searches-${index}-url`}
name={`searches[${index}].url`}
label={$i18n.t("pages.searches.page.url")}
bind:value={searches[index].url}
/>
</InputCollection>

<Button type="primary" submit>
{$i18n.t("pages.searches.page.submit")}
</Button>
</form>
</Page>
<h1>{$i18n.t("pages.searches.page.title")}</h1>

<form on:submit|preventDefault={() => updateSearches(searches)}>
<InputCollection
title={$i18n.t("pages.searches.page.groupTitle")}
addButtonLabel={$i18n.t("pages.searches.page.add")}
removeButtonLabel={$i18n.t("pages.searches.page.remove")}
rowBuilder={buildNewSearch}
bind:value={searches}

let:index={index}
>
<InputText
id={`searches-${index}-sitename`}
name={`searches[${index}].sitename`}
label={$i18n.t("pages.searches.page.sitename")}
bind:value={searches[index].sitename}
/>

<InputText
id={`searches-${index}-url`}
name={`searches[${index}].url`}
label={$i18n.t("pages.searches.page.url")}
bind:value={searches[index].url}
/>
</InputCollection>

<Button type="primary" submit>
{$i18n.t("pages.searches.page.submit")}
</Button>
</form>
Loading

0 comments on commit 07525df

Please sign in to comment.