Helper not reacting on ReactiveDict change

Hi,

I’m stuck with some ReactiveDict and helper. Could you please help ?

// ReactiveDict init
const stateReactiveDict = new ReactiveDict();

stateReactiveDict.set({
  x: 'active',
  y: 'disabled'
});
// Data structure with autorun (for reactiveDict change)

Tracker.autorun(() => {
  selectBlocks =  [{
    label:"x",
    state: stateReactiveDict.get('x'),
    selectOptions: [...]
  },{
    label:"y",
    state: stateReactiveDict.get('y'),
    selectOptions:[...]
}]
});

// Helper
Template.home.helpers({
  selectBlocks() {
    return selectBlocks
  }
});
// Events
Template.home.events({

  'change #X'(event, template) {
    // Prevent default browser form submit
    event.preventDefault();

    // 1. Get Value
    var element = document.getElementById("X");
    var selectedValue = element.options[element.selectedIndex].value;


    // 2. Update ReactiveDict
    if (selectedValue == "All"){
      sstateReactiveDict.set({
        y: 'disabled'
      });

    } else {
      stateReactiveDict.set({
        y: 'active'
      });
    }
  }
});

Thanks to autorun, selectBlocks.state is updated onChange events, but selectBlocks() helper is not “re-run” and html template doesn’t “see” changes.

What am I doing wrong ?

Thx

Yes this makes sense, because though the array is being updated, the array on itself is not reactive, meaning it will not trigger updates on the helper. To fix it, simply update the array in the helper like this:

Template.home.helpers({
  selectBlocks() {
    return  [{
      label:"x",
      state: stateReactiveDict.get('x'), // This triggers a reactive update of this helper
      selectOptions: [...]
    },{
      label:"y",
      state: stateReactiveDict.get('y'),  // This triggers a reactive update of this helper
      selectOptions:[...]
    }]
  }
});

Template helpers work similar to Tracker.autorun.

1 Like

Thx @cloudspider :pray: :heart_eyes:

Is it a question of “depth” or “scope” ?

Because following your message I tried this, and it triggers :

function testTrigger(reactiveVar){

  const selectBlocks =  [{
      label:"x",
      state: reactiveVar.get('x'), 
      selectOptions: [...]
    },{
      label:"y",
      state: reactiveVar.get('y'),  
      selectOptions:[...]
    }]

  return selectBlocks

}

and in helper :

Template.home.helpers({
  selectBlocks() {
    return testTrigger(stateReactiveDict)
  }
});

This does the job !

Yes, if I understand correctly, you have now made the function reactive, but making it depend on the reactiveDict. Since you call the function in the helper it will work just fine :slight_smile:

This is similar to how React has its hooks set-up and Vue its new composition api:

React

// This is the equivalent of your function
const useCustomState = (defaultVal) => {
   const [reactiveVar, setReactiveVar] = useState(defaultVal)

  return reactiveVar
}

const Component = () => {
  const value = useCustomState();
  return (
    <div>{value}</div>
  )
}
1 Like