Wie heirate ich diese Aufgabenliste mit sofortiger Suche in Svelte?
BEARBEITEN Sie für die tldr-Version nach unten, wo im folgenden Code steht, dass ich sehr nah dran bin.
Problem
Ich habe eine grundlegende Aufgabenliste, die nach Fertigstellung folgende Eigenschaften aufweist:
- Wenn die Seite geladen wird, sollte das Formularfeld im Fokus stehen.
- Wenn der Benutzer auf die Aufwärts- / Abwärtspfeile klickt, sollten die Elemente in der Liste über eine Änderung der CSS-Hintergrundfarbe ausgewählt werden.
- Wenn der Benutzer ein neues Element in das Formular eingibt, sollte es dem Benutzer in der Liste angezeigt werden.
- Wenn der Benutzer in das Formularfeld eingibt, wird eine "Sofort-Suche" auf die Liste angewendet, und es werden nur Elemente angezeigt, die der Suche entsprechen. Alle anderen Funktionen sollten weiterhin funktionieren. Wenn der Benutzer mit den Aufwärts- / Abwärtspfeilen einen Bildlauf durchführt, sollte dies unabhängig davon funktionieren, wie viele Elemente auf der Seite angezeigt werden. Wenn nur zwei Elemente angezeigt werden, sollte der Benutzer die Aufwärts- und Abwärtspfeile verwenden können, um diese beiden Elemente und den Fokus des Formularfelds auszuwählen.
Alle Gegenstände außer Nummer 4 scheinen gut zu funktionieren. Der folgende Code zeigt die Punkte 1-3
https://svelte.dev/repl/214b9c033d1c489e991484d387c267c2?version=3.30.0
<script>
import { onMount } from 'svelte';
let clients = ["a Little piggy","b little piggy","c little piggy"];
let indexVal = -1;
let downArrowPress = 40;
let upArrowPress = 38;
let clientInputTextField = "";
let clientVal = "";
onMount(function() {
clientInputTextField.focus();
});
function handleKeydown(event) {
if(event.keyCode === upArrowPress) {
indexVal-=1;
indexVal = indexVal < 0 ? clients.length : indexVal
console.log(indexVal);
}
if(event.keyCode === downArrowPress) {
indexVal+=1;
indexVal = indexVal > clients.length ? 0 : indexVal
console.log(indexVal);
}
if(indexVal > clients.length -1 || indexVal < 0){
clientInputTextField.focus();
} else {
clientInputTextField.blur()
}
}
function handleSubmit(e) {
const value = e.target.input.value;
console.log(value);
clients = [...clients, value];
clientVal = "";
}
</script>
<svelte:window on:keydown={handleKeydown}/>
<form on:submit|preventDefault={handleSubmit}>
<input type="text" name="input" bind:this={clientInputTextField} bind:value={clientVal} autocomplete="off">
<input type="submit" name="">
</form>
<ul>
{#each clients as client, i}
{#if i === indexVal}
<li style="background-color:orange">{client}</li>
{:else}
<li style="">{client}</li>
{/if}
{/each}
</ul>
<!--
function search(e){
console.log(e.target.value)
const searchString = e.target.value.toLowerCase();
const filteredCharacters = clients.filter((character) => {
return (
character.toLowerCase().includes(searchString) ||
character.toLowerCase().includes(searchString)
);
});
console.log(filteredCharacters)
}
-->
Ich möchte den obigen Code mit einer Sofort-Suchfunktion heiraten.
function search(e){
console.log(e.target.value)
const searchString = e.target.value.toLowerCase();
const filteredCharacters = clients.filter((character) => {
return (
character.toLowerCase().includes(searchString) ||
character.toLowerCase().includes(searchString)
);
});
console.log(filteredCharacters)
}
Alles, was ich bisher versucht habe, macht nur ein Chaos, gibt die Liste nicht zurück und fokussiert (onBlur) das Eingabefeld.
Der Code unter console.log ist ein Array, das mir bei der Suche des Benutzers das gibt, was ich möchte. Der nächste Schritt besteht darin, es auf das DOM anzuwenden. Alles, was ich bisher versucht habe, hat nicht funktioniert.
https://svelte.dev/repl/ceca685a3a4c49b4b5ccd780a101fc63?version=3.30.0
<script>
import { onMount } from 'svelte';
let clients = ["a Little piggy","b little piggy","c little piggy"];
let indexVal = -1;
let downArrowPress = 40;
let upArrowPress = 38;
let clientInputTextField = "";
let clientVal = "";
onMount(function() {
clientInputTextField.focus();
});
function search(e){
console.log(e.target.value)
const searchString = e.target.value.toLowerCase();
const filteredCharacters = clients.filter((character) => {
return (
character.toLowerCase().includes(searchString) ||
character.toLowerCase().includes(searchString)
);
});
console.log(filteredCharacters)
}
function handleKeydown(event) {
if(event.keyCode === upArrowPress) {
indexVal-=1;
indexVal = indexVal < 0 ? clients.length : indexVal
console.log(indexVal);
}
if(event.keyCode === downArrowPress) {
indexVal+=1;
indexVal = indexVal > clients.length ? 0 : indexVal
console.log(indexVal);
}
if(indexVal > clients.length -1 || indexVal < 0){
clientInputTextField.focus();
} else {
clientInputTextField.blur()
}
}
function handleSubmit(e) {
const value = e.target.input.value;
console.log(value);
clients = [...clients, value];
clientVal = "";
}
</script>
<svelte:window on:keydown={handleKeydown}/>
<form on:submit|preventDefault={handleSubmit}>
<input type="text" name="input" bind:this={clientInputTextField} bind:value={clientVal} on:input={search} autocomplete="off">
<input type="submit" name="">
</form>
<ul>
{#each clients as client, i}
{#if i === indexVal}
<li style="background-color:orange">{client}</li>
{:else}
<li style="">{client}</li>
{/if}
{/each}
</ul>
<!--
-->
BEARBEITEN
Ich bin im Code unten sehr nah dran.
In dieser Version besteht das einzige Problem darin, dass die Liste nicht im DOM angezeigt wird, wenn ein Benutzer eine neue Aufgabe einreicht. Alles andere hinter den Kulissen funktioniert. Um zu sehen, was ich meine, fügen Sie dem Eingabefeld ein Element hinzu, senden Sie es ab, geben Sie den Buchstaben a in das Formularfeld ein und drücken Sie die Rücktaste. Die Liste wird wieder angezeigt.
https://svelte.dev/repl/f8fb733401eb4e27b9b8e54c688d355a?version=3.30.0
<script>
import { onMount } from 'svelte';
let clients = ["a Little piggy","b little piggy","c little piggy"];
let clientsCopy = [...clients];
let indexVal = -1;
let downArrowPress = 40;
let upArrowPress = 38;
let clientInputTextField = "";
let clientVal = "";
onMount(function() {
clientInputTextField.focus();
});
function search(e){
console.log(e.target.value)
const searchString = e.target.value.toLowerCase();
const filteredCharacters = clients.filter((character) => {
return (
character.toLowerCase().includes(searchString) ||
character.toLowerCase().includes(searchString)
);
});
clientsCopy = [...filteredCharacters]
}
function handleKeydown(event) {
if(event.keyCode === upArrowPress) {
indexVal-=1;
indexVal = indexVal < 0 ? clientsCopy.length : indexVal
console.log(indexVal);
}
if(event.keyCode === downArrowPress) {
indexVal+=1;
indexVal = indexVal > clientsCopy.length ? 0 : indexVal
console.log(indexVal);
}
if(indexVal > clientsCopy.length -1 || indexVal < 0){
clientInputTextField.focus();
} else {
clientInputTextField.blur()
}
}
function handleSubmit(e) {
const value = e.target.input.value;
console.log(value);
clients = [...clients, value];
clientVal = "";
}
</script>
<svelte:window on:keydown={handleKeydown}/>
<form on:submit|preventDefault={handleSubmit}>
<input type="text" name="input" bind:this={clientInputTextField} bind:value={clientVal} on:input={search} autocomplete="off">
<input type="submit" name="">
</form>
<ul>
{#each clientsCopy as client, i}
{#if i === indexVal}
<li style="background-color:orange">{client}</li>
{:else}
<li style="">{client}</li>
{/if}
{/each}
</ul>
<!--
-->
Antworten
Ich hab es geschafft. Ich habe eine Kopie des Client-Arrays auf ein reaktives Array gesetzt. Hoffentlich hilft das jemandem.
https://svelte.dev/repl/ad1c185bf97a47b98506c3603f510de6?version=3.30.0
<script>
import { onMount } from 'svelte';
let clients = ["a Little piggy","b little piggy","c little piggy"];
$: clientsCopy = clients ;
let indexVal = -1;
let downArrowPress = 40;
let upArrowPress = 38;
let clientInputTextField = "";
let clientVal = "";
onMount(function() {
clientInputTextField.focus();
});
function search(e){
console.log(e.target.value)
const searchString = e.target.value.toLowerCase();
const filteredCharacters = clients.filter((character) => {
return (
character.toLowerCase().includes(searchString) ||
character.toLowerCase().includes(searchString)
);
});
clientsCopy = [...filteredCharacters]
}
function handleKeydown(event) {
if(event.keyCode === upArrowPress) {
indexVal-=1;
indexVal = indexVal < 0 ? clientsCopy.length : indexVal
console.log(indexVal);
}
if(event.keyCode === downArrowPress) {
indexVal+=1;
indexVal = indexVal > clientsCopy.length ? 0 : indexVal
console.log(indexVal);
}
if(indexVal > clientsCopy.length -1 || indexVal < 0){
clientInputTextField.focus();
} else {
clientInputTextField.blur()
}
}
function handleSubmit(e) {
const value = e.target.input.value;
console.log(value);
clients = [...clients, value];
clientVal = "";
}
</script>
<svelte:window on:keydown={handleKeydown}/>
<form on:submit|preventDefault={handleSubmit}>
<input type="text" name="input" bind:this={clientInputTextField} bind:value={clientVal} on:input={search} autocomplete="off">
<input type="submit" name="">
</form>
<ul>
{#each clientsCopy as client, i}
{#if i === indexVal}
<li style="background-color:orange">{client}</li>
{:else}
<li style="">{client}</li>
{/if}
{/each}
</ul>
<!--
-->
Dies ist eine etwas prägnantere Version von dem, was Sie haben, basierend auf dem Code, der in einem Kern hier zu finden ist . Es ist jedoch praktisch dasselbe wie Ihre Lösung (dh Erstellen und Anzeigen einer separaten "gefilterten" Liste)!
<script>
import { onMount } from 'svelte';
let clients = ["a Little piggy","b little piggy","c little piggy"];
let indexVal = -1;
let downArrowPress = 40;
let upArrowPress = 38;
let clientInputTextField = "";
let clientVal = "";
const startsWith = (item, query) => item.toLowerCase().indexOf(query.toLowerCase()) != -1;
$: filteredClients = clientVal && clientVal.length ? clients.filter(item => startsWith(item, clientVal)) : clients;
onMount(function() {
clientInputTextField.focus();
});
function handleKeydown(event) {
if(event.keyCode === upArrowPress) {
indexVal-=1;
indexVal = indexVal < 0 ? clients.length : indexVal
console.log(indexVal);
}
if(event.keyCode === downArrowPress) {
indexVal+=1;
indexVal = indexVal > clients.length ? 0 : indexVal
console.log(indexVal);
}
if(indexVal > clients.length -1 || indexVal < 0){
clientInputTextField.focus();
} else {
clientInputTextField.blur()
}
}
function onChange(e) {
console.log("what")
const searchTerm = e.target.value.toLowerCase();
console.log(searchTerm)
clients = clients.filter(client => client.toLowerCase().includes(searchTerm))
}
function handleSubmit(e) {
const value = e.target.input.value;
console.log(value);
clients = [...clients, value];
clientVal = "";
}
</script>
<svelte:window on:keydown={handleKeydown}/>
<form on:submit|preventDefault={handleSubmit}>
<!-- <input type="text" name="input" on:change={onChange} bind:this={clientInputTextField} bind:value={clientVal} autocomplete="off"> -->
<input type="text" name="input" bind:this={clientInputTextField} bind:value={clientVal} autocomplete="off">
<input type="submit" name="">
</form>
<ul>
{#each filteredClients as client, i}
{#if i === indexVal}
<li style="background-color:orange">{client}</li>
{:else}
<li style="">{client}</li>
{/if}
{/each}
</ul>