codediodeio / sveltefire

Cybernetically enhanced Firebase apps
MIT License
1.64k stars 126 forks source link

Two-way binding #127

Closed jerefrer closed 9 months ago

jerefrer commented 9 months ago

Hi there, and thanks for this great library :)

I'm trying to do something like:

<Doc ref="posts/1" let:data={post}>
  <input bind:value={post.title} />
</Doc>

But I'm getting the error

Cannot bind to a variable declared with the let: directive

But actually I would really like to do something like this:

<Doc ref="posts/1" let:data={post} let:ref={postRef}>
  <Collection ref={postRef.path + '/comments'} let:data={comments}>
    {#each comments as comment}
      <input bind:value={comment.body} />
    {/each}
  </Collection>
</Doc>

Is writing changes actually supported by sveltefire or do I have to manually send the updates to Firebase?

If this needs to be done manually, since I'm very new to Firebase and don't have that much experience in Svelte yet, could you provide a quick example of how to do so? That would be greatly appreciated 😅

Then maybe this example could then be added to the docs to give some direction to newcomers like myself.

Thank you so much !

jerefrer commented 9 months ago

Okay I just found out how to do just that, and indeed it kind of make sense that writing isn't as easy as I wanted to have it, because then there would be a request on each keydown in an input for instance.

Here's how I achieved what I wanted to do, using debounce to limit the number of update requests.

// firebase.js

import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";
import { getAuth } from "firebase/auth";

const firebaseConfig = {
  apiKey: "......",
  authDomain: "......",
  projectId: "......",
  storageBucket: "......",
  messagingSenderId: "......",
  appId: "......",
};
const app = initializeApp(firebaseConfig);
export const firestore = getFirestore(app);
export const auth = getAuth(app);
<!-- Post.svelte -->

<script>
  import { Doc, Collection } from "sveltefire";
</script>

<Doc ref="posts/some-post-id" let:data={post} let:ref={postRef}>
  <Collection ref="{postRef.path}/comments" let:data={comments}>
    {#each comments as comment}
      <Comment {comment} />
    {/each}
  </Collection>
</Doc>
<!-- Comment.svelte -->

<script>
  import { firestore } from '/firebase';

  export let comment;

  let timer;

  function debouncedUpdate(comment) {
    clearTimeout(timer);
    timer = setTimeout(() => {
      setDoc(doc(firestore, comment.ref.path), comment);
    }, 750);
  }
</script>

<input
  bind:value={comment.body}
  on:keydown={() => debouncedUpdate(group)}
  class="tibetan"
  spellcheck="false"
/>