Svelte on:change 运行太晚
Svelte on:change runs too late
我有一个 Svelte 应用:
- 可让您选择要查看的图表(饼图/条形图/日历)的下拉菜单
- 包含要包含在图表中的变量的复选框面板。 (不同的图表有不同的可用变量)
- 仅针对选定变量过滤我的数据,然后将该数据传递到图表的函数。
您可以在此处 运行 获取完整代码:
<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}
放入图表下拉列表中。但是,每次我将图表类型从 'calendar' 更改为 'bar chart' 时,我的 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
更改后才会得到 运行,所以为时已晚。
有什么建议吗?我的代码如下。
你确定吗,错误发生在makeChartData
函数中?
可能是这一行:bind:group={selectedVars[schemaVar.name].lts}
我还没有完全理解你的代码,但应该可以用反应语句将 selectedVars
的值更改为所需的值。所以,我认为您不需要 on:change
处理程序。
编辑:
我想你想要这样的东西:https://svelte.dev/repl/57d760278e0e4acfad536c1269bceba3?version=3.37.0
我有一个 Svelte 应用:
- 可让您选择要查看的图表(饼图/条形图/日历)的下拉菜单
- 包含要包含在图表中的变量的复选框面板。 (不同的图表有不同的可用变量)
- 仅针对选定变量过滤我的数据,然后将该数据传递到图表的函数。
您可以在此处 运行 获取完整代码:
<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}
放入图表下拉列表中。但是,每次我将图表类型从 'calendar' 更改为 'bar chart' 时,我的 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
更改后才会得到 运行,所以为时已晚。
有什么建议吗?我的代码如下。
你确定吗,错误发生在makeChartData
函数中?
可能是这一行:bind:group={selectedVars[schemaVar.name].lts}
我还没有完全理解你的代码,但应该可以用反应语句将 selectedVars
的值更改为所需的值。所以,我认为您不需要 on:change
处理程序。
编辑: 我想你想要这样的东西:https://svelte.dev/repl/57d760278e0e4acfad536c1269bceba3?version=3.37.0