@samitouri / QOS-React-2 / commits / 4f2d8dfe72
Fork 0

The library for web and native user interfaces.

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.

CommitSyncScript committed Jun 24, 2013 at 16:09 UTC 4f2d8dfe720aa5061ada4b027848b180a662b068
3 files changed +129 -5
src/core/ReactDefaultInjection.js
+6 -5
@@ -45,14 +45,15 @@ function inject() {
45 'TextChangeEventPlugin': TextChangeEventPlugin
46 });
47
48 - /*
49 - * This is a bit of a hack. We need to override the <form> element
50 - * to be a composite component because IE8 does not bubble or capture
51 - * submit to the top level. In order to make this work with our
52 - * dependency graph we need to inject it here.
48 + /**
49 + * This is a bit of a hack. We need to override the <form> element to be a
50 + * composite component because IE8 does not bubble or capture submit to the
51 + * top level. In order to make this work with our dependency graph we need to
52 + * inject it here.
53 */
54 ReactDOM.injection.injectComponentClasses({
55 form: ReactDOMForm
56 + // TODO: Inject `ReactDOMInput`.
57 });
58 }
59
src/dom/components/ReactDOMForm.js renamed
src/dom/components/ReactDOMInput.js new
+123
@@ -0,0 +1,123 @@
1 +/**
2 + * Copyright 2013 Facebook, Inc.
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + *
16 + * @providesModule ReactDOMInput
17 + */
18 +
19 +"use strict";
20 +
21 +var DOMPropertyOperations = require('DOMPropertyOperations');
22 +var ReactCompositeComponent = require('ReactCompositeComponent');
23 +var ReactDOM = require('ReactDOM');
24 +
25 +var merge = require('merge');
26 +
27 +// Store a reference to the <input> `ReactNativeComponent`.
28 +var input = ReactDOM.input;
29 +
30 +/**
31 + * Implements an <input> native component that allows setting these optional
32 + * props: `checked`, `value`, `defaultChecked`, and `defaultValue`.
33 + *
34 + * If `checked` or `value` are not supplied (or null/undefined), user actions
35 + * that affect the checked state or value will trigger updates to the element.
36 + *
37 + * If they are supplied (and not null/undefined), the rendered element will not
38 + * trigger updates to the element. Instead, the props must change in order for
39 + * the rendered element to be updated.
40 + *
41 + * The rendered element will be initialized as unchecked (or `defaultChecked`)
42 + * with an empty value (or `defaultValue`).
43 + *
44 + * @see http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html
45 + */
46 +var ReactDOMInput = ReactCompositeComponent.createClass({
47 +
48 + getInitialState: function() {
49 + return {
50 + checked: this.props.defaultChecked || false,
51 + value: this.props.defaultValue || ''
52 + };
53 + },
54 +
55 + getChecked: function() {
56 + return this.props.checked != null ? this.props.checked : this.state.checked;
57 + },
58 +
59 + getValue: function() {
60 + return this.props.value != null ? this.props.value : this.state.value;
61 + },
62 +
63 + render: function() {
64 + // Clone `this.props` so we don't mutate the input.
65 + var props = merge(this.props);
66 +
67 + props.checked = this.getChecked();
68 + props.value = this.getValue();
69 +
70 + // TODO: Re-implement `onChange` with the implementation of `onTextChange`.
71 + if (props.type === 'text' || props.type === 'password') {
72 + props.onTextChange = this.handleTextChange;
73 + } else {
74 + props.onChange = this.handleChange;
75 + }
76 +
77 + return input(props, this.props.children);
78 + },
79 +
80 + componentDidUpdate: function(prevProps, prevState, rootNode) {
81 + if (this.props.checked != null) {
82 + DOMPropertyOperations.setValueForProperty(
83 + rootNode,
84 + 'checked',
85 + this.props.checked || false
86 + );
87 + }
88 + if (this.props.value != null) {
89 + DOMPropertyOperations.setValueForProperty(
90 + rootNode,
91 + 'value',
92 + this.props.value || ''
93 + );
94 + }
95 + },
96 +
97 + handleTextChange: ReactCompositeComponent.autoBind(function(event) {
98 + var returnValue;
99 + if (this.props.onTextChange) {
100 + returnValue = this.props.onTextChange(event);
101 + }
102 + this.setState({
103 + checked: event.target.checked,
104 + value: event.target.value
105 + });
106 + return returnValue;
107 + }),
108 +
109 + handleChange: ReactCompositeComponent.autoBind(function(event) {
110 + var returnValue;
111 + if (this.props.onChange) {
112 + returnValue = this.props.onChange(event);
113 + }
114 + this.setState({
115 + checked: event.target.checked,
116 + value: event.target.value
117 + });
118 + return returnValue;
119 + })
120 +
121 +});
122 +
123 +module.exports = ReactDOMInput;