首页 > 解决方案 > Svelte on:改变来得太晚

问题描述

我有一个 Svelte 应用程序:

  1. 允许您选择要查看的图表的下拉列表(饼图/条形图/日历)
  2. 带有要包含在图表中的变量的复选框面板。(不同的图表有不同的可用变量)
  3. 仅针对选定变量过滤我的数据的函数,然后将该数据传递到图表。

您可以在此处运行的完整代码:

<script>
  let rawData = {
    LevelTracker: [{ text: "headache" }, { text: "pain" }],
    EventType: [{ text: "coffee" }, { text: "aspirin" }],
    Event: [
      { time: 1500000000, text: "coffee" },
      { time: 1500030000, text: "aspirin" },
      { time: 1500230000, text: "coffee" },
      // etc....
    ],
    LevelChange: [
      { time: 1500000000, text: "headache", level: 2 },
      { time: 1500030000, text: "headache", level: 3 },
      { time: 1500230000, text: "pain", level: 2 },
      // etc....
    ],
  };

  $: availableLTs = rawData.LevelTracker.map((e) => e.text);
  $: availableETs = rawData.EventType.map((e) => e.text);

  let schemas = [
    {
      name: "byTimeOfDay",
      vars: [{ name: "X", et: true, lt: true }],
    },
    {
      name: "lagBarChart",
      vars: [
        { name: "X", min: 1, et: true, lt: false },
        { name: "Y", min: 1, max: 1, lt: true, et: true },
      ],
    },
    {
      name: "calendar",
      vars: [{ name: "X", et: true, lt: true }],
    },
  ];
  let chartsMap = {};
  for (let schema of schemas) {
    chartsMap[schema.name] = schema;
  }
  //let selectedChart = "lagBarChart";
  //let selectedChart = "byTimeOfDay";
  let selectedChart = "calendar";

  function getInitSelectedVars(schemaVars) {
    let selection = {};
    for (let varSchema of schemaVars) {
      selection[varSchema.name] = { ets: [], lts: [] };
    }
    return selection;
  }

  function initSelectedVars() {
    console.log("in initSelectedVars");
    selectedVars = getInitSelectedVars(schemaVars);
  }

  function makeChartData({ selectedVars, rawData }) {
    console.log("in makeChartData");
    for (let [key, value] of Object.entries(selectedVars)) {
      // TODO: we filter rawData for just the selected vars, and return that data...
    }
  }

  // this will be passed to the chart component
  $: chartData = makeChartData({
    selectedVars,
    rawData,
  });

  $: schemaVars = chartsMap[selectedChart].vars;

  $: selectedVars = selectedVars || getInitSelectedVars(schemaVars);
</script>

<main>
  <h2>Select chart type</h2>
  <select bind:value={selectedChart} on:change={initSelectedVars}>
    {#each schemas as chart}
      <option value={chart.name}>
        {chart.name}
      </option>
    {/each}
  </select>

  <h2>Select your vars</h2>

  {#each schemaVars as schemaVar}
    <h3>
      {schemaVar.name}
    </h3>
    {#if schemaVar.lt}
      {#each availableLTs as ele}
        <div class="form-check">
          <label>
            <input
              type="checkbox"
              class="form-check-input"
              bind:group={selectedVars[schemaVar.name].lts}
              value={ele}
            />
            {ele}
          </label>
        </div>
      {/each}
    {/if}
    {#if schemaVar.et}
      {#each availableETs as ele}
        <div class="form-check">
          <label>
            <input
              type="checkbox"
              class="form-check-input"
              bind:group={selectedVars[schemaVar.name].ets}
              value={ele}
            />
            {ele}
          </label>
        </div>
      {/each}
    {/if}
  {/each}

  <!-- then we display the selected chart, like:
     <calendar {chartData} />
   -->
</main>

<style>
</style>

每次用户更改下拉菜单时,我们都需要重新初始化selectedVars为与当前图表架构匹配的值。

例如,如果选择了日历,我们需要这样做:

selectedVars = {X: {ets: [], lts: []}}

但是如果选择了条形图,我们需要:

selectedVars = {X: {ets: [], lts: []}, Y: {ets: [], lts: []}}

我定义了一个执行此操作的函数,并将on:change={initSelectedVars}其放入图表下拉列表中。但是,每次我将图表类型从“日历”更改为“条形图”时,我仍然会收到错误消息makeChartData

Uncaught (in promise) TypeError: Cannot read property 'lts' of undefined
    at Object.mount [as m] (Debug.svelte:101)
    at Object.mount [as m] (Debug.svelte:95)
    at Object.mount [as m] (Debug.svelte:109)
    at Object.update [as p] (Debug.svelte:90)
    at update (index.mjs:764)
    at flush (index.mjs:732)

我认为 on:change 函数只会在selectedVars更改后运行,所以为时已晚。

有什么建议么?我的代码如下。

标签: javascriptsvelte

解决方案


您确定错误发生在makeChartData函数中吗?
可能是这一行:bind:group={selectedVars[schemaVar.name].lts}

我还没有完全理解你的代码,但是应该可以selectedVars使用响应式语句将值更改为所需的值。所以,我认为你不需要on:change处理程序。

编辑:我想你想要这样的东西:https ://svelte.dev/repl/57d760278e0e4acfad536c1269bceba3?version=3.37.0


推荐阅读