Owl Carousel with React - javascript

I want to use Owl Carousel with React, and I am new to React.
Please see this jsfiddle, I spent much time to do it.
The JSX code
var Carousel = React.createClass({
componentDidMount: function(){
$(React.findDOMNode(this)).owlCarousel({
items: 4
});
},
render: function(){
return(
<div id="inx-carousel-thumb" className="owl-carousel">
{
this.props.images.map(function(image, index){
return (
<div className="item" key={index}><img src={image} /></div>
)
}.bind(this))
}
</div>
);
}
});
var imagesList = [['http://www.myfacewhen.net/uploads/3908-troll-smile.jpg', 'http://www.captionite.com/templates/thumb-success.jpg', 'http://pauljadam.com/forma11y/img/rage-guy-teeth-smile.jpg'],['http://i2.kym-cdn.com/entries/icons/original/000/004/073/smile.png']];
var Container = React.createClass({
getInitialState: function(){
return {
images: imagesList[0]
};
},
changeImages: function(index) {
this.setState({images: imagesList[index]});
},
render: function(){
return(
<div>
<Carousel images={this.state.images} />
<input type="button" onClick={this.changeImages.bind(this, 0)} value="Images List 0" />
<input type="button" onClick={this.changeImages.bind(this, 1)} value="Images List 1" />
</div>
);
}
});
$(document).ready(function(){
React.render(
<Container />,
document.getElementById('container')
);
});
I included Jquery, Reactjs, Owl Carousel, too.
The problem is that when I tap button "Images List 1" to change the source array of Owl Carousel, the item count of carousel should become 1. However, it is still 3, and it only change first item. I think React only replace first item and ignore whole div, but I don't know how to fix it. Please give me some hints.

You have two options here:
You should deinitialize (destroy) OwnCarousel on componentWillUpdate and init it againt on componentDidUpdate after React rerendered the component with new images
You should return false in shouldComponentUpdate and manually update DOM in componentWillReceiveProps using nextProps.images value and jQuery

sorry my bad english!
You should verify length of element the carousel will use.
Example: in this case, my element is .banner-img - refer elements of <img />
componentDidUpdate: function () {
if ($('.banner-img').length > 0) {
$("#owl-home-slider").owlCarousel();
}
}

Related

Semantic React Modal weird height behavior

Here is the problem I am having when using the semantic UI React modal: I do as shown on their website, but weirdly my Modal moves around like in this GIF of what is happening.
I have no idea how to fix this. Here is my code:
class Success extends React.Component {
constructor () {
super();
this.closeModal = this.closeModal.bind(this)
this.state = {
Modalopen: true,
Orders: "",
urlparameter: qs.parse(location.search.replace(/^.*?\=/, ''))
}
}
closeModal () {
this.setState({Modalopen: false})
this.props.history.pushState(null, "/")
}
render () {
return (
<Modal open={this.state.Modalopen}>
<Modal.Header>Success!</Modal.Header>
<Modal.Content image>
<Image wrapped size='medium' src='http://semantic-ui.com/images/avatar2/large/rachel.png' />
<Modal.Description>
<Header>Thank you</Header>
<p>bla bla bla</p>
<Button color='green' onClick={this.closeModal} inverted>
<Icon name='checkmark' /> Got it
</Button>
</Modal.Description>
</Modal.Content>
</Modal>
);
}
}
What might be causing this issue? Thank you.
I had the same problem today when trying to create a custom 'fullscreen' modal.
This is the line causing us trouble...
https://github.com/Semantic-Org/Semantic-UI-React/blob/master/src/modules/Modal/Modal.js#L255
If the modal height is greater than or equal to window.innerHeight, it adds the class scrolling which comes with a bunch of styles.
setPositionAndClassNames then appears to be called recursively on line 271, which is probably causing the weird looping behaviour.
Dirty fix
I'm adding margin-bottom: 1px to my modal to make sure it's a tiny bit less than window.innerHeight.
Long term solution
I'll open a PR into semantic-ui-react and see what they say...
UPDATE
I have a PR open at https://github.com/Semantic-Org/Semantic-UI-React/pull/3024 with a suggested fix.
UPDATE
That's merged and now part of Semantic UI React.
In my case, it create Modal normally.
Here is the test code(ES5/webpack) :
[index.html]
<!DOCTYPE html>
<html lang="ko-KR">
<head>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.2/semantic.min.css"></link>
</head>
<body>
<div id="wrap"></div>
<script src="dist/app.js"></script>
</body>
</html>
[app.jsx]
var React = require('react');
var ReactDOM = require('react-dom');
var Semantic = require('semantic-ui-react');
var Button = Semantic.Button;
var Header = Semantic.Modal.Header;
var Image = Semantic.Image;
var Modal = Semantic.Modal;
var Icon = Semantic.Icon;
var IndexPage = React.createClass({
getInitialState : function() {
return {
Modalopen: true,
Orders: "",
//urlparameter: qs.parse(location.search.replace(/^.*?\=/, ''))
}
},
closeModal: function() {
this.setState({Modalopen: false})
//this.props.history.pushState(null, "/")
},
render : function () {
return (
<Modal open={this.state.Modalopen}>
<Modal.Header>Success!</Modal.Header>
<Modal.Content image>
<Image wrapped size='medium' src='http://semantic-ui.com/images/avatar2/large/rachel.png' />
<Modal.Description>
<Header>Thank you</Header>
<p>bla bla bla</p>
<Button color='green' inverted>
<Icon name='checkmark' /> Got it
</Button>
</Modal.Description>
</Modal.Content>
</Modal>
);
}
});
ReactDOM.render(<IndexPage/>, document.getElementById('wrap'));
Image of Result by the upper code
If you get the error continually,
Please add the html/js files more detail with Codepen to test like your situation.

Is my owner react components state preventing me from updating child component state?

I'm trying to update the state of a checkbox within a modal that is mounted via button on the UI. I'm loading the settings when AppWrapper mounts so I can pass them around as needed. Right now i'm just passing the settings as props to SettingsList component, which then renders a series of child nodes as checkboxes. I'm able to click the checkboxes when the modal is open, and the settings successfully save to the database. However when the modal is closed and reopened the settings are refreshed to the initially set state from the owner. Refreshing the page though shows the accurately checked boxes. That makes sense to me, but i'm unsure they best way to resolve it.
Should I/Can I update the state of the parent from the child setting so when the modal is reopened that passed props reflect the user changes?
My react structure looks like this:
<AppWrapper>
getInitialState {settings:[]}
<Modal>
<SettingList settings={this.state.settings}>
<Setting/>
<SettingList/>
<Modal/>
<AppWrapper/>
It's not direct one to one code, bust just a representation of the hierarchy.
My Modal component looks like this:
var Modal = React.createClass({
render: function() {
if(this.props.isOpen){
return (
<ReactCSSTransitionGroup transitionName={this.props.transitionName} transitionEnterTimeout={500} transitionLeaveTimeout={500}>
<div className="mymodal">
{this.props.children}
</div>
</ReactCSSTransitionGroup>
);
} else {
return <ReactCSSTransitionGroup transitionName={this.props.transitionName} transitionName={this.props.transitionName} transitionEnterTimeout={500} transitionLeaveTimeout={500} />;
}
}
});
My SettingList component looks like this:
var SettingsList = React.createClass({
render: function() {
var settingNodes = this.props.settings.map(function(setting, i){
return (
<Setting data={setting}
key={i}>
</Setting>
)
}.bind(this));
return (
<div className="settings-block">
<h2>Notifications</h2>
<ul className="account-settings">
{settingNodes}
</ul>
</div>
)
}
});
And the Setting component looks like this:
var Setting = React.createClass({
saveSetting: function(one) {
core.setAccountSettings(this.refs.setting_checkbox.id, this.refs.setting_checkbox.checked).done(function(response){
this.setState({
defaultChecked: this.refs.setting_checkbox.checked
};
console.log(response)
}.bind(this));
},
render: function() {
//get values from settings object
for (var k in this.props.data) {
this.settingId = k
this.settingName = String(k.split(/_(.+)?/)[1]).replace(/_/g, " ");
this.settingValue = (this.props.data[k].toLowerCase() == "true")
}
return (
<li className="checkbox">
<input onChange={this.saveSetting} ref="setting_checkbox" id={this.settingId} className="settings_checkbox" type="checkbox" defaultChecked={this.settingValue}></input>
<label htmlFor={this.settingName}>{this.settingName}</label>
</li>
)
}
});
As pointed out in the comments above there is a number of ways to pass data between components.
http://andrewhfarmer.com/component-communication/
Following the article regarding callbacks was the solution for me.

Child to parent communication in React (JSX) without flux

I'm really new to React, and I'm pulling my hair out trying to solve what seems to me to be a simple problem. Here's a picture of the component I've built.
Color Picking Component
What I'm trying to accomplish seems trivial, but literally every article I've read explaining what to do has told me something different, and not one of the solutions has worked. It breaks down to this: When a user clicks on a tag, it builds out a tray and loops through an array of colors to build color buttons. When a color button is clicked it needs to pass which color was clicked to its parent component and run a function to update its color. I've read about flux, event bubbling, binding "this" to a property, and none of those solutions has seemed to work. The React docs are basically useless for a newbie like myself. I want to avoid complicated event structures like flux at this point since I'm appending some simple components to an existing app that I didn't write in React originally.
Also, PS, This code is in JSX which makes much more sense to me than straight JS react. Thanks in advance for your help!
var colorsArray = ["#ED5851", "#9CCC64", "#337AEC", "#ff7a45", "#7E58C2", "#FFEB3B", "#78909C", "#FFFFFF", "#213a4b"];
var EditDrawer = React.createClass({
updateColor: function() {
console.log("New Color: " + i);
},
render: function(){
var passTarget = this;
return (
<div className="container-fluid animated fadeIn extra-fast-animation tag-edit-drawer">
<div className="row">
<div className="col-xs-12">
{colorsArray.map(function(object, i){
return <ColorButton buttonColor={object} key={i} />;
})}
</div>
</div>
</div>
);
}
})
var ColorButton = React.createClass({
render: function(){
var buttonStyle = {
backgroundColor: this.props.buttonColor,
};
return (
<div className="tag-edit-color-button" style={buttonStyle} >
</div>
)
}
})
The callback function should work. As you've mentioned in your previous comment you can use your captured this to access the updateColor function from the child:
var passTarget = this;
...
...
return <ColorButton
buttonColor={object}
key={i}
update={passTarget.updateColor} />
Or as Bogdan mentioned you can pass it through map after your callback function:
{colorsArray.map(function(object, i){
return <ColorButton
buttonColor={object}
key={i}
update={this.updateColor} />;
}, this)}
Your <ColorButton /> component should then be able to run a simple onClick function:
onClick={this.props.update}
And then you can simply make use of normal event targets in the parent component to capture the color of the button that was clicked:
updateColor: function(e) {
console.log(e.target.style.backgroundColor);
}
Here is a full DEMO to demonstrate.
You can just pass callback function into child from your parent component, as simple as this:
<ColorButton buttonColor={object} key={i} onColorSelect={this.updateColor}/>
(when using React.createClass all class methods are already bound to this, so you are not required to call .bind(this)).
Then from ColorButton component you can call this callback as this.props.onColorSelect(...).
JS Bin example: http://jsbin.com/fivesorume/edit?js,output
OK, this is pretty simple in React without using flux or redux, similar to passing down props from parent to child, here we can use callback function like this:
var colorsArray = ["#ED5851", "#9CCC64", "#337AEC", "#ff7a45", "#7E58C2", "#FFEB3B", "#78909C", "#FFFFFF", "#213a4b"];
var EditDrawer = React.createClass({
updateColor: function(i) {
alert("New Color: " + i);
},
render: function(){
return (
<div className="container-fluid animated fadeIn extra-fast-animation tag-edit-drawer">
<div className="row">
<div className="col-xs-12">
{colorsArray.map(function(object, i){
return <ColorButton buttonColor={object} key={i} updateColor={this.updateColor}/>;
}, this)}
</div>
</div>
</div>
);
}
});
var ColorButton = React.createClass({
updateColor: function() {
this.props.updateColor(this.props.buttonColor);
},
render: function(){
var buttonStyle = {
backgroundColor: this.props.buttonColor,
};
return (
<div className="tag-edit-color-button"
style={buttonStyle}
onClick={this.updateColor}>
this.props.buttonColor
</div>
)
}
});

React components won't render; only seeing data-reactid=".0"

I'm creating my first React app, so apologies in advance. A newbie must learn as he goes.
But I'm a few hours into debugging, having gotten nowhere, and I'm hoping someone can clarify why this attempt to pass data into a React component, use prototype.map, and render a final component just isn't cutting it.
var imagedata = [{"id":"1"},{"id":"2"},{"id":"3"}];
var portraitPhoto = React.createClass({
render: function() {
return (
<div className="test">
<img src={"./build/assets/images/photos/square_raw/" + this.props.imagepath + ".jpg"}
className="full-width-portrait" />
</div>
);
}
});
var portrait = React.createClass({
getDefaultProps: function(){
return {
data: imagedata
}
},
render: function() {
var portraitEach = this.props.data.map(function (imaged,i) {
return (
<div className="portrait2">
<portraitPhoto imagepath={imaged.id}/>
</div>
);
});
return (
<div className="portrait-container">
{portraitEach}
</div>
);
}
});
React.render(
<portrait/>,
document.getElementById('portraits')
);
You need your React components to have uppercase names. React's help page says:
React's JSX uses the upper vs. lower case convention to distinguish
between local component classes and HTML tags
Simply having this should be enough:
var PortraitPhoto = React.createClass({
...
...
});
A demo on jsfiddle is here.

Dynamically Show Children of React Component?

I'm trying to make a simple dropdown that loads in a specific ul when a corresponding button is clicked. It seems like there are many correct and incorrect ways of achieving this. Currently I have two different ul's: AddMenu, and RefsMenu. When I click on a link in AddMenu, it will completely remove that ul and replace it with RefsMenu. I only want one child component to load at a time, effectively replacing the body each time a new view is selected.
So far I have:
<Dropdown open={ false } currentView={ this.state.currentView } onClick={ this.handleView }>
<AddMenu title="Add Menu" selected={ false }/>
<AddRefs title="Add Refs" selected={ false } />
</Dropdown>
So what I'm confused about is... How do I select which body element to show/render?
I suppose I could have a handler that says:
handleView: function(component, e) {
this.state.currentView = e.target.value;
}
handleSelected: function() {
selected += true;
}
I've thought about using this.props.children, but I don't think that returns instances so I'm not really sure where to start. Am I way off?
If the DropDown component has knowledge of the current view to show, (which it appears to because your code reference currentView={this.state.currentView}), then in your render method you can use that information to conditionally render the children.
As an example,
render: function() {
return (<div>
{this._getCurrentViewItem()}
</div>);
},
_getCurrentViewItem: function() {
var foundChild;
React.Children.forEach(function(child) {
if (child.props.view === this.props.currentView) {
foundChild = child;
}
});
return foundChild;
}
To make this work you would just need to specify which view each child component is applicable to.
<Dropdown open={ false } currentView={ this.state.currentView } onClick={this.handleView }>
<AddMenu title="Add Menu" view="refsView"/>
<AddRefs title="Add Refs" view="menuView" />
</Dropdown>

Categories