Table 更新错误的单元格 - Svelte-Headless-Table

问题描述 投票:0回答:0

在下面的视频中,您可以看到我有一个带有缩略图单元格的表格,您可以在单击它时更改图片。如视频中所示,UI 没有正确更新,但数据可以。关闭表格时,正确的图片会显示在正确的行中。

此外,加载指示器也不会显示在正确的单元格上,即使它们都是通过数组迭代的相同组件。

我正在使用 svelte-headless-table 库制作这张表,数据是来自 supabase 的 JSON 格式。

https://youtube.com/shorts/8kakKWNrIMI?feature=share

这是我认为可能是问题的代码,但由于该数据已正确更新,因此可能是其他问题。我需要 UI 才能正确更新。

更新数据库

async function updateThumbnail() {
        console.log('updating thumbnail', $rowIndex);
        
        // This is the line that adds the new pictureURL to the database
        $documentBody[$rowIndex].thumbnail_URL = pictureURL;
    
        const { error } = await supabaseClient
            .from('documents')
            .update({ document_body: $documentBody })
            .eq('document_id', $documentID);
        if (error) {
            console.log('THERE WAS AN ERROR');
            showError = true;
            errorMessage = 'There was an error updating your contact. Error: ' + error;
            console.log(error);
        } else if (error == null) {
            showError = false;
            console.log('Update successful');
            getMaterialSchedule();
            setTimeout(getAvatarURL, 3000);
        } else {
            showError = true;
            errorMessage = 'There was an error updating your contact. Error: ' + error;
            console.log('Update failed');
        }
    }

细胞成分

<script lang="ts">
    import { supabaseClient } from '$lib/db';

    import { slide, fade, fly } from 'svelte/transition';
    import { onMount } from 'svelte';
    import { loadingAction } from 'svelte-legos';
    import {
        documentID,
        documentName,
        documentProjectID,
        documentFirmID,
        documentType,
        documentLastModified,
        documentLastModifiedBy,
        documentNotes,
        documentBody,
        showDocumentFrame,
        showCreateNewDocument,
        rowIndex
    } from '/src/stores/documentStore';
    export let pictureURL;

    export let thumbnailFit;

    //export let row; /*: BodyRow<Item>*/

    let showError = false;
    let errorMessage = '';
    let showUI = false;
    let showFitAndFill = false;
    let src: string;
    let loading = true;
    let realPhotoUrl = '';

    let hasPhoto = false;

    
    let size = 10;
    let url: string;
    let uploading = false;
    let files: FileList;

     // handle file upload and only allow one file and for the file to be either .jpg or .png
    // if the file is larger then 5mb then it will not be accepted

    function handleFileChange(e) {
        files = e.target.files;
        if (files.length > 1) {
            console.log('Only one file allowed');
            return;
        }
        const file = files[0];
        if (file.type !== 'image/jpeg' && file.type !== 'image/png') {
            showError = true;
            errorMessage = 'Only .jpg and .png files allowed';
            console.log('Only .jpg and .png files allowed');
            return;
        }
        if (file.size > 5000000) {
            showError = true;
            errorMessage = 'File size too large (5mb max)';
            console.log('File size too large');
            return;
        }
        uploadAvatar();
    }
    // GET URL
    async function getAvatarURL() {
        if (pictureURL == 'null' || pictureURL == undefined || pictureURL == '--') {
            hasPhoto = false;

            console.log('no picture');
        } else {
            const { data } = await supabaseClient.storage.from('documents').getPublicUrl(pictureURL);
            if (data) {
                realPhotoUrl = data.publicUrl;
                src = realPhotoUrl;
                console.log('HAS picture');
                loading = false;

                hasPhoto = true;
            }
        }
    }

    // HANDLE UPLOAD
    async function uploadAvatar() {
        console.log('UPLOADING', $rowIndex);
        loading = true;
        const file = files[0];
        const fileExt = file.name.split('.').pop();
        const filePath = `${$documentID}_${Date.now()}.${fileExt}`;

        const { data, error } = await supabaseClient.storage
            .from('documents')
            .upload('materialScheduleRows/' + filePath, file, {
                upsert: true
            });
        if (data) {
            url = 'materialScheduleRows/' + filePath;

            pictureURL = url;
            updateThumbnail();
        } else if (error) {
            showError = true;
            errorMessage = 'There was an error uploading your photo. Error: ' + error;
            console.log(error);
        }
    }

    async function updateThumbnail() {
        console.log('updating thumbnail', $rowIndex);
        console.log('OLD DOCUMENT BODY', $documentBody);
        $documentBody[$rowIndex].thumbnail_URL = pictureURL;
        console.log('NEW DOCUMENT BODY', $documentBody);
        const { error } = await supabaseClient
            .from('documents')
            .update({ document_body: $documentBody })
            .eq('document_id', $documentID);
        if (error) {
            console.log('THERE WAS AN ERROR UPDATING THE USER PROFILE');
            showError = true;
            errorMessage = 'There was an error updating your contact. Error: ' + error;
            console.log(error);
        } else if (error == null) {
            showError = false;
            console.log('Update successful');
            getMaterialSchedule();
            setTimeout(getAvatarURL, 3000);
        } else {
            showError = true;
            errorMessage = 'There was an error updating your contact. Error: ' + error;
            console.log('Update failed');
        }
    }

    async function getMaterialSchedule() {
        const { data: documentJSON, error } = await supabaseClient
            .from('documents')
            .select('document_body')
            .eq('document_id', $documentID);

        [];
        if (error) {
            // showEmptyState = true;
            console.log('Error fetching contacts', error);
            // rowData= roleArray
        } else {
            const [fetchedRows] = documentJSON;
            documentBody.set(fetchedRows.document_body);
            getAvatarURL();
        }
    }

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

    function handleMouseOver() {
        showUI = true;
    }

    function handleMouseOut() {
        showUI = false;
    }

    function showButtons() {
        showFitAndFill = !showFitAndFill;
    }

    function fitImage() {
        thumbnailFit = true;
        $documentBody[$rowIndex].thumbnail_fit = true;
        showFitAndFill = false;
        updateThumbnail();
    }

    function fillImage() {
        thumbnailFit = false;
        $documentBody[$rowIndex].thumbnail_fit = false;
        showFitAndFill = false;
        updateThumbnail();
    }
</script>

<div class="flex gap-4 flex-row align-middle content-center">
    {#if pictureURL == '' || pictureURL == 'null' || pictureURL == undefined || pictureURL == '--'}
        <div>
            <label for="nonExisting">
                <div
                    class=" transition-all bg-neutral-50 border-2 rounded-sm border-neutral-300 h-24 w-24 flex text-center text-neutral-700 hover:bg-neutral-100 hover:border-neutral-400 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-50 hover:text-neutral-700 "
                >
                    <svg
                        class="self-center mx-auto "
                        width="20"
                        height="20"
                        viewBox="0 0 20 20"
                        fill="none"
                        xmlns="http://www.w3.org/2000/svg"
                    >
                        <path
                            opacity="0.3"
                            fill-rule="evenodd"
                            clip-rule="evenodd"
                            d="M9.99984 18.3332C14.6022 18.3332 18.3332 14.6022 18.3332 9.99984C18.3332 5.39746 14.6022 1.6665 9.99984 1.6665C5.39746 1.6665 1.6665 5.39746 1.6665 9.99984C1.6665 14.6022 5.39746 18.3332 9.99984 18.3332Z"
                            fill="currentColor"
                        />
                        <path
                            fill-rule="evenodd"
                            clip-rule="evenodd"
                            d="M10.8333 5.83333C10.8333 5.3731 10.4602 5 10 5C9.53976 5 9.16667 5.3731 9.16667 5.83333V9.16667H5.83333C5.3731 9.16667 5 9.53976 5 10C5 10.4602 5.3731 10.8333 5.83333 10.8333H9.16667V14.1667C9.16667 14.6269 9.53976 15 10 15C10.4602 15 10.8333 14.6269 10.8333 14.1667V10.8333H14.1667C14.6269 10.8333 15 10.4602 15 10C15 9.53976 14.6269 9.16667 14.1667 9.16667H10.8333V5.83333Z"
                            fill="currentColor"
                        />
                        <rect width="20" height="20" />
                    </svg>
                </div>
            </label>

            <input
                style="visibility: hidden; position:absolute;"
                type="file"
                id="nonExisting"
                accept="image/*"
                bind:files
                on:change={handleFileChange}
                disabled={uploading}
            />
        </div>
    {:else}
        <div class="flex flex-col text-center">
            <div
                on:mouseover={handleMouseOver}
                on:mouseout={handleMouseOut}
                on:focus={handleMouseOver}
                on:blur={handleMouseOut}
                class="flex flex-row "
            >
                {#if showUI}
                    <button
                        on:click={showButtons}
                        transition:fade
                        class="flex text-neutral-400 transition-all  hover:text-neutral-500  my-auto mx-auto"
                    >
                        <svg
                            class="self-center"
                            width="24"
                            height="24"
                            viewBox="0 0 48 48"
                            fill="none"
                            xmlns="http://www.w3.org/2000/svg"
                        >
                            <circle cx="24" cy="10" r="4" fill="currentColor" />
                            <circle cx="24" cy="24" r="4" fill="currentColor" />
                            <circle cx="24" cy="38" r="4" fill="currentColor" />
                        </svg>
                    </button>
                {/if}
                <label for="existing">
                    <div
                        use:loadingAction={loading}
                        class=" transition-all bg-neutral-50 border-2 rounded-sm border-neutral-300 h-24 w-24 flex text-center text-neutral-700 hover:bg-neutral-100 hover:border-neutral-400 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-50 hover:text-neutral-700 "
                    >
                        <img
                            {src}
                            alt={realPhotoUrl ? 'Avatar' : 'No image'}
                            class=" mx-auto transition-all {thumbnailFit === true
                                ? 'object-contain   '
                                : 'w-full h-full object-cover'} "
                        />
                    </div>
                </label>

                <input
                    style="visibility: hidden; position:absolute;"
                    type="file"
                    id="existing"
                    accept="image/*"
                    bind:files
                    on:change={handleFileChange}
                    disabled={uploading}
                />
            </div>

            {#if showFitAndFill}
                <div transition:slide class="flex w-full justify-center mx-auto gap-4 flex-row">
                    <button on:click={fitImage} class="p-2 mt-2 rounded-md hover:bg-neutral-200 ">
                        <svg
                            width="24"
                            height="24"
                            viewBox="0 0 48 48"
                            fill="none"
                            xmlns="http://www.w3.org/2000/svg"
                        >
                            <rect
                                x="4"
                                y="12"
                                width="40"
                                height="24"
                                rx="1.5"
                                stroke="currentColor"
                                stroke-width="4"
                            />
                            <rect
                                x="14"
                                y="12"
                                width="20"
                                height="24"
                                rx="1.5"
                                fill="currentColor"
                                fill-opacity="0.3"
                            />
                        </svg>
                    </button>
                    <button on:click={fillImage} class="p-2 mt-2 rounded-md hover:bg-neutral-200 ">
                        <svg
                            width="24"
                            height="24"
                            viewBox="0 0 48 48"
                            fill="none"
                            xmlns="http://www.w3.org/2000/svg"
                        >
                            <rect
                                x="4"
                                y="8"
                                width="40"
                                height="32"
                                rx="1.5"
                                fill="currentColor"
                                fill-opacity="0.3"
                            />
                            <rect
                                x="4"
                                y="12"
                                width="40"
                                height="24"
                                rx="1.5"
                                stroke="currentColor"
                                stroke-width="4"
                            />
                        </svg>
                    </button>
                </div>
            {/if}
        </div>
    {/if}

    <!--  ERROR MESSAGE -->
    {#if showError === true}
        <div
            transition:slide
            class="p-4 mb-8 border gap-2 border-pink-700 border-t-4 bg-pink-100 flex flex-row"
        >
            <h1 class=" text-sm font-display uppercase text-pink-700">Error:</h1>
            <p class="text-pink-700 text-sm ">{errorMessage}</p>
        </div>
    {/if}

    <!--  END ERROR MESSAGE -->
</div>

svelte
© www.soinside.com 2019 - 2024. All rights reserved.