mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Dynamic Input Component
Summary:
This is a proposal based loosely on the discussions I've had with @paulshen and @jwalke. It implements a shim for `React.DOM.input` (used as `<input>`) that supports two different use cases depending on whether `value` is provided or not.
If a `value` is //not// provided, the input will be initialized with the empty string (or `defaultValue`) and anytime the user changes the input, the `onChange` (or `onTextChange`) handler will be fired and the DOM will reflect the new changes.
React.renderComponent(
<input type="text" defaultValue="Untitled" onTextChange={handleChange} />,
container
);
If a `value` is provided, the input will be initialized to that value. Anytime the user changes the input, the `onChange` (or `onTextChange`) handler will be fired. However, the DOM will //not// reflect the new changes. If a `value` is provided, it is the responsibility of the owner to update the `value` prop passed in.
var value = "Untitled";
var input = React.renderComponent(
<input type="text" value={value} onTextChange={handleChange} />,
container
);
function handleChange(event) {
// Do something cool like strip out non-numbers.
var value = event.target.value.replace(/\D/g, '');
input.setProps({value: value});
}
This is just a start and we should build similar components for `textarea` and `select`. Also, this does not inject the new components because the changes are not backward compatible. Once we change all `<input>` uses to use `ReactDOMInput`, then we can inject.
This commit is contained in:
committed by
Paul O’Shannessy
parent
7c60bb3e54
commit
4f2d8dfe72
@@ -45,14 +45,15 @@ function inject() {
|
||||
'TextChangeEventPlugin': TextChangeEventPlugin
|
||||
});
|
||||
|
||||
/*
|
||||
* This is a bit of a hack. We need to override the <form> element
|
||||
* to be a composite component because IE8 does not bubble or capture
|
||||
* submit to the top level. In order to make this work with our
|
||||
* dependency graph we need to inject it here.
|
||||
/**
|
||||
* This is a bit of a hack. We need to override the <form> element to be a
|
||||
* composite component because IE8 does not bubble or capture submit to the
|
||||
* top level. In order to make this work with our dependency graph we need to
|
||||
* inject it here.
|
||||
*/
|
||||
ReactDOM.injection.injectComponentClasses({
|
||||
form: ReactDOMForm
|
||||
// TODO: Inject `ReactDOMInput`.
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Copyright 2013 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @providesModule ReactDOMInput
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var DOMPropertyOperations = require('DOMPropertyOperations');
|
||||
var ReactCompositeComponent = require('ReactCompositeComponent');
|
||||
var ReactDOM = require('ReactDOM');
|
||||
|
||||
var merge = require('merge');
|
||||
|
||||
// Store a reference to the <input> `ReactNativeComponent`.
|
||||
var input = ReactDOM.input;
|
||||
|
||||
/**
|
||||
* Implements an <input> native component that allows setting these optional
|
||||
* props: `checked`, `value`, `defaultChecked`, and `defaultValue`.
|
||||
*
|
||||
* If `checked` or `value` are not supplied (or null/undefined), user actions
|
||||
* that affect the checked state or value will trigger updates to the element.
|
||||
*
|
||||
* If they are supplied (and not null/undefined), the rendered element will not
|
||||
* trigger updates to the element. Instead, the props must change in order for
|
||||
* the rendered element to be updated.
|
||||
*
|
||||
* The rendered element will be initialized as unchecked (or `defaultChecked`)
|
||||
* with an empty value (or `defaultValue`).
|
||||
*
|
||||
* @see http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html
|
||||
*/
|
||||
var ReactDOMInput = ReactCompositeComponent.createClass({
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
checked: this.props.defaultChecked || false,
|
||||
value: this.props.defaultValue || ''
|
||||
};
|
||||
},
|
||||
|
||||
getChecked: function() {
|
||||
return this.props.checked != null ? this.props.checked : this.state.checked;
|
||||
},
|
||||
|
||||
getValue: function() {
|
||||
return this.props.value != null ? this.props.value : this.state.value;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// Clone `this.props` so we don't mutate the input.
|
||||
var props = merge(this.props);
|
||||
|
||||
props.checked = this.getChecked();
|
||||
props.value = this.getValue();
|
||||
|
||||
// TODO: Re-implement `onChange` with the implementation of `onTextChange`.
|
||||
if (props.type === 'text' || props.type === 'password') {
|
||||
props.onTextChange = this.handleTextChange;
|
||||
} else {
|
||||
props.onChange = this.handleChange;
|
||||
}
|
||||
|
||||
return input(props, this.props.children);
|
||||
},
|
||||
|
||||
componentDidUpdate: function(prevProps, prevState, rootNode) {
|
||||
if (this.props.checked != null) {
|
||||
DOMPropertyOperations.setValueForProperty(
|
||||
rootNode,
|
||||
'checked',
|
||||
this.props.checked || false
|
||||
);
|
||||
}
|
||||
if (this.props.value != null) {
|
||||
DOMPropertyOperations.setValueForProperty(
|
||||
rootNode,
|
||||
'value',
|
||||
this.props.value || ''
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
handleTextChange: ReactCompositeComponent.autoBind(function(event) {
|
||||
var returnValue;
|
||||
if (this.props.onTextChange) {
|
||||
returnValue = this.props.onTextChange(event);
|
||||
}
|
||||
this.setState({
|
||||
checked: event.target.checked,
|
||||
value: event.target.value
|
||||
});
|
||||
return returnValue;
|
||||
}),
|
||||
|
||||
handleChange: ReactCompositeComponent.autoBind(function(event) {
|
||||
var returnValue;
|
||||
if (this.props.onChange) {
|
||||
returnValue = this.props.onChange(event);
|
||||
}
|
||||
this.setState({
|
||||
checked: event.target.checked,
|
||||
value: event.target.value
|
||||
});
|
||||
return returnValue;
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
module.exports = ReactDOMInput;
|
||||
Reference in New Issue
Block a user