This is nav component. This nav component rendered at run time. Text should be visible when mouse will enter to div with ref "text_nav" and text should hide when mouse will leave div with ref "text_nav".
onMouseLeave is not working
var React = require('React');
var $ = require('jquery');
var Nav = React.createClass({
getInitialState: function() {
return {
items: []
}
},
componentWillMount: function() {
var _this = this;
this.serverRequest =
$.post("/nav", {}, function(result) {
_this.setState({
items: result.data
});
})
},
onMouseEnter: function() {
this.refs.text_navigator.style = {display: true}
},
onMouseLeave: function() {
this.refs.text_navigator.style = {display: 'none'}
},
render: function() {
var text = this.state.items.map(function(data, index) {
var icon = "text_" + data.sname;
return (
<div id={icon} key={index} className="text_nav_item">
<p>
<span><a href={data.url}>{data.title} </a></span>
</p>
</div>
);
});
return (
<div id="nav" className="fixed" style={{zIndex: 1018}} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
<div id="text_nav" ref="text_navigator" style={{display: 'none'}} >
<div id="text_nav_content">
{item_text}
</div>
</div>
</div>
)
}
})
First off, the ref is text_nav in your render method, not text_navigator as you're using in onMouseEnter and onMouseLeave. But the main issue is that you can't set the display style the way you're trying to do, as
this.refs.text_navigator.style = {display: true}
The most common approach to take is to set a boolean in state, perhaps called displayTextNavigator. In getInitialState, set it to false, and then your onMouseEnter and onMouseLeave functions can be:
onMouseEnter: function() {
this.setState({ displayTextNavigator: true})
},
onMouseLeave: function() {
this.setState({ displayTextNavigator: false})
},
Now in your render method, you can change your wrapping div to look like this:
<div id="text_nav" ref="text_nav" style={{display: this.state.displayTextNavigator ? 'block': 'none'}} >
You can pull that ternary operator out to earlier in the render method if you'd like it be more readable.
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
When switching data by selecting slice from an array, putting it into state and rendering by setInterval, I try to create a slider effect by clicking up and down arrows:
UPDATE START
I was finally able to create slider using technique from this codepen:
http://codepen.io/sergiodxa/pen/aOYdeN
UPDATE END
var MainContainer = React.createClass({
getInitialState: function () {
return {
position: 0,
max_elements: 3,
data: [],
source: Array.prototype.slice.call([1, 2, 3, 4, 5, 6, 7]).reverse()
}
},
componentDidMount: function () {
setInterval(this.updateState, 10);
},
arrowUp: function () {
if (this.state.position > 0) {
this.state.position--;
this.updateState();
}
},
arrowDown: function () {
if (this.state.source.length - this.state.position > this.state.max_elements) {
this.state.position++;
this.updateState();
}
},
updateState: function () {
data = this.state.source.slice(this.state.position, this.state.position + this.state.max_elements)
this.setState({data: data});
console.log(this.state.data);
},
render: function () {
var Items = this.state.data.map(function (item, i) {
return (
<div key={i}>
<SimpleItem message={item} active={i == 0 ? true : false}/>
</div>
);
}, this);
return (
<div>
{Items}
<ArrowUp onClick={this.arrowUp}/>
<ArrowDown onClick={this.arrowDown}/>
</div>
);
}
});
var ArrowUp = React.createClass({
render: function () {
return (
<a href="#" className="glyphicon glyphicon-arrow-up" onClick={this.props.onClick}>
</a>
);
}
});
var ArrowDown = React.createClass({
render: function () {
return (
<a href="#" className="glyphicon glyphicon-arrow-down" onClick={this.props.onClick}>
</a>
);
}
});
var SimpleItem = React.createClass({
render: function () {
var className = "well well-lg"
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
className = this.props.active ? className + " active" : className;
return (
<ReactCSSTransitionGroup
transitionName="example"
transitionAppear={true} transitionAppearTimeout={500}
transitionEnter={false} transitionLeave={false}
>
<div className={className}>
{this.props.message}
</div>
</ReactCSSTransitionGroup>
);
}
});
ReactDOM.render(<MainContainer />, document.getElementById('container'));
The animation is only seen when components render for the first time, re-rendered elements won't animate, for some reason.
My styles are:
.example-appear {
opacity: 0.01;
}
.example-appear.example-appear-active {
opacity: 1;
transition: opacity 500ms ease-in;
}
I'm not a frontend guy so any hint or link would be much appreciated.
I noticed a couple of things wrong. This first is in you arrowUp and down functions. State always needs to be set using the setState() function. From the docs:
NEVER mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.
The second thing is that the children of ReactTransition group must have a unique key. When this key changes that is what tells react transition group to animate.
<ReactCSSTransitionGroup
transitionName="example"
transitionAppear={true} transitionAppearTimeout={500}
transitionEnter={false} transitionLeave={false}
>
{*/ This div needs a key. When the key changes react transition group animates. /*}
<div key={this.state.currentItem} className={className}>
{this.props.message}
</div>
</ReactCSSTransitionGroup>
In the above example I've set the key to this.state.currentItem your up and down arrow functions would update state.currentItem appropriately, react would re-render the component, react transition group would animate because this.state.currentItem changed.
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');
I have a created a menu component in reactjs. As you can see, the parent component has a method called "handleClick which toggles the "open state" of the menu, opening and closing it accordingly.
Now, I am trying to pass a click event from the child component "MenuItem" (which is a link in the menu) to the parent "Menu" component so that when one of the menu items is clicked the menu closes.
I have tried to do this in a number of ways. At the moment, I have bound the click event of each "MenuItem" in "MenuList" (the list of MenuItems) to a prop called "whenClicked" and then bound "whenClicked" to the "handleClick" method of "Menu".
The problem is that this seems to have no effect on "Menu". Neither the React tool in Chrome, nor the regular dev console are giving me any errors but the menu does not close when I click one of the MenuItems. The React tool in Chrome allows me to view the virtual DOM and I can see that all of the onClick functions are defined.
Below is the code. As you can see, I am using the same methodology to pass a click event from a different component ("MenuToggle") to "Menu". Oddly enough this works fine and clicking on the toggle button changes the state of "Menu" successfully and opens and closes the menu. I am using the "react-scroll" module for "MenuItem" so maybe that is the issue. Any light anyone can shed on this would be helpful and I would love to know what I am doing incorrectly!
var Menu = React.createClass({
getInitialState: function() {
return {open: false, mobi: false}
},
handleClick: function() {
this.setState({open: !this.state.open})
},
closeOnMobiScroll: function() {
/*
if(this.state.mobi === false) {
this.setState({open: false})
}
*/
},
updateDimensions: function() {
$(window).width() >= 767 ? this.setState({mobi: true}) : this.setState({mobi: false});
},
componentWillMount: function() {
this.updateDimensions();
},
componentDidMount: function() {
$(window).on("resize", this.updateDimensions);
},
componentWillUnmount: function() {
$(window).on("resize", this.updateDimensions);
},
render: function() {
return (
<div id="menu" className={(this.state.open ? 'open' : '')} >
<div id="menu-inner-wrap">
<MenuTitle />
<MenuToggle whenClicked={this.handleClick}/>
<MenuList whenClicked={this.handleClick}/>
</div>
</div>
)
}
});
module.exports = Menu;
var MenuItem = React.createClass({
render: function() {
return (
<li className="menu-link">
<Link to={this.props.menuLink} spy={true} smooth={true} duration={500}>
<i className={this.props.icon}></i>
<span className="menu-link-text">{this.props.menuTitle}</span>
</Link>
</li>
);
}
});
var MenuList = React.createClass({
getInitialState: function() {
return {data: []}
},
componentWillMount: function() {
$.ajax({
url: 'http://10.0.0.97:8888/public-code/React.cv/data/data.json',
dataType: 'json',
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, error) {
var err = JSON.parse(xhr.responseText);
console.log(err.Message);
}
});
},
render: function() {
var list = this.state.data.map(function(menuItemProps) {
return <MenuItem onClick={this.props.whenClicked} {...menuItemProps} key={menuItemProps.id} />
}.bind(this));
return (
<ul id="menu-list">
{list}
</ul>
)
}
});
It seems like you still need to bind the onClick to something that the DOM will handle. Adding an onClick attribute to MenuItem allows you to have a prop inside MenuItem, but you still need to bind it:
var MenuItem = React.createClass({
render: function() {
return (
<li className="menu-link" onClick={this.props.onClick}>
<Link to={this.props.menuLink} spy={true} smooth={true} duration={500}>
<i className={this.props.icon}></i>
<span className="menu-link-text">{this.props.menuTitle}</span>
</Link>
</li>
);
}
});
}
In the above example, onClick is added to the li:
<li className="menu-link" onClick={this.props.onClick}>
The best example in the documentation of behaviour like this is in Expose Component Functions.
In that example you can see that the Todo child component finally binds to div and then bubbles up in a similar way:
var Todo = React.createClass({
render: function() {
return <div onClick={this.props.onClick}>{this.props.title}</div>;
},
//this component will be accessed by the parent through the `ref` attribute
animate: function() {
console.log('Pretend %s is animating', this.props.title);
}
});
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"}/>;