I have the following react component for a dropdown:
var UIDropdown = React.createClass({
getDefaultProps: function () {
return {
isOpen: false
};
},
render: function () {
if (this.props.isOpen) {
return (
<div className="dropdown">
<ul className="uk-nav uk-nav-dropdown tm-svg-center">
{this.props.mapOpacityValues.map(function (list, i) {
return (
<li onClick={this.props.opacityThermatic.bind(this, list) } key={"list" + i}>{`${list * 100}%`}</li>
);
}, this) }
</ul>
</div>
);
}
return null;
}
});
I'm looping through some data which outputs some list items, but I have a number for different data items.
How can I add the following in the component without repeating the dropdown component code:
{this.props.mapOpacityValues.map(function (list, i) {
return (
<li onClick={this.props.opacityThermatic.bind(this, list) } key={"list" + i}>{`${list * 100}%`}</li>
);
}, this) }
Example but with a single dropdown component
https://jsfiddle.net/zidski/ddLdg84s/
If I understand you correctly, you need to reuse your Dropdown component
Then do something like this
DropdownItems component
var DropdownItems = React.createClass({
render: function () {
return(
<ul className="uk-nav uk-nav-dropdown tm-svg-center">
{this.props.mapOpacityValues.map(function (list, i) {
return (
<li onClick={this.props.opacityThermatic.bind(this, list) } key={"list" + i}>{`${list * 100}%`}</li>
);
}, this)
}
</ul>
)
}
});
UIDropdown component
var UIDropdown = React.createClass({
getDefaultProps: function () {
return {
isOpen: false
};
},
render: function () {
if (this.props.isOpen) {
return (
<div className="dropdown">
{this.props.children}
</div>
);
}
return null;
}
});
Then you can create any number UIDropdowns like
<UIDropdown>
<DropdownItems mapOpacityValues={someData} opacityThermatic={someFunction}>
</UIDropdown>
Here you need to repeat neither dropdown nor li items. You just resue them in your implementation.
Related
I am trying to make filter navigation and want to go back to previous state or trigger function to get the data from another API.
On click of this state, I should be able to clear the filter to return the response from another API.
To understand it completely, please look at the sample App I have created below
Stackblitz : https://stackblitz.com/edit/react-3bpotn
Below is the component
class Playground extends Component {
constructor(props) {
super(props);
this.state = {
selectedLanguage: 'All', // default state
repos: null
};
this.updateLanguage = this.updateLanguage.bind(this);
this.updateLanguagenew = this.updateLanguagenew.bind(this);
}
componentDidMount() {
this.updateLanguage(this.state.selectedLanguage);
}
updateLanguage(lang) {
this.setState({
selectedLanguage: lang,
repos: null
});
fetchPopularRepos(lang).then(
function (repos) {
this.setState(function () {
return { repos: repos };
});
}.bind(this)
);
}
updateLanguagenew(lang) {
if (lang === 'All') {
this.updateLanguage(lang);
return;
}
this.setState({
selectedLanguage: lang,
repos: null
});
fetchPopularReposUpdated(lang).then(
function (repos) {
this.setState(function () {
return { repos: repos };
});
}.bind(this)
);
}
render() {
return (
<div>
<div>
This is the current state : <strong style={{padding: '10px',color:'red'}}>{this.state.selectedLanguage}</strong>
</div>
<div style={{padding: '10px'}}>
On click of above state I should be able to trigger this function <strong>(updateLanguage)</strong> again to clear the filter and load data from this API
</div>
<p>Click the below options</p>
<SelectLanguage
selectedLanguage={this.state.selectedLanguage}
onSelect={this.updateLanguagenew}
/>
{//don't call it until repos are loaded
!this.state.repos ? (
<div>Loading</div>
) : (
<RepoGrid repos={this.state.repos} />
)}
</div>
);
}
}
SelectLanguage component mapping for filter options:
class SelectLanguage extends Component {
constructor(props) {
super(props);
this.state = {
searchInput: '',
};
}
filterItems = () => {
let result = [];
const { searchInput } = this.state;
const languages = [ {
"options": [
{
"catgeory_name": "Sigma",
"category_id": "755"
},
{
"catgeory_name": "Footner",
"category_id": "611"
}
]
}
];
const filterbrandsnew = languages;
let value
if (filterbrandsnew) {
value = filterbrandsnew[0].options.map(({catgeory_name})=>catgeory_name);
console.log (value);
}
const brand = value;
if (searchInput) {
result = this.elementContainsSearchString(searchInput, brand);
} else {
result = brand || [];
}
return result;
}
render() {
const filteredList = this.filterItems();
return (
<div className="filter-options">
<ul className="languages">
{filteredList.map(lang => (
<li
className={lang === this.props.selectedLanguage ? 'selected' : ''}
onClick={this.props.onSelect.bind(null, lang)}
key={lang}
>
{lang}
</li>
))}
</ul>
</div>
);
}
}
Note: This is having the current state {this.state.selectedLanguage}, on click of this I should be able to trigger this function. updateLanguage
The way you are doing set state is not correct
Change
fetchPopularRepos(lang).then(
function (repos) {
this.setState(function () {
return { repos: repos };
});
}.bind(this)
);
To
fetchPopularRepos(lang).then(
function (repos) {
this.setState({
repos: repos
});
}.bind(this)
);
Also Change
fetchPopularReposUpdated(lang).then(
function (repos) {
this.setState(function () {
return { repos: repos };
});
}.bind(this)
);
To
fetchPopularReposUpdated(lang).then(
function (repos) {
this.setState({
repos: repos
});
}.bind(this)
);
I'm too new to react. I'm curious about a few things. The first topic I was wondering, why the HTML tags in js?
I need to do a project. I have a method that returns json with .NET
I have a code like below. How do I update the div when I add something into it?
This .net code.
private static readonly IList<Mock.Model.Skills> _Skills;
[Route("api/Skills/add")]
[HttpPost]
public ActionResult Skills(Mock.Model.Skills Model)
{
if (ModelState.IsValid)
{
_Skills.Add(Model);
return Json("true");
}
return Json(false);
}
And, js (react) code.
var Rows = React.createClass({
render: function () {
return (
<span className="label label-info tags">{this.props.item.tag}</span>
);
}
});
var SkillsRow = React.createClass({
getInitialState: function () {
return {
items: []
}
},
componentDidMount: function () {
$.get(this.props.dataUrl, function (data) {
if (this.isMounted()) {
this.setState({
items: data
});
}
}.bind(this));
},
render: function () {
var rows = [];
this.state.items.forEach(function (item, index) {
rows.push(<Rows class="label label-info tags" key={index} item={item} />);
});
return (<span>{rows}</span>);
}
});
ReactDOM.render(
<SkillsRow dataUrl="/api/Skills" />,
document.getElementById('skills-data')
);
This works well, but do not add.
I wonder if this is the correct method?
Thank you to everyone who showed interest.
If you want to add items to api, you can call something like this:
var SkillsRow = React.createClass({
getInitialState: function() {
return {
items: [],
currentEditor: ''
}
},
componentDidMount: function() {
this.updateSkillList()
},
updateSkillList: function() {
$.get(this.props.dataUrl, function(data) {
this.setState({
items: data
})
}).bind(this)
},
handleEditorChange: function(event) {
this.setState({
currentEditor: event.target.value
})
},
handlePostForm: function() {
$.post('api/Skills/add', {skill: this.state.currentEditor}, function(data) {
this.updateSkillList()
})
},
renderSkillList: function() {
this.state.items.map(function(item, idx) {
return <Row className="label label-info tags" key={idx} item={item} />
})
},
render: function() {
return (
<div>
<span>
<input value={this.state.currentEditor} onChange={this.handleEditorChange} />
<button onClick={this.handlePostForm} />
</span>
<span>{this.renderSkillList()}</span>
</div>
)
}
})
Edited:
Now i understood the question, you code will look something like this, also you will have to fix backend code to only receive the skill name, and then create the object (you can't create a C# object in javascript)
Depending on which link is clicked, I would like to update the img src in the MapImage Component
import React from 'react'
import NavLink from './NavLink'
var MapImage = React.createClass({
render: function() {
return <img src={'./img/' + this.props.img + '.png'} />
}
});
export default React.createClass({
getInitialState: function () {
return { img: '1' }
},
loadImage: function () {
this.setState({
img: this.props.img
});
},
render() {
return (
<div>
<h2>Maps</h2>
<ul>
<li><NavLink onClick={this.loadImage} to="/maps/firstfloor" img='1'>1st Floor</NavLink></li>
<li><NavLink onClick={this.loadImage} to="/maps/secondfloor" img='2'>2nd Floor</NavLink></li>
<li><NavLink onClick={this.loadImage} to="/maps/thirdfloor" img='3' >3rd Floor</NavLink></li>
</ul>
{this.props.children}
<MapImage img={this.state.img} />
</div>
)
}
})
The image src is updated to ./img/undefined.png
You don't have that image value in the props when you're doing:
this.setState({
img: this.props.img
});
Try to pass a parameter to the loadImage function, and use it in the setState:
// in JSX
onClick={ function () { this.loadImage(1); } }
// function
loadImage: function (img) {
this.setState({
img: img
});
}
For each NavLink image.
In general, I'd recommend having an array and iterating over it, like:
var images = [{
value: 'firstfloor',
text: '1st Floor'
},
{ ... // other objects }]
And then iterate like this (or change values depending on your logic):
{
images.map((image, index) => {
return (
<li>
<NavLink
onClick={ function () { this.loadImage(index); } }
to={ '/maps/' + image.value }
img={ index }>
{ image.text }
</NavLink>
</li>
);
});
}
So, I believe this is a formatting issue OR I'm not clear about how the return works when dynamically building.
The render function in Results works, if I replace the code with anythign else it renders where I want. Similarly, the console.log's in the Results function outputs the data correctly. There's no error, it just doesn't render the html and it doesn't hit the debugger in SynonymElement.
What am I missing in here / what core concept am I misconstruing?
(This is just an input form that takes a word, user hits submit, it returns an object with the word as a key and the value an array of synonynms. that get rendered in the ul)
'use strict'
const Smithy = React.createClass({
dsiplayName: "Smithy",
getInitialState: function() {
return { data: []};
},
handleSubmit: function(data) {
$.get('/get-synonyms', { data: data.data }).done(function(data) {
this.setState({ data: data})
}.bind(this));
},
render: function() {
return (
<div className="smithy">
<h1>Craft Tweet</h1>
<SmithyForm onSubmit={this.handleSubmit} />
<Results data={this.state.data} />
</div>
)
}
})
const SmithyForm = React.createClass({
displayName: "SmithyForm",
getInitialState: function() {
return { placeholder: "tweet", value: "" };
},
handleChange: function(event) {
this.setState({value: event.target.value});
},
handleSubmit: function(event) {
event.preventDefault();
var tweet = this.state.value.trim();
this.props.onSubmit({ data: tweet });
this.setState({value: ''});
},
render: function() {
var placeholder = this.state.placeholder;
var value = this.state.value;
return (
<form className="smithyForm" onSubmit={this.handleSubmit}>
<input type="text" placeholder={placeholder} value={value} onChange={this.handleChange} />
<button>smithy</button>
</form>
);
}
})
const SynonymElement = React.createClass({
render: function() {
debugger
return (
<li>{this.props.data}</li>
)
}
})
const Results = React.createClass({
render: function() {
var words = this.props.data;
return (
<div className="results">
{
Object.keys(words).map(function(value) {
{ console.log(value) }
<div className={value}>
<ul>
{
words[value].map(function(syn) {
{ console.log(syn) }
return <SynonymElement data={syn} />
})
}
</ul>
</div>
})
}
</div>
)
}
})
ReactDOM.render(<Smithy />, document.getElementsByClassName('container')[0])
Might have some other complicating issues but assuming everything else is wired up correctly, you need to return the result of the function you pass into the first map (over the collection Object.keys(words)) just as you have for the later map otherwise the function is executed and nothing useful is returned.
Possibly just a dupe of loop inside React JSX
return (
<div className="results">
{
Object.keys(words).map(function(value) {
return ( // <-- this
<div className={value}>
I am trying to creating some reusable components to filter arrays, but I think I am doing something wrong.
Should I be passing the handleclick all the way back up the chain of components like this?
I also cannot get the loading icon to appear in the filter button, it seems the button only re-renders after the click and filtering has been completed.
Is there a better place to store the active button, but this is the only way I could get the buttons to re-render.
var FilterButton = React.createClass({
getInitialState: function() {
return { loading: false };
},
handleClick: function() {
this.setState({ loading: true }, function() {
this.props.handleClick(this.props.filter);
});
this.setState({ loading: false });
},
render: function() {
var cx = React.addons.classSet;
var classes = cx({
'btn': true,
'btn-white': !this.props.active,
'btn-primary': this.props.active
});
var loader = <i className="fa fa-circle-o-notch fa-spin"></i>;
return (
<button className={classes} onClick={this.handleClick}>
{this.state.loading ? loader : ''} {this.props.label}
</button>
);
}
});
var FilterBar = React.createClass({
getInitialState: function() {
return { filter: 1 };
},
handleClick: function(filter) {
this.setState({ filter: filter }, function() {
this.props.handleClick(this.state.filter);
});
},
render: function() {
var filter = this.state.filter;
return (
<div className="nav">
<FilterButton handleClick={this.handleClick} active={filter == 1} filter="1" label="Pending" />
<FilterButton handleClick={this.handleClick} active={filter == 2} filter="2" label="Canceled" />
<FilterButton handleClick={this.handleClick} active={filter == 3} filter="3" label="Shipped" />
</div>
);
}
});
var OrdersView = React.createClass({
getInitialState: function () {
return {orders: [], status_id: 1};
},
componentDidMount: function() {
/* get orders here via ajax and set state*/
},
handleFilter: function(status_id) {
this.setState({ status_id: status_id });
},
render: function() {
var self = this;
var orders = $.grep(this.state.orders, function(order, i){
return order.status_id == self.state.status_id;
});
return (
<div>
<FilterBar handleClick={this.handleFilter} />
<OrderList orders={orders} />
</div>
);
}
});