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

[Slider] Add example showing how to access value #3892

Merged
merged 1 commit into from
Apr 13, 2016

Conversation

kerryboyko
Copy link
Contributor

  • PR has tests / docs demo, and is linted.
  • Commit and PR titles begin with [ComponentName], and are in imperative form: "[Component] Fix leaky abstraction".
  • Description explains the issue / use-case resolved, and auto-closes the related issue(s) (http://tr.im/vFqem).

Issue: It was not clear from the documentation how, exactly, to grab the value from the Slider component, as this was not mentioned on the component page. As Standardization of Callback Signatures #2957 states, the way to handle this is onChange={(event, value) => /use 'value' here/} in most cases. I had erroneously tried (event) => event.target.value and (value) => value, and it caused me enough frustration that I felt that when I figured it out I should make a PR and add it to the docs.

The main thing that would have helped me, I think, was to have examples which clearly show how to get the value from the slider element and use it (usually in the component state).

I created a new file in /docs/src/app/components/pages/Slider/ExampleValue.js and amended /docs/src/app/components/pages/Slider/Page.js to include two examples, where moving the slider also alters the slider's value in the state, and re-renders it on the page. As a bonus, I also amended Page.js to make it clear that you can assign values outside the range of 0 and 1 (such as 1-100) to "min" and "max" props.

slider

@kerryboyko
Copy link
Contributor Author

Will withdraw and make changes to get Travis linter to pass.

<Slider
defaultValue={0.5}
value={this.state.value1}
onChange={(event, value) => this.setState({value1: value})}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you create an handler method for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought I could originally, but no - I really can't.

Key point: I submitted this request to change the documentation because it wasn't clear to me how to even get the value from the slider in the first place.

The only way I can see to do it is to use that arrow notation to create a function which contains value was the only way I could do it myself.

That said, I might be able to do something... is this what you're looking for?

  handleSlider (name, value) {
    var stateChange = {}
    stateChange[name] = value;
    this.setState(stateChange);
  }

// ...

          onChange={(event, value) => this.handleSlider('value1', value)}

@oliviertassinari
Copy link
Member

@brianboyko Yes indeed, we need to standardize the callbacks of Material-UI.
I think that it's a good idea to add a controlled example here 👍 .
Notice that we could also document the callback parameters (#3096).

@oliviertassinari oliviertassinari added PR: needs revision The pull request can't be merged. More details is available on the code review or fails in the CI and removed PR: Needs Review labels Apr 9, 2016
@kerryboyko
Copy link
Contributor Author

I don't know if this is what you want (especially since I can't figure out how to work that handler without an arrow function) but here you go

<Slider
defaultValue={0.5}
value={this.state.firstSlider}
onChange={(event, value) => this.handleSlider('firstSlider', value)}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, the idea is to prevent the creating of a function in the render method and, in some aspect, increase readability / reduce the cost of changes.
Here is an example.

handleOpen = () => {
  this.setState({open: true});
};

...

<RaisedButton label="Dialog" onTouchTap={this.handleOpen} />

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I made this pull request because it was unclear how to get the value from the slider.

So far as I can tell, there's no way to actually get the value without putting a function in the render method. This may be a problem that has to be resolved in the source of Slider.js, but that's not applicable here, this is just documenting how to get a value out of a slider.

If there's a better way to do this, please let me know, because this method is the one I came up with after a half-day of beating myself over the head.

If there's a better way to get the value, of course, that should replace this pull request.

Here's the code from material-ui/src/Slider/Slider.js:

//line 366
      // We need to use toFixed() because of float point errors.
      // For example, 0.01 + 0.06 = 0.06999999999999999
      if (this.state.value !== newValue) {
        this.setState({
          percent: newPercent,
          value: parseFloat(newValue.toFixed(5)),
        }, () => {
          if (this.props.onChange) this.props.onChange(event, this.state.value);
        });
      }

As far as I can tell, the only way to pass this.state.value to the handleChange method is via some sort of function.

Perhaps a change like this may be needed to Slider.js:

      if (this.state.value !== newValue) {
        this.setState({
          percent: newPercent,
          value: parseFloat(newValue.toFixed(5)),
        }, () => {
          if (this.props.onChange) this.props.onChange(Object.assign({}, event, {value: this.state.value}, value);
        });
      }

so as to not break backwards compatibility, but allow you to just simply bind the event, like so:

handleSlider1(event) {
    this.setState({'slider1': event.value});
  }
// ...
          onChange={this.handleSlider1.bind(event)}

So, basically, what I'm saying is, so far as I can tell, there's actually no way to get the value from the slider without putting a function in the render method. :( If I'm wrong, I'd be pleasantly surprised! :D

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's no way to actually get the value without putting a function in the render method

It depends of what you mean but putting.
We do need to give a function for the onChange property. However, we don't have to create a new function at each render with a bind.
Look at the example I have linked in the previous comment. That's working fine with an arrow function as a class property.
Well, you will need two handlers here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I think I gotcha. Making an update.

  handleFirstSlider(event, value) {
    this.setState({firstSlider: value});
  }

  handleSecondSlider(event, value) {
    this.setState({secondSlider: value});
  }

  render() {
    return (
      <div>
        <Slider
          defaultValue={0.5}
          value={this.state.firstSlider}
          onChange={this.handleFirstSlider.bind(this)}

@kerryboyko
Copy link
Contributor Author

Figured out what you meant, and learned something in the process!

import sliderCode from '!raw!material-ui/lib/Slider/Slider';

const descriptions = {
simple: 'The `defaultValue` property sets the initial position of the slider. The slider appearance changes when ' +
'not at the starting position.',
stepped: 'By default, the slider is continuous. The `step` property causes the slider to move in discrete ' +
'increments.',
value: 'The slider bar can have a set minimum and maximum, and the value can be ' +
'obtained through the value parameter fired on an onChange event',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing dot at the end.

@oliviertassinari
Copy link
Member

Figured out what you meant, and learned something in the process!

I'm glad and thanks, this example is going to be helpful for others.
I have done just few comments, can you have a look at them?

@kerryboyko
Copy link
Contributor Author

Made those changes, have you checked?

@oliviertassinari oliviertassinari added PR: Needs Review and removed PR: needs revision The pull request can't be merged. More details is available on the code review or fails in the CI PR: Needs Review labels Apr 13, 2016
@oliviertassinari
Copy link
Member

@brianboyko Thanks. That looks good. Could you squash down the commits?

@mbrookes mbrookes changed the title [Documentation/Slider] Add example showing how to access value of <Slider /> component. [Slider] Add example showing how to access value Apr 13, 2016
@mbrookes mbrookes added the docs Improvements or additions to the documentation label Apr 13, 2016
@mbrookes
Copy link
Member

@brianboyko - When you squash, please also reword the commit description to match the current PR title. Thanks!

@kerryboyko
Copy link
Contributor Author

Squishied!

@oliviertassinari oliviertassinari merged commit 1050593 into mui:master Apr 13, 2016
@oliviertassinari
Copy link
Member

@brianboyko Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs Improvements or additions to the documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants