Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to set inputs from server #139

Merged
merged 25 commits into from Apr 17, 2013
Merged

Add ability to set inputs from server #139

merged 25 commits into from Apr 17, 2013

Conversation

wch
Copy link
Collaborator

@wch wch commented Apr 2, 2013

This is still a work in progress. It implements:

  • Adding session argument to shinyServer(). This will allow us to pass things between the app code and the shinysession object.
  • sending messages to input objects
    • on server: session$send
    • on client: input bindings have receiveMessage function
    • on server side, inputMessages are put in a queue which gets flushed with the rest of the output.
  • sending arbitrary javascript to the client. Unlike inputMessages, these are sent immediately.
  • getting the state of input objects (not yet implemented for all input bindings)
  • unit tests for input bindings (testing receiveMessage and getValue)

See example app at:
https://gist.github.com/wch/5266962

runGist('https://gist.github.com/wch/5266962')

@alexbbrown
Copy link

@alexbbrown alexbbrown commented Apr 2, 2013

Nice, now I can delete a whole lot of code.

-Alex Brown

On Apr 2, 2013, at 3:03 PM, Winston Chang notifications@github.com wrote:

This is still a work in progress. It implements:

Adding session argument to shinyServer(). This will allow us to pass things between the app code and the shinysession object.
sending messages to input objects
on server: session$send
on client: input bindings have receiveMessage function
on server side, inputMessages are put in a queue which gets flushed with the rest of the output.
sending arbitrary javascript to the client. Unlike inputMessages, these are sent immediately.
getting the state of input objects (not yet implemented for all input bindings)
unit tests for input bindings (testing receiveMessage and getValue)
See example app at:
https://gist.github.com/wch/5266962

runGist('https://gist.github.com/wch/5266962')
You can merge this Pull Request by running

git pull https://github.com/wch/shiny set-input
Or view, comment on, or merge it at:

#139

Commit Summary

shiny.js: allow setting inputs and getting input state
Add input binding tests
Add messenge-sending support
Add functions for sending messages to client
Put inputMessage in a queue
Align checkboxes with labels
Add getState and receiveMessage support to selectInputBinding
File Changes

M R/bootstrap.R (15)
M R/shiny.R (35)
A inst/tests-js/SpecRunner.html (88)
A inst/tests-js/fixtures/textInputBinding.html (2)
A inst/tests-js/lib/jasmine-1.3.1/MIT.LICENSE (20)
A inst/tests-js/lib/jasmine-1.3.1/jasmine-html.js (681)
A inst/tests-js/lib/jasmine-1.3.1/jasmine.css (82)
A inst/tests-js/lib/jasmine-1.3.1/jasmine.js (2600)
A inst/tests-js/spec/SpecHelper.js (9)
A inst/tests-js/spec/inputBindingSpec.js (486)
M inst/www/shared/shiny.js (148)
Patch Links:

https://github.com/rstudio/shiny/pull/139.patch
https://github.com/rstudio/shiny/pull/139.diff

@wch
Copy link
Collaborator Author

@wch wch commented Apr 5, 2013

The function bindMultiInput() previously was used to handle checkbox and radio groups, but it isn't needed for the new code, since those are now handled with checkboxGroupInputBinding and radioGroupInputBinding. We do need to keep it around, though, to preserve backward compatibility.

It's important now to make sure that bindMultiInput() doesn't try to work on the new-style checkbox and radio groups. In order to do this, I think there's going to need to be not-pretty code that looks for each case. Here's the HTML for checkbox groups and radio groups, in the old and new styles.

Checkbox group

Checkbox group, old style:

<div class="control-group">
  <label class="control-label" for="in_checkboxgroup">Checkbox group input:</label>
  <input name="in_checkboxgroup" type="checkbox" value="option1"/>
  label 1
  <br/>
  <input name="in_checkboxgroup" type="checkbox" value="option2"/>
  label 2
  <br/>
</div>

Checkbox group, new style:

<div id="in_checkboxgroup" class="control-group shiny-input-checkboxgroup">
  <label class="control-label" for="in_checkboxgroup">Checkbox group input:</label>
  <label class="checkbox">
    <input type="checkbox" name="in_checkboxgroup" id="in_checkboxgroup1" value="option1"/>
    <span>label 1</span>
  </label>
  <label class="checkbox">
    <input type="checkbox" name="in_checkboxgroup" id="in_checkboxgroup2" value="option2"/>
    <span>label 2</span>
  </label>
</div>

Radio group

Radio group, old style:

<label class="control-label">Radio buttons:</label>
<label class="radio">
  <input type="radio" name="in_radio" id="in_radio1" value="option1" checked="checked"/>
  label 1
</label>
<label class="radio">
  <input type="radio" name="in_radio" id="in_radio2" value="option2"/>
  label 2
</label>

Radio group, new style:

<div id="in_radio" class="control-group shiny-input-radiogroup">
  <label class="control-label">Radio buttons:</label>
  <label class="radio">
    <input type="radio" name="in_radio" id="in_radio1" value="option1" checked="checked"/>
    <span>label 1</span>
  </label>
  <label class="radio">
    <input type="radio" name="in_radio" id="in_radio2" value="option2"/>
    <span>label 2</span>
  </label>
</div>

@wch
Copy link
Collaborator Author

@wch wch commented Apr 6, 2013

I've added the input updater functions, so that app authors can easily set input values from server.r. Example app here:
http://glimmer.rstudio.com/winstontest/setinput/

Code here:
https://github.com/wch/testapp/tree/master/setinput

@alexbbrown
Copy link

@alexbbrown alexbbrown commented Apr 6, 2013

Nice, thanks. I especially like the tab one.

Presumably this also means that I can more directly and consistently use set value instead of the custom functions I have in my URL-> input code?

Also, (I should really look at the code before asking this) what is the relationship between :

Initial value of inputs as set by input constructors
Initial value of inputs as set by slider
Initial value of inputs$ as consumed by renderX
Fist stable value of inputs$ as consumed by renderX

-Alex Brown

On Apr 6, 2013, at 7:53 AM, Winston Chang notifications@github.com wrote:

I've added the input updater functions, so that app authors can easily set input values from server.r. Example app here:
http://glimmer.rstudio.com/winstontest/setinput/

Code here:
https://github.com/wch/testapp/tree/master/setinput


Reply to this email directly or view it on GitHub.

@alexbbrown
Copy link

@alexbbrown alexbbrown commented Apr 6, 2013

Okay I have read the code; I think I can guess - there's an input$ at time 0, a stable input$ at some later time, and preferably none in between but maybe.

When the slider is pulled, how many times might a function which depends upon every input except slider be executed? (Please be 1)

Next question: do the input updaters trigger the change event on the input with the #id?

I simulated input updaters by using renderUi with a single input in. However each time the input value was force changed the HTML for the input and its container were destroyed and recreated. This meant that the change events I registered for on the input didn't fire, and I never managed to get a 'create' event to work. It would be great if that's different with these new input updaters.

-Alex Brown

On Apr 6, 2013, at 7:53 AM, Winston Chang notifications@github.com wrote:

I've added the input updater functions, so that app authors can easily set input values from server.r. Example app here:
http://glimmer.rstudio.com/winstontest/setinput/

Code here:
https://github.com/wch/testapp/tree/master/setinput


Reply to this email directly or view it on GitHub.

@wch
Copy link
Collaborator Author

@wch wch commented Apr 7, 2013

Yes, you can use setValue for the all the input bindings. It's probably better to use receiveMessage(), which will allow you to set other values; for example, the min/max/step of a number input. If you take a look at the tests (in inst/tests-js/spec/inputTestBindingSpec.js) you'll see examples of what receiveMessage will accept for various types of inputs. One limitation: slider inputs currently only allow setting of value, and not min/max/step, because the widget we're using doesn't have any provision for changing those values. It may be possible to work around this by having receiveMessage put a new widget on the DOM, but I'll have to experiment with that.

The updateTextInput() and related functions (on the server side) send messages which eventually get passed to receiveMessage() for the appropriate binding on the client side.

Okay I have read the code; I think I can guess - there's an input$ at time 0, a stable input$ at some later time, and preferably none in between but maybe.

You're right that there's an initial value of the input, then the server sends a message to set the inputs on the client side, then the client sends those updated input values to the server.

When the slider is pulled, how many times might a function which depends upon every input except slider be executed? (Please be 1)

If an function doesn't depend on the slider input, then setting the value of the slider should have no effect. Setting the value of an input with updateSliderInput should be just like setting it with normal user input.

Next question: do the input updaters trigger the change event on the input with the #id?

setValue() doesn't trigger a change event, but receiveMessage() does. Functions like updateTextInput() send messages which are processed by receiveMessage(), so the change event is triggered.

@wch
Copy link
Collaborator Author

@wch wch commented Apr 8, 2013

With the version of jslider presently included with Shiny, it appears not to be possible to remove and add back a slider, in order to change min/max/step. With the latest version of jslider on Github, it looks like you can do it, with something like this:

$el = $("#in_slider")
$el.removeData('jslider')
$el.parent().find('.jslider').remove()
$el.slider({ from: 5, to: 40, step: 2.5, round: 1, skin: "round" });

However, the latest Github version of jslider doesn't seem to like the HTML that Shiny generates. This doesn't work properly anymore:

<input id="in_slider" type="slider" name="in_slider" value="15" class="jslider"
  data-from="5" data-to="20" data-step="1" data-skin="plastic"
  data-round="false" data-locale="us" data-format="#,##0.#####"
  data-scale="|;|;|;|;|;|;|;|;|;|;|;|;|;|;|;|" data-smooth="false"/>

I believe it would have to be something like this:

<div class="layout-slider">
  <input id="in_slider" type="slider" name="price" value="20" />
</div>
<script type="text/javascript" charset="utf-8">
  jQuery("#in_slider").slider({
    from: 5, to: 20, step: 1, round: 1, 
    format: { format: '#,##0.#####', locale: 'us' },
    skin: "plastic"
  });
</script>

wch added a commit that referenced this issue Apr 17, 2013
Add ability to set inputs from server
@wch wch merged commit 6715dc2 into rstudio:master Apr 17, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants