Search code examples
svelte

Why is post title and description exists inside of onMounr, but don't wne I click button


When I render this page, I can see my post's properties in the console, but they disappear when I click the button. Why is that?

<script lang="ts">
  import { onMount } from 'svelte';
  import type { Post } from "$lib/models/Post";
  import { postToBeCreated } from "$lib/posts/store";

  export let post: Post | undefined = undefined;

  let title: string = ""
  let description: string = ""
  // Initialize the store with the post prop if defined
  onMount(() => {
    if (post) {
      postToBeCreated.update((value)=>{
        return{
          ...value,
          title: post.title,
          description: post.description
        }
      });
      console.log("onMount post", post);
      title = $postToBeCreated.title
      description = $postToBeCreated.description
    }
  });

  function handleChange(event: Event) {
    const input = event.target as HTMLInputElement;
    postToBeCreated.update((current) => {
      if (current) {
        return {
          ...current,
          [input.name]: input.value,
        };
      }
      return current;
    });
  }
</script>

<div>
  <label for="title">Title</label>
  <input
    id="title"
    name="title"
    bind:value={title}
    on:change={handleChange}
    
  />
  <label for="description">Description</label>
  <input
    id="description"
    name="description"
    bind:value={description}
    on:change={handleChange}
  />
  <button on:click={()=>console.log($postToBeCreated)}>Click</button>
</div>

Post writable variable

export const postToBeCreated: Writable<Post> = writable({
  id: "",
  title: "",
  html: "",
  created_by: "",
  description: "",
  thumbnail: "",
});

When the component mounts (onMount), the post variable is correctly logged and its properties are set in the store:

{
  "id": "667a3127a5f55d8e9d4490ca",
  "title": "Hello!",
  "thumbnail": "https://...",
  "description": "dwq",
  "html": "<p><img src=\"https://...\"></p><p>here is his picture</p>",
  "created_by": "6673cb5c5b7b256fcaa9e89f",
  "update_count": 0,
  "updated_at": "2024-06-25T11:53:27.914+00:00",
  "created_at": "2024-06-25T11:53:27.914+00:00"
}

However, when I click the button, the logged postToBeCreated value only contains some of the properties:

{
  "id": "667a3127a5f55d8e9d4490ca",
  "html": "<p><img src=\"https://...\"></p><p>here is his picture</p>"
}

I pass the post variable, which is the same as the one logged in onMount. Any insights into why the post's properties are missing when I click the button would be greatly appreciated.


Solution

  • When testing this myself. Your post object doesn't get fully set to the postToBeCreated store, you're only updating the title and description and the rest are spread to whatever is already in the store.

    If you're wanting the postToBeCreated to contain ALL the properties of the incoming post, you can just do $postToBeCreated = post in your onMount

    onMount(() => {
          if (post) {
            $postToBeCreated = post
            console.log("onMount post", post);
            title = $postToBeCreated.title
            description = $postToBeCreated.description
          }
    });
    

    Also, if that is really what you are trying to do, make this form update the store. You can skip all the handleChange code all together and just bind the inputs to the store's properties

    <script lang="ts">
        import { onMount } from 'svelte';
        import type { Post } from "$lib/models/Post";
        import { postToBeCreated } from "$lib/posts/store";
    
        export let post: Post | undefined = undefined;
      
        // Initialize the store with the post prop if defined
        onMount(() => {
          if (post) {
            $postToBeCreated = post
            console.log("onMount post", post);
          }
        });
      
      </script>
      
      <div>
        <label for="title">Title</label>
        <input
          id="title"
          name="title"
          bind:value={$postToBeCreated.title}
          
        />
        <label for="description">Description</label>
        <input
          id="description"
          name="description"
          bind:value={$postToBeCreated.description}
        />
        <button on:click={()=>console.log($postToBeCreated, 'postToBeCreated')}>Click</button>
      </div>