突然无法选中 Svelte 复选框

Svelte checkboxes suddenly can't be checked

下面是重现我的问题的代码 (Svelte 3.0.0)。

重现步骤:

  1. 单击一个复选框。 (表现正常)
  2. 在搜索框中输入一些字符。
  3. 删除您刚刚输入的字符。
  4. 再次单击复选框。请注意,现在它没有任何效果。复选框保持空白。

EDIT: 好像跟这行有关:

bind:group={selectedVars[schemaVar.name].lts}

如果我将其硬编码为:

bind:group={selectedVars['bar'].lts}

然后它工作正常。

知道为什么过滤器会破坏复选框吗?

<script>
  let schema = {
    name: "bar",
    vars: [{ name: "X" }],
  };

  $: availableLTs = ["aaa", "bbb", "ccc", "abc"];

  function matchesSearch(searchString, text) {
    let query = searchString;
    console.log("query is", query);
    if (!query) return true;
    return text.includes(query);
  }

  let selectedChart = 'bar';
  let selectedVars = {X: { lts: [] }};
  $: schemaVars = schema.vars;
  let searchString = "";
</script>

<main>
  {#each schemaVars as schemaVar}
    <h6>
      {schemaVar.name}
      <input type="text" bind:value={searchString} placeholder="Search..." />
    </h6>
    {#each availableLTs as ele}
      {#if matchesSearch(searchString, ele)}
        <div class="form-check">
          <label>
            <input
              type="checkbox"
              class="form-check-input"
              bind:group={selectedVars[schemaVar.name].lts}
              value={ele}
            />
            {ele}
          </label>
        </div>
      {/if}
    {/each}
  {/each}
</main>

你可以这样解决这个问题

在App.Svelte

<script>
  import Checkbox from './Checkbox.svelte';
    
  let schema = {
    name: "bar",
    vars: [{ name: "X" }],
  };

  $: availableLTs = ["aaa", "bbb", "ccc", "ABC"];   
  $: matchesSearch = availableLTs.filter((elem) =>{ return elem.includes(searchString); })

  let selectedChart = 'bar'; 
  let selectedVars = {X: { lts: [] }};
  $: console.log(selectedVars)
  $: schemaVars = schema.vars;
  let searchString = "";
</script>

<main>
  {#each schemaVars as {name}}
    <h6>
      {name}
      <input type="text" bind:value={searchString} placeholder="Search..." />
    </h6>
    <Checkbox bind:value={selectedVars} {name} {matchesSearch}/>
  {/each}
</main>

在Checkbox.Svelte


<script>
    export let value, name, matchesSearch;
</script>

{#each matchesSearch as ele}
    <div class="form-check">
        <label>
            <input
                         type="checkbox"
                         class="form-check-input"
                         bind:group={value[name].lts}
                         value={ele}
            /> 
            {ele}
        </label>
    </div>
{/each}

你可以在这个repl

中查看

看起来问题与嵌套的 each 循环有关

  {#each schemaVars as schemaVar}
    ...
    {#each availableLTs as ele}
      
    ...//Checkbox

    {/each}
  {/each}

可以通过将内部循环包装在组件中来解决。

前面的回答差不多解决了问题,但是漏掉了一个重要的东西: 组件内的每个循环不是 "keyed each block" ->

  1. select第三个复选框'ccc'
  2. 过滤 'c'
  3. -> 'ccc' 移动到第一个位置,不再检查

(或者 select 'aaa' 并过滤 'b'...)

这可以通过将标签文本添加为​​ key/id 来解决(假设复选框标签是唯一的)->

{#each filteredLTs as ele (ele)}        
        ...
{/each}

因为问题不在于变量的设置方式 (...selectedVars[[=​​47=]].lts}),我会尽量保持组件内部的逻辑通用并在 App.svelte 内的组件标签内专门设置变量 -> 组件保持通用并且可以轻松重用 Example in this REPL

[App.svelte]
<script>
import Checkboxes from './Checkboxes.svelte'
    
let schema = {
   name: "bar",
   vars: [{ name: "X" }],
};

let allLTs = ["aaa", "bbb", "ccc", "abc"];
let searchString = "";
    
$: filteredLTs = allLTs.filter(lt => lt.includes(searchString)) 
let selectedVars = {X: { lts: [] }};
    
$: console.log(selectedVars.X.lts)
    
</script>

<main>
  {#each schema.vars as schemaVar}
    <h6>
      {schemaVar.name}
      <input type="text" bind:value={searchString} placeholder="Search..." />
    </h6>
    
    <div class="form-check">
    <Checkboxes checkboxes={filteredLTs} bind:checked={selectedVars[schemaVar.name].lts}/>
  </div>
  {/each}
</main>
[Checkboxes.svelte]
<script>
    export let checkboxes, checked  
</script>

{#each checkboxes as checkbox (checkbox)}        
        <label>
            <input
              type="checkbox"
              class="form-check-input"
              bind:group={checked}
              value={checkbox}
            />
            {checkbox}
   </label>
{/each}