I currently have this component in React.JS which shows all the Images passed to it in an array and onMouseOver it shows a button below. I planed on using setState to check the variable hover if is true or false and toggle the button of that image accordingly however I keep getting the following error:
Uncaught TypeError: Cannot read property 'state' of undefined
var ImageList = React.createClass({
getInitialState: function () {
return this.state = { hover: false };
},
getComponent: function(index){
console.log(index);
if (confirm('Are you sure you want to delete this image?')) {
// Save it!
} else {
// Do nothing!
}
},
mouseOver: function () {
this.setState({hover: true});
console.log(1);
},
mouseOut: function () {
this.setState({hover: false});
console.log(2);
},
render: function() {
var results = this.props.data,
that = this;
return (
<ul className="small-block-grid-2 large-block-grid-4">
{results.map(function(result) {
return(
<li key={result.id} onMouseOver={that.mouseOver} onMouseOut={that.mouseOut} ><img className="th" alt="Embedded Image" src={"data:" + result.type + ";" + "base64," + result.image} /> <button onClick={that.getComponent.bind(that, result.patientproblemimageid)} className={(this.state.hover) ? 'button round button-center btshow' : 'button round button-center bthide'}>Delete Image</button></li>
)
})}
</ul>
);
}
});
You get the error because you're storing the reference to this in a that variable which you're using to reference your event handlers, but you're NOT using it in the ternary expression to determine the className for the button element.
your code:
<button
onClick={ that.getComponent.bind(that, result.patientproblemimageid) }
className={ (this.state.hover) ? // this should be that
'button round button-center btshow' :
'button round button-center bthide'}>Delete Image
</button>
When you change this.state.hover to that.state.hover you won't get the error.
On a side note, instead of storing the reference to this in a that variable you can simple pass a context parameter to the map() method.
results.map(function (result) {
//
}, this);
In ES5 format you cannot set this.state directly
var ImageList = React.createClass({
getInitialState: function () {
return { hover: false };
},
render : function(){
return(<p>...</p>);
});
However with new ES6 syntax you can essentially manage this:
class ImageList extends React.Component{
constructor (props) {
super(props);
this.state = {hover : false};
}
render (){ ... }
}
Related
I am tring to show todo list with load more option. I am appling limit.Limit is apply to list.But when i add loadmore()function. then i get error this.state.limit is null Wher i am wrong.Any one can suggest me.
here is my code
todoList.jsx
var TodoList=React.createClass({
render:function(){
var {todos}=this.props;
var limit = 5;
function onLoadMore() {
this.setState({
limit: this.state.limit + 5
});
}
var renderTodos=()=>{
return todos.slice(0,this.state.limit).map((todo)=>{
return(
<Todo key={todo.todo_id}{...todo} onToggle={this.props.onToggle}/>
);
});
};
return(
<div>
{renderTodos()}
<a href="#" onClick={this.onLoadMore}>Load</a>
</div>
)
}
});
module.exports=TodoList;
Changes:
1. First define the limit in state variable by using getInitialState method, you didn't define the limit, that's why this.state.limit is null.
2. Define all the functions outside of the render method.
3. Arrow function with renderTodos is not required.
4. Use this keyword to call the renderTodos method like this:
{this.renderTodos()}
Write it like this:
var TodoList=React.createClass({
getInitialState: function(){
return {
limit: 5
}
},
onLoadMore() {
this.setState({
limit: this.state.limit + 5
});
},
renderTodos: function(){
return todos.slice(0,this.state.limit).map((todo)=>{
return(
<Todo key={todo.todo_id}{...todo} onToggle={this.props.onToggle}/>
);
});
};
render:function(){
var {todos} = this.props;
return(
<div>
{this.renderTodos()}
<a href="#" onClick={this.onLoadMore}>Load</a>
</div>
)
}
});
This is witout button click.
As you all know react components has a function componentDidMount() which gets called automatically when the template of that component is rendered into the DOM. And I have used the same function to add the event listener for scroll into our div iScroll.
The scrollTop property of the element will find the scroll position and add it with the clientHeight property.
Next, the if condition will check the addition of these two properties is greater or equal to the scroll-bar height or not. If the condition is true the loadMoreItems function will run.
class Layout extends React.Component {
constructor(props) {
super(props);
this.state = {
items: 10,
loadingState: false
};
}
componentDidMount() {
this.refs.iScroll.addEventListener("scroll", () => {
if (this.refs.iScroll.scrollTop + this.refs.iScroll.clientHeight >=this.refs.iScroll.scrollHeight){
this.loadMoreItems();
}
});
}
displayItems() {
var items = [];
for (var i = 0; i < this.state.items; i++) {
items.push(<li key={i}>Item {i}</li>);
}
return items;
}
loadMoreItems() {
this.setState({ loadingState: true });
setTimeout(() => {
this.setState({ items: this.state.items + 10, loadingState: false });
}, 3000);
}
render() {
return (
<div ref="iScroll" style={{ height: "200px", overflow: "auto" }}>
<ul>
{this.displayItems()}
</ul>
{this.state.loadingState ? <p className="loading"> loading More Items..</p> : ""}
</div>
);
}
}
This is example
I am getting
Uncaught TypeError: Cannot read property 'openModal' of undefined
at onClick
with the following react component:
class ReactReduxTabs extends React.Component {
constructor(props){
super(props);
this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this);
this.render_response_json_modal = this.render_response_json_modal.bind(this);
this.state = {tabIndex: 1, isModelOpen: false, modalText: "blah blah blah"};
}
openModal() {
console.log("open modal");
this.setState({ isModalOpen: true })
}
closeModal() {
this.setState({ isModalOpen: false })
}
render_response_json_modal(headers, target_header) {
return add_rendering(
headers,
target_header,
function(val, row) {
return (<p onClick={() => {this.openModal()} }>yaaaaaaa</p>)
}
)
}
render() {
if (orderMetricsFetched == true) {
order_metrics.error_report_failed_orders.headers = this.render_response_json_modal(order_metrics.error_report_failed_orders.headers, 'RESPONSE', this.openModal)
return (
<div className="card">
<ReduxDataTable data={order_metrics.error_report_failed_orders}/>
</div>
What add_rendering does is take something like
headers = ['Header 1', 'Header 2']
and if you target Header 1 change to
headers= [
{title: 'Header 1', render: function() { ...returns what should go in the table cell...} },
'Header 2'
]
The issue seems to be with the this context as the table cell is clicked. When the table cell is clicked, it should call the component's openModal method.
The good new is it's very close, the table renders as it should, with each RESPONSE column cell having the random 'yaaaaa' inside, proving the add_rendering of render_response_json_modal worked. There are no errors until I click on each RESPONSE cell (one of the 'yaaaa'), where I see this print in console:
here:
return (<p onClick={() => {this.openModal()} }>yaaaaaaa</p>)
this refers to the function scope not the outer scope (that is what you want), a quick fix is to save a reference of this outside the function and use that.
var self = this;
return add_rendering(
headers,
target_header,
function(val, row) {
return (<p onClick={() => {self.openModal()} }>yaaaaaaa</p>)
})
);
By the way, the exception says that this is undefined inside the function probably because you're using "use strict" mode.
I have a simple component that I want to test using React and ReactUtils.
var TextConfirmButton = React.createClass({
getInitialState: function() {
return {
inputText: '',
confirmText: this.props.confirmText,
buttonEnabled: false,
inputEnabled: true
}
},
handleChange: function(event) {
this.setState({ inputText: event.target.value });
},
handleConfirm: function() {
this.props.onConfirmClick();
// When user clicks the confirm button, disable both the input and button.
this.setState({ buttonEnabled: false, inputEnabled: false });
},
render: function() {
return (
<div>
<input onChange={this.handleChange} disabled={!this.state.inputEnabled} type='text' ref='text' placeholder={this.state.confirmText} />
<button onClick={this.handleConfirm} disabled={this.state.inputText !== this.state.confirmText} className='btn btn-danger'>Delete</button>
</div>
)
}
})
Is there a way to test for a button's disabled state?
I've attempted:
var TestUtils = React.addons.TestUtils;
describe('TextConfirmButton', function () {
it('starts with confirm button disabled', function () {
var onConfirmClick = function() {
console.log("Confirm click");
}
var textConfirmButton = TestUtils.renderIntoDocument(
<TextConfirmButton confirmText="example" onConfirmClick={this.onConfirmClick} />
);
var textConfirmButtonNode = ReactDOM.findDOMNode(textConfirmButton);
expect(textConfirmButtonNode.disabled).toEqual('disabled');
});
});
But the test fails, with the error: textConfirmButtonNode.disabled undefined. So .disabled is obviously the wrong way to go about this.
Any suggestions?
You need to use the TestUtils#findRenderedDOMComponentWithTag in order to be able to query the DOM generated by TestUtils.
var textConfirmButtonNode =
TestUtils.findRenderedDOMComponentWithTag(textConfirmButton, 'button');
expect(textConfirmButtonNode.disabled).toEqual(true);
textConfirmButtonNode references the outermost div in your render() function. Unless it has an attribute of disabled, it isn't surprising that it is returning undefined.
My guess is that you were looking for a DOM node that references the actual button.
var textConfirmButtonNode = ReactDOM.findDOMNode(textConfirmButton);
var renderedButtonNode = textConfirmButtonNode.childNodes[1];
expect(renderedButtonNode.disabled).toEqual('disabled');
How do I call the function for getClass for the className inside this example? The way I have it written out does not seem to call getClass.
var CreateList = React.createClass({
getClass: function() {
//some code to return className
},
render: function() {
return(
<div className{this.getClass}>Example</div>
);
}
});
You're referencing the instance of the getClass() function as opposed to calling the function. Try tweaking it like so:
render: function() {
return(
<div className={this.getClass()}>Example</div>
);
}
className{this.getClass} won't compile. Try this:
var CreateList = React.createClass({
getClass: function() {
//some code to return className
},
render: function() {
return(
<div className={this.getClass()}>Example</div>
);
}
});
If you want the div to have a class name that starts with 'className', then prepend that string to the result of the call: className={'className' + this.getClass()}.
functional component
const statusColor = () => {
return 'red';
};
<span className={statusColor()}>your text</span>
I've just started learning React and have a question.
I want to do the following:
If a user clicks on a paragraph I want to change the element to an input field that has the contents of the paragraph prefilled.
(The end goal is direct editing if the user has certain privileges)
I'm come this far but am totally at a loss.
var AppHeader = React.createClass({
editSlogan : function(){
return (
<input type="text" value={this.props.slogan} onChange={this.saveEdit}/>
)
},
saveEdit : function(){
// ajax to server
},
render: function(){
return (
<header>
<div className="container-fluid">
<div className="row">
<div className="col-md-12">
<h1>{this.props.name}</h1>
<p onClick={this.editSlogan}>{this.props.slogan}</p>
</div>
</div>
</div>
</header>
);
}
});
How can I override the render from the editSlogan function?
If I understand your questions correctly, you want to render a different element in case of an "onClick" event.
This is a great use case for react states.
Take the following example
React.createClass({
getInitialState : function() {
return { showMe : false };
},
onClick : function() {
this.setState({ showMe : true} );
},
render : function() {
if(this.state.showMe) {
return (<div> one div </div>);
} else {
return (<a onClick={this.onClick}> press me </a>);
}
}
})
This will change the components state, and makes React render the div instead of the a-tag. When a components state is altered(using the setState method), React calculates if it needs to rerender itself, and in that case, which parts of the component it needs to rerender.
More about states
https://facebook.github.io/react/docs/interactivity-and-dynamic-uis.html
You can solve it a little bit more clear way:
class EditableLabel extends React.Component {
constructor(props) {
super(props);
this.state = {
text: props.value,
editing: false
};
this.initEditor();
this.edit = this.edit.bind(this);
this.save = this.save.bind(this);
}
initEditor() {
this.editor = <input type="text" defaultValue={this.state.text} onKeyPress={(event) => {
const key = event.which || event.keyCode;
if (key === 13) { //enter key
this.save(event.target.value)
}
}} autoFocus={true}/>;
}
edit() {
this.setState({
text: this.state.text,
editing: true
})
};
save(value) {
this.setState({
text: value,
editing: false
})
};
componentDidUpdate() {
this.initEditor();
}
render() {
return this.state.editing ?
this.editor
: <p onClick={this.edit}>{this.state.text}</p>
}
}
//and use it like <EditableLabel value={"any external value"}/>;