PlutoUI.jl icon indicating copy to clipboard operation
PlutoUI.jl copied to clipboard

Button should return number of clicks?

Open fonsp opened this issue 5 years ago • 16 comments

Right now the Button always returns the same: the label of the button (String). This is fine, you can use the button to "trigger reactivity" just by referencing the bound variable somewhere:

https://github.com/fonsp/PlutoUI.jl/blob/v0.6.1/src/Builtins.jl#L64-L86

But if you only want to do something after the button is clicked, you need to write that logic yourself:

begin
    clicked_ref = Ref(false)
	@bind click Button("Do it!")
end
begin
	if clicked_ref[]
		something()
	end
    clicked_ref[] = true
end

Instead we could have the bound value be the number of times it was clicked:

@bind click Button("Do it!")
if click > 0
	something()
end

fonsp avatar Sep 17 '20 10:09 fonsp

@GiggleLiu @dralletje

fonsp avatar Sep 17 '20 10:09 fonsp

Another option is to add a new element: ToggleButton, which looks like a button, but feels like a checkbox

fonsp avatar Sep 17 '20 10:09 fonsp

Returning the counter is definitely better, besides providing more information, it also makes it clear that a click changes a value. It took me a while to understand the meaning of a button, and the answer is "nothing" :rofl:

Returning a counter is not enough, a loophole of the above solution is

if click > 0
        other_vars
	something()
end

When click > 0 and other_vars is updated, it can still run.

I posted a possible solution here https://github.com/fonsp/PlutoUI.jl/issues/37#issuecomment-694432874

GiggleLiu avatar Sep 17 '20 19:09 GiggleLiu

But that's reactivity 😅 I'll comment more on the other issue

fonsp avatar Sep 19 '20 13:09 fonsp

Yeah, I mean it requires people to understand the logic of Pluto. Is it possible to let button return a button object so that one can use the button like:

if button.signal()  # this is not julian, see bellow.
    # do something
end

There is a field _signal in the button object, and

  • set _signal = true if the button is clicked,
  • return the value of _signal when calling signal(),
  • signal() function will reset the _signal field to false.

GiggleLiu avatar Sep 20 '20 02:09 GiggleLiu

onclick(button) do
	... 
end

:o

dralletje avatar Sep 20 '20 03:09 dralletje

https://github.com/fonsp/PlutoUI.jl/issues/37#issuecomment-695217352

fonsp avatar Sep 20 '20 10:09 fonsp

But won't returning the number of times it is clicked generate a hidden state, namely the number of clicks? If someone wants an incremental counter, they can simply trigger reactivity in a cell which also updates a variable.

Or implement a Counter which can be both incremented and decreased. A button shouldn't return how many times it's clicked, just the fact that it is clicked.

DhruvaSambrani avatar Oct 10 '20 23:10 DhruvaSambrani

How about allowing to bind an already existing function name to the Button which then calls the function on click?

begin
  function onclick(text)
    dostuff()
    println("Button $text has been pressed")
  end
  @bind onclick Button("Do it!")
  @bind onclick Button("Do other!")
end

internal implementation might be a bit cumbersome but with (@isdefined binding) && binding isa Function && binding(text) this should be possible. Sure, that has the drawback that only functions can be used here, but that's a restriction that is very easy to overcome.

rapus95 avatar Apr 12 '21 07:04 rapus95

@rapus95 It's a cool idea, but if you think about, it does not work with the way you write interactivity in Pluto. The cool thing about Pluto is that, instead of callbacks, we work with global variables as the way to make things interactive. In fact, it is not possible for a function to produce any kind of visual output, since the are no display side-effects in Pluto.

fonsp avatar Apr 12 '21 12:04 fonsp

@fonsp While that's true, there's no good way to barrier a cell from arbitrary evaluation on startup. We'd need an option to make a cell ONLY execute on the click of a button. I.e. there's no elegant way to prevent evaluation until the click.

rapus95 avatar Apr 13 '21 01:04 rapus95

@bind num_clicks Button()
if num_clicks > 0
	...
end

fonsp avatar Apr 13 '21 08:04 fonsp

And the counter is reset once the cell with the @bind is re-evaluated, right? Then that would be awesome. Is there an eta for it? :D

rapus95 avatar Apr 14 '21 00:04 rapus95

In fact, it is not possible for a function to produce any kind of visual output, since the are no display side-effects in Pluto.

That could individually be solved by adding some sort of triggerupdate(:trigger) function that allows for manually triggering the flow graph for certain variables. Though, I see that would make it necessary to wrap every cell into its own function and pass it a global state object 🤔 Probably not worth the effort.

Will the feature that the button references the click counter make it into Pluto? Arbitrarily breaking out of reactivity would also be very easy since it just requires an additional ref that holds a "counter at last time executed" number or any other relative number. I.e. triggering by comparison to a reference value.

rapus95 avatar Apr 21 '21 01:04 rapus95

Together with https://github.com/fonsp/disorganised-mess/blob/f0f13eb4038604f0cccf12922cea6a4c635c6633/javascript.jl#L97-L128 (and div replaced by span in order to allow inline) the following code

begin
	reactivitybreaker = Dict{Symbol, Int}()
	function needsupdate(x::Symbol, value)
		value != get(reactivitybreaker, x, 0)
	end
	function update!(x::Symbol, value; force=false)
		if force || needsupdate(x, value)
			reactivitybreaker[x] = value
			return true
		end
		return false
	end
	macro update!(x)
		return Expr(:call, :update!, QuoteNode(x), esc(x))
	end
end

allows for

@bind clicker ClickCounter("Click It!")

to be the only way to trigger the following print

if @update!(clicker)
  println(clicker)
end

rapus95 avatar Apr 27 '21 03:04 rapus95

I added CounterButton in PlutoUI 0.7.16 which does https://github.com/fonsp/PlutoUI.jl/issues/38#issuecomment-818532913

In PlutoUI 0.8.0 I will CounterButton the default Button.

fonsp avatar Oct 11 '21 12:10 fonsp