Why can't I keep component-related actions within the component in this Svelte app?

162 views Asked by At

I am working on a small Users app in Svelte for learning purposes (Im new to Svelte).

In App.Svelte, I loop through a set of users:

<script>
const apiURL = "https://randomuser.me/api/";
import { onMount } from "svelte";
import Search from './Search.svelte';
import User from './User.svelte';

let users = [];
let stringToMatch = "";

$:filteredUsers = users;

 onMount(() => {
    getUsers();
});

const getUsers = () => {
let getFrom = "&results=20&inc=name,location,email,cell,picture";
fetch(`${apiURL}?${getFrom}`)
    .then(res => res.json())
    .then((data) => users = data.results);
};

let filterUsers = () => {
    if (stringToMatch) {
        filteredUsers = users.filter(user => {
            return user.name.first.toLowerCase().includes(stringToMatch.toLowerCase()) ||
                user.name.last.toLowerCase().includes(stringToMatch.toLowerCase()) ||
                user.location.city.toLowerCase().includes(stringToMatch.toLowerCase());
        });
    } else filteredUsers = users;
};

</script>

<div class="container-fluid">
    <div class="card bg-light mb-2 overflow-hidden">
        <div class="card-header px-2 py-0 d-flex">
            <h6 class="text-dark m-0 align-self-center">Members Area</h6>
        </div>
            <div class="card-body bg-white p-0">
            <Search {filterUsers} bind:stringToMatch={stringToMatch} />
            {#if filteredUsers.length > 0}
                <table class="table users-table m-0">
                    <thead>
                        <tr>
                            <th class="text-right">#</th>
                            <th>Name</th>
                            <th>Lives in</th>
                            <th class="text-right">Actions</th>
                        </tr>
                    </thead>
                    <tbody>
                        {#each filteredUsers as user,index (user)}
                            <User {user} {index} on:Delete = {deleteUser(user)} />
                        {/each}
                    </tbody>
                </table>
            {:else}
                <p class="text-center text-muted my-3">No members found</p>
            {/if}
        </div>
    </div>
</div>

As can be seen in the loop above, I display every user from a User.svelte component. It seems logical that every user-related action (like deleting a user, for instance) show live in this component. So, it is here that I have:

const dispatch = createEventDispatcher();
const Delete = () => dispatch("deleteUser", user);

const deleteUser = (user) => {
    let itemIdx = filteredUsers.findIndex(x => x == user);
    filteredUsers.splice(itemIdx, 1);
    filteredUsers = filteredUsers;
}

Yet, I get this 'deleteUser' is not defined error, as can be seen in the REPL.

Question(s)

  • What am I doing wrong?
  • How can I keep the deleteUser method within User.svelte and use it successfully?
1

There are 1 answers

2
Stephane Vanraes On BEST ANSWER

You are defining deleteUser in the User component, but you are trying to use it in App were it is indeed not defined. So the error is not that strange imo.

One of the problems you have is that your delete function is acting upon an array that is not part of the component (filteredUsers), so even if you would call deleteUser directly inside the component you would just get another undefined error.

What I see here is that you, logically, want to keep all the logic dealing with an individual user inside User, but by doing so you take in logic that deals with the users as whole (the array), which is inconsistent: the users as an array itself is part of App, why would you want to take logic related with the array out of where it belongs ?

In my opinion, deleting a user is not a function executed by an item on itself but is a function done by the holder of the array. So in your case you would be better of moving the deleteUser up to App.

If you do it this way, the User component will be responsible for

  • display an individual user
  • potentially edit an individual user

And the App will be responsible for

  • display a list of users
  • adding/removing users of said list