Multiple Triggers on SignalListener - Vega-Lite + Mutable #1829
-
| 
         I’m encountering an issue with a bar chart implementation using Vega-Lite in Observable. My problem lies in how the  Expected Behavior: 
 Observed Behavior: 
 This behavior disrupts the dynamic of resetting another chart, which depends on a comparison between the  CodeBelow is the relevant code: Data let energyConsumptionData = [
  { "consumption_type": "Others", "annual_consumption": 80704749 },
  { "consumption_type": "Commercial", "annual_consumption": 97715805 },
  { "consumption_type": "Industrial", "annual_consumption": 188268304 },
  { "consumption_type": "Residential", "annual_consumption": 164323258 }
];Chart Specification let barChart = vl.render({
  spec: {
    width: 500,
    height: 300,
    data: { values: energyConsumptionData },
    mark: { type: "bar" },
    selection: {
        barSelect: {
            fields: ["consumption_type"],
            on: "click",
            type: "single"
        }
    },
    encoding: {
      x: {
        field: "annual_consumption", 
        type: "quantitative",
        title: "Annual Consumption (MWh)"
      },
      y: {
        field: "consumption_type",
        type: "nominal",
        title: "Consumption Type"
      }
    }
  }
});
let barChartView = view(barChart);Signal Handling let setSelectedBar = (x) => { barSelectionSignal.value = x };
let barSelectionSignal = Mutable(null);
let defaultSelectionSignal = Mutable(null);
function handleBarSelection(name, value) {
    console.log("Handler called");
    if (barSelectionSignal !== defaultSelectionSignal) {
        console.log("barSelectionSignal mismatch. Resetting.");
        setSelectedBar(null);
    } else {
        console.log("Setting to:", value.consumption_type[0]);
        setSelectedBar(value.consumption_type[0]);
    }
}
barChartView.addSignalListener("barSelect", handleBarSelection);I have  
 Any guidance, insights, or best practices would be greatly appreciated.  | 
  
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
| 
         At a glance, I don't see anywhere that you are unregistering the event handler. That would mean that every time the barchartView is updated and the signal handling block is re-run, you'd get duplicate events. This might not be the problem you're seeing, but as a matter of best practices I'd recommend removing the signal listener in response to the  invalidation.then(() => barChartView.removeSignalListener("barSelect", handleBarSelection)); | 
  
Beta Was this translation helpful? Give feedback.
-
| 
         Keep in mind that the perceived value of a  So if  I’m not actually sure you need to check whether the value changed before assigning to the mutable; that was probably a bug from registering multiple event listeners. And you won’t need to use the  Putting all that together, this seems to work: const barChart = display(await vl.render(…));
const barSelection = Mutable(null);
barChart.value.addSignalListener("barSelect", (name, value) => {
  barSelection.value = value.consumption_type?.[0] ?? null;
}); | 
  
Beta Was this translation helpful? Give feedback.
At a glance, I don't see anywhere that you are unregistering the event handler. That would mean that every time the barchartView is updated and the signal handling block is re-run, you'd get duplicate events. This might not be the problem you're seeing, but as a matter of best practices I'd recommend removing the signal listener in response to the
invalidationpromise. I'd expect that to be something like