I would like to use universe:i18n for translating my meteor application (using react).
In this component you can see, that I iterate through an array using map() and as the output I would like to get the categories as translations:
imports/ui/components/example.jsx
import React, { Component } from 'react'
import i18n from 'meteor/universe:i18n'
class Example extends Component {
getCategories(index) {
const categories = [ 'one', 'two', 'three' ]; // <-- Get correct translations of these elements
return categories[index - 1];
}
render() {
return (
<div id="content">
{ this.props.sections.map((i) => {
return (
<div>
{ this.getCategories(i.index) }
</div>
);
}) }
</div>
);
}
}
i18n/de.i18.json
{
categories: {
one: 'Eins',
two: 'Zwei',
three: 'Drei'
}
}
I tried to do it with
const T = i18n.createComponent()
class Example extends Component {
getCategories(index) {
const categories = [ 'one', 'two', 'three' ]; // <-- Get correct translations of these elements
return categories[index - 1];
}
render() {
return (
<div id="content">
{ this.props.sections.map((i) => {
return (
<div>
<T>categories[{ this.getCategories(i.index) }]</T>
</div>
);
}) }
</div>
);
}
}
It won't work, because you have to use dot instead of bracker notation, so
<T>categories.{ this.getCategories(i.index) }</T>
Instead of
<T>categories[{ this.getCategories(i.index) }]</T>
But it still won't work, because it will create an children array, but only string is accepted, so use it like this:
<T children={`categories.${ this.getCategories(i.index) }`} />
Source.
Related
Im importing an SVG file as a ReactComponent.
I then want to output this component dynamically based on data from a request.
i.e.
import { ReactComponent as S1 } from '../../assets/images/characteristics/S1.svg';
{characteristics.map(characteristic => (
<div className="characteristic" key={characteristic.key}>
<characteristic.key />
</div>
}
where characteristic.key holds the name of the SVG i.e. "S1" in my example
How can i output the component as this does not work?
Thanks
You can try to do it like this instead:
import { ReactComponent as S1 } from "./path1.svg";
import { ReactComponent as S2 } from "./path2.svg";
// ...
function App() {
// defining characteristics for demonstration purposes
const characteristics = [
{ component: S1, key: "S1" },
{ component: S2, key: "S2" }
];
return (
<div className="App">
{characteristics.map(characteristic => (
<div className="characteristic" key={characteristic.key}>
<characteristic.component />
</div>
))}
</div>
);
}
So the string "S1" would be a good value for a key and you use S1 from the import to actually render the svg component.
The function is getting the value of a button click as props. Data is mapped through to compare that button value to a key in the Data JSON called 'classes'. I am getting all the data correctly. All my console.logs are returning correct values. But for some reason, I cannot render anything.
I've tried to add two return statements. It is not even rendering the p tag with the word 'TEST'. Am I missing something? I have included a Code Sandbox: https://codesandbox.io/s/react-example-8xxih
When I click on the Math button, for example, I want to show the two teachers who teach Math as two bubbles below the buttons.
All the data is loading. Just having an issue with rendering it.
function ShowBubbles(props){
console.log('VALUE', props.target.value)
return (
<div id='bubbles-container'>
<p>TEST</p>
{Data.map((item,index) =>{
if(props.target.value == (Data[index].classes)){
return (
<Bubble key={index} nodeName={Data[index].name}>{Data[index].name}
</Bubble>
)
}
})}
</div>
)
}
Sandbox Link: https://codesandbox.io/embed/react-example-m1880
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
const circleStyle = {
width: 100,
height: 100,
borderRadius: 50,
fontSize: 30,
color: "blue"
};
const Data = [
{
classes: ["Math"],
name: "Mr.Rockow",
id: "135"
},
{
classes: ["English"],
name: "Mrs.Nicastro",
id: "358"
},
{
classes: ["Chemistry"],
name: "Mr.Bloomberg",
id: "405"
},
{
classes: ["Math"],
name: "Mr.Jennings",
id: "293"
}
];
const Bubble = item => {
let {name} = item.children.singleItem;
return (
<div style={circleStyle} onClick={()=>{console.log(name)}}>
<p>{item.children.singleItem.name}</p>
</div>
);
};
function ShowBubbles(props) {
var final = [];
Data.map((item, index) => {
if (props.target.value == Data[index].classes) {
final.push(Data[index])
}
})
return final;
}
function DisplayBubbles(singleItem) {
return <Bubble>{singleItem}</Bubble>
}
class Sidebar extends Component {
constructor(props) {
super(props);
this.state = {
json: [],
classesArray: [],
displayBubble: true
};
this.showNode = this.showNode.bind(this);
}
componentDidMount() {
const newArray = [];
Data.map((item, index) => {
let classPlaceholder = Data[index].classes.toString();
if (newArray.indexOf(classPlaceholder) == -1) {
newArray.push(classPlaceholder);
}
// console.log('newArray', newArray)
});
this.setState({
json: Data,
classesArray: newArray
});
}
showNode(props) {
this.setState({
displayBubble: true
});
if (this.state.displayBubble === true) {
var output = ShowBubbles(props);
this.setState({output})
}
}
render() {
return (
<div>
{/* {this.state.displayBubble ? <ShowBubbles/> : ''} */}
<div id="sidebar-container">
<h1 className="sidebar-title">Classes At School</h1>
<h3>Classes To Search</h3>
{this.state.classesArray.map((item, index) => {
return (
<button
onClick={this.showNode}
className="btn-sidebar"
key={index}
value={this.state.classesArray[index]}
>
{this.state.classesArray[index]}
</button>
);
})}
</div>
{this.state.output && this.state.output.map(item=><DisplayBubbles singleItem={item}/>)}
</div>
);
}
}
ReactDOM.render(<Sidebar />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.0.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
The issue here is ShowBubbles is not being rendered into the DOM, instead (according the sandbox), ShowBubbles (a React component) is being directly called in onClick button handlers. While you can technically do this, calling a component from a function will result in JSX, essentially, and you would need to manually insert this into the DOM.
Taking this approach is not very React-y, and there is usually a simpler way to approach this. One such approach would be to call the ShowBubbles directly from another React component, e.g. after your buttons using something like:
<ShowBubbles property1={prop1Value} <etc...> />
There are some other issues with the code (at least from the sandbox) that you will need to work out, but this will at least help get you moving in the right direction.
How can i push html into the last array. I was trying to add an item and supposed be add instantly into list array. The cod is working except I'm struggling to add new list into last array.
function addItem(id,name){
const array = JSON.parse(localStorage.getItem('categories'));
array.push({
name: name,
id:id,
});
//<li>{name}</li> push this into last array
localStorage.setItem('categories',JSON.stringify(array));
}
{categories.map(function(item, key){
return <div>
<ul>
<li>item.name</li>
</ul>
<button onClick={() => addItem(item.id,'value name')}>Add</button>
</div>
})}
Something looks wrong in your example. I have added a complete exampl. You can maintain localStorage and State both. I hope this example helps you.
You mistake is that while adding new item you are pushing it to localStoage due to which react dom does not get rerendered. You have to update the value of state for that.
class App extends React.Component {
constructor() {
super();
this.state = {
categories: [
{
name: "Hello",
id: 1
},
{
name: "World",
id: 2
}
]
};
this.addItem = this.addItem.bind(this);
this.SaveToLocalStorage = this.SaveToLocalStorage.bind(this);
}
SaveToLocalStorage() {
const categories = this.state.categories;
localStorage.setItem("categories", JSON.stringify(categories));
}
addItem(id, name) {
const categories = this.state.categories;
categories.push({
name: name,
id: id
});
this.setState({ categories });
//localStorage.setItem("categories", JSON.stringify(categories));
}
render() {
let categories = this.state.categories;
const test = categories.map(item => (
<div key={item.id}>
<li>{item.name}</li>
</div>
));
return (
<div>
{test}
<button onClick={() => this.addItem(Date.now(), "Item")}>
Click to Add More
</button>
<button onClick={() => this.SaveToLocalStorage()}>
Save To LocalStorage{" "}
</button>
</div>
);
}
}
ReactDOM.render( < App / > , document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I guess this is what you are asking for. You just need to set it to state and re-render it when ever you are trying to add an element to list/array. I don't know why you are setting it to local storage but you can do it from state directly if your intention is to just store the previous array for future additions.
import React, { Component } from "react";
class App extends Component {
state = {};
constructor(props){
super(props);
this.state={
arr = []
}
}
addItem(id, name) {
const array = JSON.parse(localStorage.getItem("categories"));
array.push({
name: name,
id: id
});
//<li>{name}</li> push this into last array
localStorage.setItem("categories", JSON.stringify(array));
this.setState({arr:array});
}
renderList = () => {
return this.state.array.map(function(item, key) {
return (
<div>
<ul>
<li>item.name</li>
</ul>
<button onClick={() => addItem(item.id, "value name")}>Add</button>
</div>
);
});
};
render() {
return <div>{this.renderList()}</div>;
}
}
export default App;
I have a very basic ReactJS app which uses Redux which contains the following components:
PanelMaterialSize > Select
/src/controls/PanelMaterialSize/PanelMaterialSize.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import './PanelMaterialSize.scss';
import Select from '../Select/Select';
import { setThemeList } from '../../store/AppConfig/actions';
class PanelMaterialSize extends Component {
componentDidMount() {
this.n = 1;
setInterval(() => {
let themeList = [
{ value: this.n, text: 'Option ' + this.n },
{ value: this.n + 1, text: 'Option ' + (this.n + 1) },
{ value: this.n + 2, text: 'Option ' + (this.n + 2) },
];
this.props.setThemeList(themeList);
this.n += 3;
}, 1000);
}
render() {
return (
<div className="partial-designer-panel-material-size">
<div>
<div className="label-input">
<div className="label">MATERIAL</div>
<div className="input">
<Select data={this.props.themeList} style={{ width: '100%' }} />
</div>
</div>
</div>
</div>
);
}
}
const mapStateToProps = (appState) => {
return {
themeList: appState.appConfig.themeList,
}
}
const mapDispatchToProps = (dispatch) => {
return {
setThemeList: (themeList) => dispatch(setThemeList(themeList)),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(PanelMaterialSize);
In my opinion the Redux logic is fine because I have tested by doing couple of things.
My problem is that when the render(...) method of: PanelMaterialSize gets called, the component: Select doesn't get rendered with the new data (which changes every one second).
Here you have a Codesandbox.io you can play with (preferable use Chrome):
https://codesandbox.io/s/03mj405zzv
Any idea on how to get its content changed properly?
If possible, please, provide back a new Codesandbox.io with your solution, forked from the previous one.
Thanks!
the problem is here in your select component.
you are passing initially empty array and checking your component with this.state.data props, next time reducer change your this.state.data will not update the data. because you initialize in constructor. constructor only invoke once when component mount.
SOLVED DEMO LINK
The Problem is in your select render method:
render() {
let data = this.state[this.name];
return (
<div className="control-select" {...this.controlProps}>
<div className="custom-dropdown custom-dropdown--grey">
<select className="custom-dropdown__select custom-dropdown__select--grey">
//change data with this.props.data
{this.props.data.length > 0 &&
this.props.data.map((elem, index) => {
return (
<option value={elem.value} key={index}>
{elem.text}
</option>
);
})}
</select>
</div>
</div>
);
}
I thought this would be a simple task, but I've been working on this all day but still can't seem to figure it out.
I am receiving a very large (multiple layers of objects) JSON file which I stored in a state of my component, now I need to render that data on the screen. This has become difficult, because within the object I have several others objects which also may contain other objects.
So far, I am using Object.keys(myJSONObject).map(...) to try to get it done, however I can't seem to find a way to reach all the 'sub-objects'. Here is my current code:
render: function(){
return (
<div>
{
Object.keys(_this.state.content).map(function (key) {
if (typeof _this.state.content[key] instanceof Object){
//go through all objects and sub-objects???
}
return <div > Key: {
key
}, Value: {
_this.state.content[key]
} </div>;
})
}
</div>
);
}
Edit: I should probably add that my object is _this.state.content
Edit 2: Here is an example of the object I am looking to iterate through. Keep in mind that is it a lot bigger than this.
{ "3.8": [ "Something something" ],
"3.2": [ { "Blabla": [ "More things I am saying", "Blablablabal", "Whatever" ] } ],
"2.9": [ { "Foo": [ "bar", "something something something something", "blablablabalbalbal" ] } ]}
Edit 3: Here is how I would somewhat like it to look when rendered:
3.8:
- Something something
3.2:
- Blabla:
- More things I am saying
- Blablablabal
- Whatever
2.9:
-Foo:
-bar
...
Is this what your are after: http://codepen.io/PiotrBerebecki/pen/PGjVxW
The solution relies on using React's reusable components. It accepts objects of varying levels of nesting as per your example. You can adjust it further to accommodate even more types of objects.
const stateObject = {
"3.8": [ "Something something" ],
"3.2": [ { "Blabla": [ "More things I am saying", "Blablablabal", "Whatever" ] } ],
"2.9": [ { "Foo": [ "bar", "something something something something", "blablablabalbalbal" ] } ]
}
class App extends React.Component {
render() {
const renderMainKeys = Object.keys(stateObject)
.map(mainKey => <MainKey mainKey={mainKey}
innerObject={stateObject[mainKey]} />);
return (
<div>
{renderMainKeys}
</div>
);
}
}
class MainKey extends React.Component {
render() {
if (typeof this.props.innerObject[0] === 'string') {
return (
<div>
<h4>{this.props.mainKey}</h4>
<ul>
<li>{this.props.innerObject[0]}</li>
</ul>
</div>
);
}
const innerObjectKey = Object.keys(this.props.innerObject[0])[0];
const innerList = this.props.innerObject[0][innerObjectKey];
return (
<div key={this.props.mainKey}>
<h4>{this.props.mainKey}</h4>
<InnerKey innerObjectKey={innerObjectKey} innerList={innerList}/>
</div>
)
}
}
class InnerKey extends React.Component {
render() {
return (
<ul>
<li>{this.props.innerObjectKey}</li>
<InnerList innerList={this.props.innerList} />
</ul>
)
}
}
class InnerList extends React.Component {
render() {
if (!Array.isArray(this.props.innerList)) {
return (
<ul>
<li>{this.props.innerList}</li>
</ul>
);
}
const listItems = this.props.innerList.map(function(item, index) {
return <li key={index}>{item}</li>;
});
return (
<ul>
{listItems}
</ul>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('app')
);
Here is a code which I wrote sometime back to handle 3 layers of nesting in my json file.
JSON
var a = {
"parent":{
"name":"x",
"child":{
"name":"y",
"subchild":{
"name":"check"
}
}
}
}
Iterator
Object.keys(obj).map(function(key,index){
let section = obj[key]
//getting subsections for a single section
let subSections = section["subsections"] // get you nested object here
Object.keys(subSections).map(function(subSectionId,key){
//getting a single sub section
let subSection=subSections[subSectionId]
//getting instruments for a sub section
let nestedSection = subSection["//key"] //get you next nested object here
Object.keys(instruments).map(function(instrumentId,key){
//operation
}
})
})
})
})
Hope it helps.