i wanna edit my p element's text when i press edit button.
When i click edit button, i display a textarea and get keyed text with alert but can't put that text to my p element.
What is the simple way to do it with React.js ?
JSFIDDLE
When i press edit button, editing state changing and textarea shows up.The code below.
renderNormal: function() {
return (
<div>
<p>Edit me</p>
<button onClick={this.edit}>Edit</button>
</div>
)
},
renderForm: function() {
return (
<div>
<textarea ref="newText" defaultValue="Edit me"></textarea>
<button onClick={this.save}>Save</button>
</div>
)
},
render: function() {
if (this.state.editing) {
return this.renderForm()
} else {
return this.renderNormal()
}
}
You need to store and retrieve the text from a state variable. Modifying the state causes a re-render, which will then display the updated text. Copied from your JSFiddle... note where I've added a "text" property to your state
var MyCom = React.createClass({
getInitialState: function() {
return {
editing: false,
// ** Initialize "text" property with empty string here
text: ''
}
},
edit: function() {
this.setState({
editing: true
})
},
save: function() {
var val = this.refs.newText.value;
alert(val)
this.setState({
// ** Update "text" property with new value (this fires render() again)
text: val,
editing: false
})
},
renderNormal: function() {
// ** Render "state.text" inside your <p> whether its empty or not...
return (
<div>
<p>{this.state.text}</p>
<button onClick={this.edit}>Edit</button>
</div>
)
},
renderForm: function() {
return (
<div>
<textarea ref="newText" defaultValue="Edit me"></textarea>
<button onClick={this.save}>Save</button>
</div>
)
},
render: function() {
if (this.state.editing) {
return this.renderForm()
} else {
return this.renderNormal()
}
}
})
ReactDOM.render(
<div>
<MyCom/>
<MyCom/>
</div>,
document.querySelector(".box")
)
You have to set a value on the state on the button is clicked, and then read that on render.
Example:
handler : function () {
this.setState({ value : 'hey' });
},
render : function () {
return <p>{ this.state && this.state.value ? this.state.value : 'hoy' }</p>;
}
Everytime you want the render method to change according to something that can happen, the action that triggers it must trigger a state change, and change the state object, and the object will be rerendered, so the render method should check the current state.
If you want to change the value of a input (or in your case, a textarea), you can use the linkedstate pattern as a two way databinding (more here).
I particularly use this lib. There are plenty of examples there.
I actually had this same problem, here was my solution:
{editableSubTasks.filter(id => id === subTask.Id).length > 0 ? <input type="text" /> : <span>{subTask.Name}</span>}
So basically, you have an array, in my case it was editableSubTasks. Whenever I would trigger the text element to change to a textarea, I would simply add that guy to the edtiableSubTasks array. And then in my map function, if the Id of the correspnding item was in the editableSubTasks array, I would use a ternary operator to tell it to be a <input type="text">, otherwise just a span. In your case obviously you can use a textarea. This worked out wonderfully. Here was my SO with the answer that I ended up using:
How to dynamically show/hide a list of items in react
If you don't need the array, then the answer is even simpler, just have a bool and change it to true when you want it to be a text area.
Related
I want to create a React component with a render method that has an <a> tag that wraps an entire "box", if you will, which redirects to another page when clicked. Within said box there is a <button> that can be clicked that activates an event that changes state.
What I want to be able to do is click the <button> and trigger the event without the redirect from the <a> tag occurring.
Tried some ideas with stopPropagation() but no luck :/ I don't want to move the button outside of the <a> tag either so not sure where to go from here.
It seems like it should be something simple but I just can't figure it out. Thanks!
the render method looks like this:
render(){
return(
<div>
<a href="http://www.google.com">
<div className="box">
<h2 className="title">Random Title</h2>
<button onClick={this.handleClick}> Like </button>
</div>
</a>
</div>
)
}
handleClick() would look something like this:
handleClick = () => {
if (this.state.liked) {
console.log("disliking")
} else {
console.log("liking")
}
this.setState({ liked: !this.state.liked})
}
you can achieve this with a simple trick. see what I did -
replace the anchor with a div and place a click handler
add a flag (clicked) with in the component and ignore in div click handler if it's a button click
reset the flag
update - check out this js fiddle :
https://jsfiddle.net/rabinarayanb/pvx2n3x3/
note - I have used es5 syntax. you can convert to es6
(function() {
var BoxSetup = React.createClass({
clicked : "",
getInitialState : function () {
return { clickCount : 0};
},
handleDivClick : function (event) {
if (this.clicked !== "Button") {
window.location.href = "http://www.google.com";
}
// reset
this.clicked = "";
},
handleButtonClick : function (event) {
this.clicked = "Button"
this.setState({
clickCount : ++this.state.clickCount
});
},
render : function () {
return (
<div>
<div onClick={this.handleDivClick} style={ { }}>
<div style={ { width : "100px", height : "100px", border : "1px solid red" } }>
<h2 className="title">{ this.state.clickCount }</h2>
<button onClick={this.handleButtonClick}> Like </button>
</div>
</div>
</div>
);
}
});
var element = React.createElement(BoxSetup, { title : "Hello" });
ReactDOM.render(element, document.getElementById("app"));
})();
What you are wanting to do does not seem possible. Once the user clicks on the <a> enclosed content they will be redirected to the linked content, in your case: http://www.google.com
If you want to execute your function then follow the link you must remove the <a> tag and put window.location = "http://www.google.com"; at the end of your function.
One way this can be done is by setting a reference to the anchor element, then using the button elements onMouseEnter and onMouseLeave to programatically change the anchor elements href property whenever the user moves the mouse over the Like button.
class Test extends React.Component {
constructor(props){
super(props)
this.state={ likes:0 }
this.anchorElement=null;
}
enter = () => { this.anchorElement.href='javascript:;'; }
leave = () => { this.anchorElement.href='http://www.google.com'; }
handleClick = () => { this.setState({ likes: ++this.state.likes}); }
render() {
return (
<div>
<div>{'Likes:'+this.state.likes}</div>
<a href="http://www.google.com" ref={(el) => { if (el) { this.anchorElement = el; } }}>
<div>
<h2 className="title">Random Title</h2>
<button onClick={this.handleClick} onMouseEnter={this.enter} onMouseLeave={this.leave}> Like </button>
</div>
</a>
</div>
);
}
}
See it in action: Working fiddle
In the fiddle you will note the link is activating, but is not going anywhere because it is effectively "turned off" while the button is under the mouse. If you want to get rid of the appearance of activation on the link, a little more manipulation of the anchor element is needed, or simply set the a:active css property to the same color as the base/active color.
Personally, I would avoid the scenario if possible, but that's just good advice, something that more folks around here should learn is not the same thing as an answer.
I have a simple react class which renders a controlled input box of type number.
var Form = React.createClass({
getInitialState: function() {
return { value: 12.12 };
},
handleChange: function(e) {
this.setState({ value: e.target.value });
},
render: function() {
return (
<input
onChange = {(e) => this.handleChange(e)}
type = "number"
value = {this.state.value}
/>
);
}
});
ReactDOM.render( <Form /> , document.getElementById('container'));
This code is present in this jsfiddle.
To change the value, when I delete the numbers one by one and delete the decimal point, the focus suddenly shifts to the start of the input box.
This happens on latest Chrome browser (54.0.2840.87) but not on Firefox.
If I use a defaultValue instead of value in state, on Chrome, even when I add a decimal value to the number, the focus shifts to the start. (The issue happens both on adding decimal value or on deleting the decimal part)
Please refer to this jsfiddle.
I saw the answer to a similar question here. But the problem persists in Chrome when I try to delete numbers till decimal point.
Is there a way to get around this problem?
Thanks in advance for your help.
I wanted to use an input box of type 'number' (for stepper, etc.), so did a work around by using refs.
I took this idea of using refs from an answer to a similar question here.
I do not use defaultValue in the input tag but set the initial value in componentDidMount. And on change, I set value in a variable for future use.
var Form = React.createClass({
componentDidMount() {
this.input.value = "123.12";
},
handleChange: function(e) {
this.value = e.target.value;
},
render: function() {
return (
<input
onChange = {(e) => this.handleChange(e)}
type = "number"
ref={(elem) => this.input = elem}
/>
);
}
});
ReactDOM.render( <Form /> , document.getElementById('container'));
Please find jsfiddle code here.
It happens because your type="number". The e.target.value variable will have type of number too. Since there is no number that has value 12. (happens when you delete last decimal number after decimal point), then e.target.value will simply has value of 12, so the value jump from 12.1 to 12 (note that two characters deleted at the same time). It seems that Chrome doesn't like that change and behave strangely.
The solution for this problem is to simply change your input type to text, and validate your text box on submit.
Or simply strip invalid characters on text box change.
var Form = React.createClass({
getInitialState: function() {
return { value: 12.12 };
},
handleChange: function(e) {
this.setState({
value: e.target.value.replace(/([^0-9\.])/g, '')
});
},
render: function() {
return (
<input
onChange = {(e) => this.handleChange(e)}
type = "text"
value = {this.state.value}
/>
);
}
});
ReactDOM.render( <Form /> , document.getElementById('container'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container"></div>
I'm new to react, I'm curious how to do this properly.
suppose I have this form, by clicking button, I want to get textbox value,
var form = React.createClass({
submit : function(e){
//how to get textbox value?
},
render : function(){
return (
<form>
<input type="text" id="textbox" value="hey, get me"/>
<button onClick={this.submit}>Get it</button>
</form>
);
}
});
Any answer will be appreciated! thank you!
React enforces parent-to-child unidirectional data flow.
So, there's no simple way to access data from siblings.
But, if a child changes the state across the component, you probably want a state for keeping a track of that.
Sample code:
var FormBox = React.createClass({
getInitialState: function () {
return {
textBox: 'hey, get me!'
}
},
pressButton: function () {
alert(this.state.textBox)
},
textChange: function (e) {
this.setState({
textBox: e.target.value
})
},
render: function () {
return (
<form action='.'>
<input type='text' placeholder={this.state.textBox} onChange={this.textChange}/>
<button onClick={this.pressButton}> Get it </button>
</form>
)
}
})
ReactDOM.render(<FormBox />, document.getElementById('root'))
JSBin demo: https://jsbin.com/koxujuwope/edit?js,output
Also, just a suggestion... You should move to ES2015
One way to accomplish this is using refs.
After building your component, you may find yourself wanting to "reach
out" and invoke methods on component instances returned from render(). link to refs docs
Refs are basically the html elements / react instances you want to access. In this case, we want to get Input html element. We get input element by this.inputValue. Then read its value by usual js rule.
var form = React.createClass({
submit : function(e){
e.preventDefault();
console.log(this.inputValue.value);
},
render : function(){
return (
<form onSubmit={this.submit}>
<input type="text" id="textbox" defaultValue="hey, get me"
ref={ function(node){ this.inputValue = node }.bind(this) }
/>
<button onClick={this.submit}>Get it</button>
</form>
);
}
});
here is a jsfiddle for your example, you can check the console for the input value.
Another way to accomplish the same thing is to make your input a controlled element. That means you assign input's value attribute to this.state.inputValue and you pass a onChange event handler as onChange={yourInputHandlerFunction}.
See the answer which explains this way of accomplishing the same thing.
The following code helps me to setup communication between two siblings. The setup is done in their parent during render() and componentDidMount() calls.
It is based on https://reactjs.org/docs/refs-and-the-dom.html
class App extends React.Component<IAppProps, IAppState> {
private _navigationPanel: NavigationPanel;
private _mapPanel: MapPanel;
constructor() {
super();
this.state = {};
}
// `componentDidMount()` is called by ReactJS after `render()`
componentDidMount() {
// Pass _mapPanel to _navigationPanel
// It will allow _navigationPanel to call _mapPanel directly
this._navigationPanel.setMapPanel(this._mapPanel);
}
render() {
return (
<div id="appDiv" style={divStyle}>
// `ref=` helps to get reference to a child during rendering
<NavigationPanel ref={(child) => { this._navigationPanel = child; }} />
<MapPanel ref={(child) => { this._mapPanel = child; }} />
</div>
);
}
}
I am new to React,
My question is:
I have a button (Btn) in html form and a react input text (TXT) component; I want to make the button clicked on the "oninput" event of the txt.
this is the component jsx file:
(function(app){
function component(){
var Date = React.createClass({
getValue: function() {
var el = $(this.getDOMNode());
var input = el[0].childNodes[1].childNodes[0];
return $(input).val();
},
componentDidMount: function() {
var el = $(this.getDOMNode());
var element = el[0].childNodes[1];
$(element).datetimepicker({
autoclose: true,
format: 'yyyy-mm-dd',
startView: 'decade',
minView: 'month',
isRTL: false,
//pickTime: false,
pickerPosition:"bottom-right"
});
},
render: function() {
return (<div className="form-group" style={{display: '-webkit-box'}}>
<label>{this.props.title}</label>
<div className="input-group date ">
<input type="text" name={this.props.name} style={{paddingRight: 0,
fontSize: 12}} readOnly className="form-control" className={this.props.class}/>
<span className="input-group-btn">
<button className="btn default date-set" type="button"><i className="fa fa-calendar"></i></button>
</span>
</div>
</div>);
}
});
function create(elementId,props){
return React.render(<Date {...props} />, document.getElementById(elementId));
}
return {
create:create
};
}
app.component('dateComponent',component);
})(beirutHubBaseApp);
The button is in html file; this button is a search button made by jquery datatable so it has to be in the datatable.
this is the controller:
jd = dateComponent.create('jd',
{
title:"",
name:"filter_joinDate",
class:"form-control form-filter datepicker"
});
So how to make this event?
First of all, instead of having
var el = $(this.getDOMNode());
var element = el[0].childNodes[1];
You should use refs, this is what they are for, see http://facebook.github.io/react/docs/more-about-refs.html .
Second, your getValue function is not at all in the spirit of React. Either you also use refs and then you can get your input value through this.refs.input.value or you use a state to store the value.
Concerning your problem :
if you want to react to the click on the button to trigger something in the text field, you should add the listener in the componentDidMount, like this :
componentDidMount:
var c = this
$("#mybutton").click(function(e) {
// do something here, with c instead of this to refer to the component
})
Do not forget to also implement the componentWillUnmount to clear the listener.
If you want to trigger something in the button in reaction to an input (which I believe is what you are looking for), you should add a listener to the input like this onInput={this.handleInput} and have a handleInput this way :
handleInput:
handleInput: function() {
$("#mybutton").doSomethingWithJquery()
},
I'm trying to switch between a focused / blurred state for a search bar. Right now the tag has a click handler that shows an input field if the element is clicked. I'm trying to reverse this effect and hide the visibility of the input field when the user clicks outside the element.
My code is:
var Search = React.createClass({
getInitialState:function(){
return{ inputVisible:false }
},
showInput:function(){
this.setState({ inputVisible:true });
},
componentDidUpdate:function(){
if( this.state.inputVisible ){
this.getDOMNode().focus();
}
},
renderInput: function(){
return (
<input type="text" style={this.props} />
);
},
renderLink: function(){
return (
<a><h3 onClick={this.showInput}>Search</h3></a>
);
},
render: function() {
if( this.state.inputVisible ){
return this.renderInput();
}else{
return this.renderLink();
}
}
});
I've tried adding logic to the componentDidUpdate function, so that
if (input.state.isVisible == false ) {
this.getDOMNode().blur();
}
I've also tried adding an onBlur handler to the element and tried creating a hideInput method:
hideInput: function() {
this.setState({ inputVisible:false });
}
and adding to the element:
<a><h3 onClick={this.showInput} onBlur={this.hideInput}>Search</h3></a>
But something just isn't working. Can anyone point out what I'm doing wrong?
You can't focus an H3 element without a tabindex attribute, and so it can't be "blurred" to begin with, thus the onBlur event doesn't fire. Try attaching the onBlur event on the rendered input element in your renderInput method.
Here's an example: http://plnkr.co/edit/STMPIkIQEIAZPZQ9SCq4?p=preview