DEV Community

Mitesh Kamat
Mitesh Kamat

Posted on

Simple CRUD app with Svelte JS

Introduction

This post is an attempt to create a simple CRUD operation using svelte js.
In order to learn some aspects of svelte, I thought of creating this simple use case.

Use case

  1. Perform create, update, delete and read.
  2. A simple note with title and content field.

Let us begin.

npx degit sveltejs/template svelte-crud-example

cd svelte-crud-example

npm install
npm run dev

Above mentioned are the basic steps to create a svelte project and run it on your browser http://localhost:5000/

I will use bootstrap 4 cdn link to style my page. So, goto your root folder locate index.html present in your public directory and add this:

<link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
    />

Now create a new file named Notes.svelte under src folder and add the below template:

<section>
  <div class="container">
    <div class="row mt-5">
      <div class="col-md-6">
        <div class="card p-2 shadow">
          <div class="card-body">
            <h5 class="card-title mb-4">Add New Note</h5>
            <form>
              <div class="form-group">
                <label for="title">Title</label>
                <input
                  type="text"
                  class="form-control"
                  id="text"
                  placeholder="Note Title" />
              </div>
              <div class="form-group">
                <label for="content">Content</label>
                <textarea
                  class="form-control"
                  id="content"
                  rows="3"
                  placeholder="Note Content" />
              </div>
              <button type="submit" on:click|preventDefault={addNote} class="btn btn-primary">
            Add Note</button>
            </form>
          </div>
        </div>
      </div>
      <div class="col-md-6">
        {#each notes as note}
          <div class="card ">
            <div class="card-body">
              <h5 class="card-title">{note.title}</h5>
              <p class="card-text">{note.content}</p>
              <button class="btn btn-info"  on:click={editNote()}>Edit</button>
              <button class="btn btn-danger" on:click={deleteNote()}>Delete</button>
            </div>
          </div>
        {/each}
      </div>
    </div>
  </div>
</section>

Now lets add some script to make it functional

<script>

let notes = [];

let data = {
    title: "",
    content: "",
    id: null
};

let addNote = () => {
    //create functionality
}

let deleteNote = id => {
    //delete functionality
};

let editNote = note => {

    //editfunctionality
};
let updateNote = () => {
    //update functionality
}

I have my note template ready but I need to store the values which I enter. So, I will make use of *bind: *

Now my template would look like this:

<section>
  <div class="container">
    <div class="row mt-5">
      <div class="col-md-6">
        <div class="card p-2 shadow">
          <div class="card-body">
            <h5 class="card-title mb-4">Add New Note</h5>
            <form>
              <div class="form-group">
                <label for="title">Title</label>
                <input
                  bind:value={data.title}
                  type="text"
                  class="form-control"
                  id="text"
                  placeholder="Note Title" />
              </div>
              <div class="form-group">
                <label for="content">Content</label>
                <textarea
                  class="form-control"
                  id="content"
                  bind:value={data.content}
                  rows="3"
                  placeholder="Note Content" />
              </div>

                <button type="submit" on:click|preventDefault={addNote} class="btn btn-primary">
            Add Note</button>

            </form>
          </div>
        </div>
      </div>
      <div class="col-md-6">
        {#each notes as note}
          <div class="card ">
            <div class="card-body">
              <h5 class="card-title">{note.title}</h5>
              <p class="card-text">{note.content}</p>
              <button class="btn btn-info"  on:click={editNote()}>Edit</button>
              <button class="btn btn-danger" on:click={deleteNote()}>Delete</button>
            </div>
          </div>
        {/each}
      </div>
    </div>
  </div>
</section>

I wanted to experiment this with stores concept. So, I will add writable store to it and add my logic to the store.
Now create a file name Store.js

import { writable } from 'svelte/store';

const store = () => {
    const state = []; //Initial state
    const {subscribe, set, update} = writable(state);
    const tasks= {
        createNote(data) {
            console.log("data: ", data);
            //logic
        },
        modify() {
          //logic
        },
        delete(id) {
            //logic
        }
    }

    return {
        subscribe,
        set,
        update,
        ...tasks
    }
}
export const notesStore = store();

Lets breakdown the above code:

  1. Create a function named store which would contain crud logic.
  2. Create an initial state.
  3. Create an object tasks which would have helper functions like add, delete and modify.
  4. My store should return default methods of store which are subscribe, set and update and also it should give access to tasks object which holds my helper functions.
  5. So, we just need to import this in our component and invoke this helper functions on respective event handlers which we would write for our component.

I will update Notes.svelte with following code

<script>
import { notesStore } from './Store.js'; //Import store

let notes = []; //Array used to iterate over number of notes

let data = {  // An object to store the entered values
    title: "",
    content: "",
    id: null
};

//Subscription with store for latest changes
const unsubscribe = notesStore.subscribe(value => {notes = value});

let addNote = () => {
    const newNote = {
      id: notes.length + 1,
      title: data.title,
      content: data.content
    };
    notesStore.createNote(newNote); //trigger create functionality
    data = {
        id: null,
        title: "",
        content: ""
    };
}

let deleteNote = id => {
    notesStore.delete(id);
};
let isEdit = false;
let editNote = note => {
    isEdit = true;
    data = note;
};
let updateNote = () => {
    isEdit = !isEdit;
    notesStore.modify(data);
    data = {
      id: null,
      title: "",
      content: ""
    };
}

</script>
<section>
  <div class="container">
    <div class="row mt-5">
      <div class="col-md-6">
        <div class="card p-2 shadow">
          <div class="card-body">
            <h5 class="card-title mb-4">Add New Note</h5>
            <form>
              <div class="form-group">
                <label for="title">Title</label>
                <input
                  bind:value={data.title}
                  type="text"
                  class="form-control"
                  id="text"
                  placeholder="Note Title" />
              </div>
              <div class="form-group">
                <label for="content">Content</label>
                <textarea
                  class="form-control"
                  id="content"
                  bind:value={data.content}
                  rows="3"
                  placeholder="Note Content" />
              </div>
              {#if isEdit === false}
                <button type="submit" on:click|preventDefault={addNote} class="btn btn-primary">
            Add Note</button>
                {:else}
                <button type="submit" on:click|preventDefault={updateNote} class="btn btn-info">
                    Edit Note</button>
            {/if} 
            </form>
          </div>
        </div>
      </div>
      <div class="col-md-6">
        {#each notes as note}
          <div class="card ">
            <div class="card-body">
              <h5 class="card-title">{note.title}</h5>
              <p class="card-text">{note.content}</p>
              <button class="btn btn-info"  on:click={editNote(note)}>Edit</button>
              <button class="btn btn-danger" on:click={deleteNote(note.id)}>Delete</button>
            </div>
          </div>
        {/each}
      </div>
    </div>
  </div>
</section>

My final store logic would look like:

import { writable } from 'svelte/store';

const store = () => {
    const state = []
    const {subscribe, set, update} = writable(state);
    const methods = {
        createNote(data) {
            console.log("data: ", data);
            update(state => {
                state = state.concat(data);
                console.log("store data: ",state);
                return state;
            });
        },
        modify() {
             update(state => {
              console.log('state in store: ',state);
              return state;
             });
        },
        delete(id) {
            console.log(id);
            update(state => state.filter(state => state.id != id))
        }
    }

    return {
        subscribe,
        set,
        update,
        ...methods
    }
}
export const notesStore = store();

Now move to App.svelte and import Notes.svelte and place in

<script>
 import Notes from './Notes.svelte';
</script>
<main>
    <p>Visit the <a href="https://svelte.dev/tutorial">Svelte tutorial</a> to learn how to build Svelte apps.</p>
    <Notes />
</main>

Now check http://localhost:5000/ and try creating , editing and deleting a note.
As I am still exploring sveltejs, so this might not be the best approach or practice. But I think this can help you to dig more into svelte store.

Hope this helps. Cheers !!!

Top comments (0)