Can one clear the displayed text in a TextInput box?

I’d like to be able to clear the text that is shown in the TextInput widget. My use case involves sliders: I have a slider plus 2 TextInput boxes to optionally set upper and lower limits. If the user uses these boxes, the slider limits are set to them; if the user then uses the slider itself to change the limits again, I’d like to be able to clear out the text that’s displayed in the TextInput boxes.

Can that be done?

Thanks!

Richard

I bet you could do it by using a callback on the slider and setting the TextInput value to an empty string ("").

If you run into problems, just post your code here and we can get more specific!

Yes, but :slight_smile:

When I set the TextInput value it calls the TextInput callback. How do I stop it from doing that?

Your suggestion does indeed blank out the box…

You can’t, but you can check if the new value is the empty string, and then do nothing in the callback in that case:

if new == "": return

That had occurred to me as a hack, but had been hoping to be able to avoid an unnecessary callback call. Oh well.

in any case, that fix did the trick. Thanks!! And thanks for the rapid responses!

Richard

You could also do

slider.remove_on_change(...)
_set value_
slider.on_change(...)

I use this in some of my callback functions that need to manipulate values of itself and/or others.
However it isn’t such a nice solution either :confused:

I feel like I should clarify that when I suggested

if new == "": return

it was not intended as a workaround or anything I would consider hacky. It’s the correct and appropriate way to handle this use case.

I hope a little context might shed light on why things are best as they are. As it is, the operation of callbacks is completely uniform and can be explained in once succinct statement:

Callbacks fire any time a Bokeh model property changes.

I hope everyone agrees that going from "foo" to "" constitutes a change. :slight_smile: Additionally, all users, including the ones who do want to do something when the value is the empty string, can satisfy their needs. Contrast if we start adding special cases:

Callbacks fire any time a Bokeh model property change. Except for these special properties on these modes, that all each behave in these special different ways: .


Now the only way to know for sure what the behavior of a model actual is, is to dig through reference documentation. But worse, there is now an arbitrary limitation on capability that means that any users who do want to respond to the empty string no longer have any recourse to do so.

Well, in my case, there are often non-empty values set to the input box. Like pre-defined standards, the last syntactical correct user input, messages like “Input this and that…” if the box is empty, and various other cases.

Would you consider the approach I posted above as a “non-hacky” and correct/appropriate way as well or could you suggest a better solution?

Based on your way, I also thought about defining a list of strings that would yield in a direct return, like

if new in predefined_strings: return

However this would also ignore user input in some of the cases mentioned at the beginning.

Additionally I found that constructs like

def foo(attr, old, new):
    my_input_box.value = "some text"

my_input_box.on_change('value', foo)

do not end in endless callback loops but is only triggered one additional time.
So foo gets executed twice if the user changes the value in the input box.
Often enough, I’m also ok with this, since the execution is very fast and it does not matter if it runs once or twice, but of course in general leaving it like this is not a good style :smile:

The public APIs are public, so if that suits your need, then it suits your need. I don’t really have an opinion on that. I only wanted to challenge the notion that ignoring empty string changes is somehow bad.

If you wanted to tidy things up you might consider making a simple context manager (untested, just a rough idea)

import contextlib

@contextlib.contextmanager
def silenced(model, attr, callback):
    model.remove_on_change(attr, callback)
    yield model
    model.on_change(attr, callback)

with silenced(model, 'foo', cb):
    # do stuff
1 Like