如何使用api请求在sveltekit中实现多个预输入搜索输入?

How to implement multiple typeahead search input in sveltekit with api request?

提问人:Jay0813 提问时间:9/19/2023 最后编辑:Jay0813 更新时间:9/20/2023 访问量:87

问:

我正在尝试实现一项功能,每次用户在输入字段中键入时,都会发出 API 请求,结果会直接显示在输入下方。它类似于预输入或自动完成功能。虽然我可能直接从客户端发出请求并显示结果,但我需要在服务器端处理 API 请求。这是因为所有请求都必须在标头中包含令牌,并且存储令牌的 cookie 设置为 httpOnly:true。因此,我无法从客户端访问此 cookie。有人可以指导我如何实现这一目标吗? 欢迎任何建议。谢谢

<script lang="ts">
    import { Button, Input, Label } from 'flowbite-svelte';

    export let data;
    let taskId = '';

    const onChange = async () => {};
</script>

<div class="max-w-screen-md mx-auto p-6 space-y-8">
    <div class="bg-white shadow-md rounded-lg p-6">
        <div class="text-center mb-8">
            <h2 class="text-2xl bold">Task Form</h2>
        </div>
        <div class="relative">
            <Label class="block mb-1">Task ID</Label>
            <Input
                label="Email"
                id="email"
                name="email"
                bind:value={taskId}
                on:change={onChange}
                required
                placeholder="Task id..."
            />

            <br />

            <Label class="block mb-1">유저 닉네임</Label>
            <Input label="nickname" id="nickname" name="nickname" required placeholder="nickname..." />
        </div>
    </div>

    <Button type="submit">Create</Button>
</div>


输入 服务器端 sveltekit typeahead

评论

0赞 brunnerh 9/19/2023
你在这里的问题到底是什么?
0赞 Jay0813 9/19/2023
我想在每次在输入字段中输入值时发送 API 请求,然后在输入的正下方显示来自 API 的结果,类似于预输入功能。
0赞 brunnerh 9/19/2023
已经有关于发送请求的各种问题,可能还有关于使用 Svelte 显示数据的问题。看起来你甚至没有尝试过任何东西。(此外,从客户端发送的任何请求都将自动包含所有相关的 cookie。
0赞 Jay0813 9/19/2023
我已经探索了使用 SvelteKit 的预输入实现。在我见过的许多示例中,通常的做法是获取整个数据集,然后在客户端对其进行过滤。但是,我的目标是通过每个输入实时检索相关数据。如前所述,虽然这在客户端很简单,但我需要在服务器端管理此逻辑。原因是每个请求都必须包含存储在 cookie 中的 accessToken。这里的挑战是,这个cookie是用httpOnly:true设置的,这使得它无法从客户端访问。
0赞 Jay0813 9/19/2023
你说我研究得不够深入可能是对的。此外,这是我第一次使用具有服务器端支持的框架,因此我正在浏览一个学习曲线。感谢您提供的任何指导或见解。

答:

0赞 Jay0813 9/20/2023 #1

问题陈述:我的目标是实现一个功能,每次用户输入字段时,都会触发一个 API 请求,结果显示在输入的正下方。请务必注意,API 请求需要在服务器端处理,而不是直接从客户端处理。这是因为必须在请求标头中包含令牌,该令牌存储在设置为 httpOnly: true 的 cookie 中。因此,无法从客户端访问它。

客户端代码:

为了避免在每次击键时立即发出 API 请求,我采用了去抖动功能。这可确保函数仅在用户停止键入指定持续时间后执行。 我使用单独的状态变量来管理 taskId 和 nickname 的输入值。 在每个输入上,都会调用去抖动包装的 API 调用函数 和 。 结果存储在 taskResults 和 nicknameResults 中,随后显示给用户。_handleTaskInput_handleNicknameInput

服务器端代码:

这段代码处理从客户端发送的请求。 它处理 /api/task 端点的 POST 请求。 taskId 值是从请求正文中提取的,并基于该值生成并返回模拟结果数据。 在实际方案中,此部分通常会查询外部 API 或数据库来获取实际数据。

注意:当从客户端对“/api/task”进行 fetch 调用时,它 对应于执行位于 /routes/api/task/+server.ts。

这是我的代码。

// client side
<script lang="ts">
    import debounce from '$lib/utils/debounce';
    import { Button, Input, Label } from 'flowbite-svelte';

    let taskId = '';
    let nickname = '';
    let nicknameResults: any[];
    let taskResults: any[];

    async function _getTaskList() {
        const response = await fetch('/api/task', {
            method: 'POST',
            body: JSON.stringify({ taskId }),
            headers: {
                'content-type': 'application/json'
            }
        });

        taskResults = await response.json();
    }

    async function _getNicknameList() {
        const response = await fetch('/api/user', {
            method: 'POST',
            body: JSON.stringify({ nickname }),
            headers: {
                'content-type': 'application/json'
            }
        });

        nicknameResults = await response.json();
    }

    function _selectTaskResult(result: { id: number; name: string }) {
        taskId = result.id.toString();
        taskResults = []; // 선택한 후 결과 목록을 숨깁니다.
    }

    function _selectNicknameResult(result: { id: number; name: string }) {
        nickname = result.id.toString();
        nicknameResults = []; // 선택한 후 결과 목록을 숨깁니다.
    }

    const _debouncedTaskList = debounce(_getTaskList, 300);
    const _debouncedNicknameList = debounce(_getNicknameList, 300);

    function _handleTaskInput(event: Event) {
        _debouncedTaskList();
    }

    function _handleNicknameInput(event: Event) {
        _debouncedNicknameList();
    }

    $: console.log({ nickname });
</script>

<div class="max-w-screen-md mx-auto p-6 space-y-8">
    <div class="bg-white shadow-md rounded-lg p-6 min-h-[800px]">
        <div class="text-center mb-8">
            <h2 class="text-2xl bold">Create Task</h2>
        </div>
        <div class="relative">
            <div class="relative">
                <Label class="block mb-1">taskId</Label>
                <Input
                    label="taskId"
                    id="taskId"
                    name="taskId"
                    bind:value={taskId}
                    on:input={_handleTaskInput}
                    required
                    placeholder="task id"
                />
                {#if taskResults && taskResults.length > 0}
                    <div class="absolute w-full top-16 mt-2 bg-white border border-gray-300 z-10">
                        {#each taskResults as taskResult}
                            <div
                                on:keydown={() => _selectTaskResult(taskResult)}
                                on:click={() => _selectTaskResult(taskResult)}
                                class="cursor-pointer hover:bg-gray-200 p-2"
                            >
                                {taskResult.id}
                            </div>
                        {/each}
                    </div>
                {/if}
            </div>
            <br />

            <div class="relative">
                <Label class="block mb-1">nickname</Label>
                <Input
                    label="nickname"
                    id="nickname"
                    name="nickname"
                    bind:value={nickname}
                    on:input={_handleNicknameInput}
                    required
                    placeholder="nickname"
                />

                {#if nicknameResults && nicknameResults.length > 0}
                    <div class="absolute w-full top-16 mt-2 bg-white border border-gray-300 z-10">
                        {#each nicknameResults as nicknameResult}
                            <div
                                on:keydown={() => _selectNicknameResult(nicknameResult)}
                                on:click={() => _selectNicknameResult(nicknameResult)}
                                class="cursor-pointer hover:bg-gray-200 p-2"
                            >
                                {nicknameResult.id}
                            </div>
                        {/each}
                    </div>
                {/if}
            </div>
        </div>
    </div>

    <Button type="submit">Create</Button>
</div>

// server side 
// path : /routes/task/+server.ts

import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

export const POST: RequestHandler = async ({ request }) => {
    const { taskId } = await request.json();

    if (!taskId) return json([]);

    // Api call here

    console.log({ taskId });
    const result = [
        { id: 1, name: taskId },
        { id: 2, name: taskId },
        { id: 3, name: taskId },
        { id: 4, name: taskId },
        { id: 5, name: taskId },
        { id: 6, name: taskId }
    ];
    return json(result);
};