Prevent events from being fired for every keystroke on field_input

189 views
Skip to first unread message

The Shumanator

unread,
Apr 28, 2021, 4:34:31 AM4/28/21
to Blockly
Hello,

Currently every keystroke/input field change causes an event fired due to the way setValue and onHtmlInputChange work.

Instead I'm looking to fire an event only when the focusout event occurs (i.e user moves out of the input field).

At the moment, I'm approaching this by creating a custom field input class and extending the existing blockly field input class. I've overriding the following functions:

1. setValue: 2 changes here:
  • Accept a flag to prevent events being fired. This flag will be passed by onHtmlInputChange (see below).
  • Check the 'newValue' against the original oldValue (i.e the value before the user focused into the input field.

2. onHtmlInputChange: pass a flag to setValue function to do everything it normally does except fire out an event.

3. bindInputEvents_: I added focus in and focus out event handlers.

4. unbindInputEvents_: to unbind the focus in event.

5. dispose: to unbind the focus out event.

Moreover, because I have a multiline input field, I've had to do the same as above. 

I'm wondering if there is a better/cleaner way to achieve this at the moment in blockly? 

Thanks

Beka Westberg

unread,
Apr 28, 2021, 10:12:29 AM4/28/21
to blo...@googlegroups.com
Hello,

This is a common issue that people have with the text input field =) And I like your approach to fixing it! I think that's a good way to handle it, but there's an additional method that I usually recommend.

All you do is take the text input field you want to listen to and assign a function to its onFinishEditing_ property. For example, the procedure blocks do this.
```
var field = new Blockly.FieldTextInput('default text');
field.onFinishEditing_ = function(finalVal) {
  // Do whatever with the finalVal.
}
```

This function will then get called whenever the field's text editor closes (so when it loses focus). It is a bit of a hack, but I've recommended this to at least half a dozen other people (plus the procedure blocks use it), so I doubt it's ever going away.

I hope that helps! If you have any further questions please reply!
--Beka

--
You received this message because you are subscribed to the Google Groups "Blockly" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blockly+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/blockly/adad7aac-6182-4fa2-a78b-c3de794ff4e0n%40googlegroups.com.

The Shumanator

unread,
Apr 29, 2021, 3:54:06 AM4/29/21
to Blockly
Thanks Beka! That was helpful. I don't need the focusout event handler anymore :-)

With regards to suppressing the fire event on the field's setValue fn here. I'm wondering if there is something I could do instead? At the moment I'm suppressing it using the workaround I mentioned above (by passing a flag to setValue from onHtmlInputChange).

Thanks

Beka Westberg

unread,
Apr 29, 2021, 10:04:36 AM4/29/21
to blo...@googlegroups.com
Hello,

I have a few ideas, but I'm not sure which applies to your situation. It really depends on what you're trying to achieve by suppressing the event, which I'm not sure of. Could you provide some context about what you're trying to prevent by killing the firing of the event? Eg is there a change listener that has erroneous behavior if the events are fired?

Honestly I think that having the extra flag is a good idea! It modifies just the behavior you want it to, and it should be pretty easy to maintain (as far as monkey-patches go).

You could also use the Blockly.Events.disable and Blockly.Events.enable functions to temporarily disable events when you set the value from onHtmlInputChange. But this would still require modifying the core files, so I'm not sure if there's really an advantage to achieving the behavior in this way :/
```
Blockly.FieldTextInput.prototype.onHtmlInputChange_ = function(_e) {
  var text = this.htmlInput_.value;
  if (text !== this.htmlInput_.oldValue_) {
    this.htmlInput_.oldValue_ = text;

    // TODO(#2169): Once issue is fixed the setGroup functionality could be
    //              moved up to the Field setValue method. This would create a
    //              broader fix for all field types.
    Blockly.Events.setGroup(true);
    var value = this.getValueFromEditorText_(text);
    Blockly.Events.disable(); // Added!
    this.setValue(value);
    Blockly.Events.enable(); // Added!
    this.forceRerender();
    this.resizeEditor_();
    Blockly.Events.setGroup(false);
  }
};
```

Best wishes,
--Beka

Reply all
Reply to author
Forward
0 new messages