How can i render a component but with multiples content - javascript

I have a card component generator, that grabs info from a const array and renders an div with the data in a sort of a table inside a card UI component.
I need to implement an ADD button inside of each card so i can open an modal with some inputs.
But, as the modal is inside the function, every modal on differen cards are rendering the same
how can i make an implementation so each modal grab something unique to the card being rendered ?
here's the code
function ProntCard() { const [modal, setModal] = useState(false);
const columns = [
{
title: "Estado de Saúde",
dataIndex: "1",
key: "name",
width: 150,
},
{
title: "Diagnostico",
dataIndex: "2",
key: "age",
width: 150,
},
{
title: "Medicação",
dataIndex: "3",
key: "address 1",
ellipsis: true,
},
{
title: "Data de atendimento",
dataIndex: "4",
key: "address 2",
ellipsis: true,
},
{
title: "Nota",
dataIndex: "",
key: "address 3",
ellipsis: true,
},
];
const nomes = [
{
nome: "Condições de Saúde / Comorbidades",
colunas: [
{
title: "Estado de Saúde",
dataIndex: "name",
key: "name",
width: 150,
},
{
title: "Sintomas",
dataIndex: "age",
key: "age",
width: 150,
},
{
title: "Diagnóstico",
dataIndex: "date",
key: "address 1",
ellipsis: true,
},
{
title: "Data de atendimento",
dataIndex: "address",
key: "address 2",
ellipsis: true,
},
{
title: "Nota",
dataIndex: "tags",
key: "address 3",
ellipsis: true,
},
],
laudos: [
{
key: "1",
name: "Atípico",
age: "Leve dor de cabeça",
date: "Dipirona de 1g",
address: "02/01/2021",
tags: "Noite de Sono mal dormida",
},
{
key: "2",
name: "Convencional",
age: "Leve dor membros",
date: "Insulina de 1g",
address: "02/01/2021",
tags: "Mal estar",
},
],
},
function showModal() {
setModal(!modal);
}
function CardsHost(props) {
const cards = nomes.map((nome) => (
<div>
<div className="box2">
<div className="box2header">
<div>
<h3>{nome.nome}</h3>
</div>
<div className="addSpan">
<PlusCircleOutlined />
<span onClick={showModal}> Adicionar</span>
</div>
</div>
<div className="box2info">
<Table columns={nome.colunas} dataSource={nome.laudos} />
</div>
</div>
</div>
));
return <div className="controler">{cards}</div>;
}
return (
<>
<div className="">
<CardsHost posts={nomes} />
</div>
<Modal
visible={modal}
onOk={showModal}
title="Novo Prontuário"
onCancel={showModal}
width={1000}
>
{columns.map((column) => (
<div key={column.key} className="labelll">
<label>{column.title}</label>
<Input style={{ width: "61.3%" }} />
</div>
))}
</Modal>
</>
);
}
export default ProntCard;

If what you really want is pass specific data to the modal based on the Card you select, change this part.
<span onClick={showModal}> Adicionar</span>
As follow.
<span onClick={() => {showModal(nome)}}> Adicionar</span>
Customize showModal function to set necessary data as a state.

If I understood the question correctly, you can render different jsx for each different card:
const cards = nomes.map((name, index) => (
<UniqueCard key={index} name={name} />
));
UniquCard.jsx:
export const UniqueCard = ({key, name}) => {
const renderCard = () => {
switch(name){
case 'name1':
return <p style={{color: 'red'}}> Card name: {name} </p>
case 'name2':
return <p style={{color: 'yellow'}}> Card name: {name} </p>
case 'name3':
return <p style={{color: 'green'}}> Card name: {name} </p>
default:
return <p> No card </p>
}
}
return (
<> {renderCard()} </>
)
}

Use the index of the map-loop:
function showModal(index) {
// use the index here to find element in array
}
const cards = nomes.map((nome, index) => (
<span onClick={() => showModal(index)}> Adicionar</span>
))
You can assign this index to any property you want to use it later to uniquely identify each modal.

Related

How to render nested map from JSON in React.JS?

I'm trying to render menu values from a JSON. Considering that this is a multilevel menu, I'm trying to do a nested map to render the full menu.
const menu = {
data:[
{
title: "Home",
child: [
{
title: "SubLevel1",
child: {
title: "SubSubLevel1"
}
},
{
title: "SubLevel2",
child: [
{title: "SubSubLevel1"},
{title: "SubSubLevel2"}
]
}
]
},
{
title: "About",
},
{
title: "Contact",
}
]}
And here is the part when I use the map function :
const MenuNavigation = () => {
return (
{menu.data.map((item) => (
<div>
<ul>{item.title}</ul>
{item.map((sub, id) =>
<li>{sub.child[id].title}</li>
)}
</div>
))}
)
};
I managed to render main level for the menu (Home, About, Contact), but how can I print sublevel & subsublevel values?
Another question: Is there a way to map recursively a tree structure?
Try below:
The menu should be like this. Your menu had one issue in child of "SubLevel1" not defined inside an array.
const menu = {
data: [
{
title: "Home",
child: [
{
title: "SubLevel1",
child: [{
title: "SubSubLevel1",
}],
},
{
title: "SubLevel2",
child: [{ title: "SubSubLevel1" }, { title: "SubSubLevel2" }],
},
],
},
{
title: "About",
},
{
title: "Contact",
},
],
};
Render it recursively like below. I have added a margin-left to see the levels properly.
const renderMenu = (menu) => {
return menu.map((item) => (
<div style={{ marginLeft: '25px' }}>
{item.title}
{item.child && renderMenu(item.child)}
</div>
))
}
return <div>{renderMenu(menu.data)}</div>;

Data object with array of different groups, trying to display ordered by group type using .map() and pushing to new array nothing is rendering

I have a React Component I'm building out that accepts a data object as props.
This data object holds an array of groups each with it's own group type.
What I'm trying to do is map over each group in the array and display it's contents as it's own section, but I also want to ensure that all of the objects with the type grid display together, followed by any sections with a list type no matter what position they are in the array.
So even if the array holds the values like:
[{Grid}, {List}, {Grid}, {List}, {Grid}]
It will display like this:
Group #1 (Grid)
Contents
Group #2 (Grid)
Contents
Group #3 (Grid)
Contents
Group #4 (List)
Contents
Group #5 (List)
Contents
The problem I'm having is that I wrote two separate components to handle the styling of each type and then passed them into a function that creates a new array from the original to then render, and nothing is displaying. I'm not getting any error messages or anything in the console so I'm completely stumped as to where I'm going wrong.
Here are my components, the data structure and a Codesandbox:
// Component File
import "./styles.css";
import data from "./resourceMock";
import FileIcon from "./FileIcon";
const GridView = (group) => {
const { groupName, items } = group;
return (
<>
<h2>{groupName}</h2>
<ul
style={{
display: "inline-flex",
flexWrap: "wrap",
listStyleType: "none"
}}
>
{items.map((item) => {
return (
<li style={{ height: "40vh", flexGrow: 1 }}>
<img src={item.img} style={{ height: "150px", width: "150px" }} />
<h4>{item.name}</h4>
<h5>{item.subtitle}</h5>
</li>
);
})}
</ul>
</>
);
};
const ListView = (group) => {
const { groupName, items } = group;
return (
<>
<h2>{groupName}</h2>
<ul style={{ listStyleType: "none" }}>
{items.map((item) => {
return (
<li>
<FileIcon />
{item.title}
</li>
);
})}
</ul>
</>
);
};
function renderList(group) {
const lists = [];
if (!group) return null;
data.map((group) => {
switch (group.groupType) {
case "grid":
return lists.push((group) => {
<GridView group={group} />;
});
case "list":
return lists.push((group) => {
<ListView group={group} />;
});
default:
return lists.push((group) => {
<ListView group={group} />;
});
}
});
return lists;
}
export default function App() {
return <div className="App">{data.map((group) => renderList(group))}</div>;
}
Data Structure:
export default [
{
groupName: "Marvel Characters",
groupType: "grid",
items: [
{
name: "Iron Man",
subtitle: "Inventor Tony Stark",
img:
"https://www.denofgeek.com/wp-content/uploads/2019/02/mcu-1-iron-man.jpg?resize=768%2C432"
},
{
name: "Incredible Hulk",
subtitle: "Bruce Banner",
img:
"https://lh3.googleusercontent.com/proxy/-jHnFcGLqlxjdOl9Mf99UPBk4XJKcQ1Hsv7lPYEs8Vai874sW0l5TUwn3acriwGpE36aUDPpZHPFzccRUt7b7POGOWCFIbgYomTO9bDCXF0eovxFGdr_D3P-0wfLnkUMOOJDG09MgAzqSCbiDq-A"
}
]
},
{
groupName: "Magic Cards",
groupType: "list",
items: [
{
title: "Kamahl, Fist Of Krosa",
link:
"https://gatherer.wizards.com/pages/card/Details.aspx?multiverseid=220490"
},
{
title: "Seedborn Muse",
link:
"https://gatherer.wizards.com/pages/card/Details.aspx?multiverseid=446180"
}
]
},
{
groupName: "DC Characters",
groupType: "grid",
items: [
{
name: "Batman",
subtitle: "Bruce Wayne",
img:
"https://static.wikia.nocookie.net/marvel_dc/images/a/a6/Batman_Vol_2_2_Variant_Textless.jpg/revision/latest/top-crop/width/360/height/450?cb=20120228075313"
},
{
name: "Martian Manhunter",
subtitle: "J'onn J'onzz",
img:
"https://cdn.flickeringmyth.com/wp-content/uploads/2021/03/Martian-Manhunter-600x338.png"
}
]
},
{
groupName: "Kaiju and Mechs",
groupType: "grid",
items: [
{
name: "Godzilla",
img:
"https://www.denofgeek.com/wp-content/uploads/2019/05/godzillakingofmonsters-2.jpg?resize=768%2C432"
},
{
name: "Hunter Vertigo",
img: "https://i.ytimg.com/vi/7F-iZYAqSbw/maxresdefault.jpg"
}
]
},
{
groupName: "Comic Books",
groupType: "list",
items: [
{
title: "Descender",
link: "https://imagecomics.com/comics/series/descender"
},
{
title: "East of West",
link: "https://imagecomics.com/comics/series/east-of-west"
},
{
title: "Letter 44",
link: "https://onipress.com/collections/letter-44"
}
]
}
];
I have fixed the issues.
Sandbox: https://codesandbox.io/s/affectionate-sinoussi-5suro
You are already looping over data inside renderList, so we can directly have <div className="App">{renderList(data)}</div>;
To sort, we can use Array.sort()
data.sort((a, b) => a.groupType === b.groupType ? 0 : a.groupType > b.groupType ? 1 : -1);
Also, in switch case you need to push the component and not a function.
case "grid":
lists.push(<GridView group={group} />);
break;
Need to use destructuring here const ListView = ({ group }) => {}
Finally add key to your lists. I have added using the item name, but you need to change per your requirement.

Attempting to show array element of react select in list item

I am using react-select to store multiple elements and am using the map function to display elements which is working fine. But when I am using the same element in another class to display in a list element it shows a blank.
Here is the code where I am displaying the multiple options.
const Departments = [
{ label: "OneIT", value: "OneIT" },
{ label: "HR", value: "HR" },
{ label: "Vigilance", value: "Vigilance" },
{ label: "Ethics", value: "Ethics" },
{ label: "Corporate Services", value: "Corporate Services" },
{ label: "Legal", value: "Legal" },
{ label: "Sports", value: "Sports" },
{ label: "TQM", value: "TQM" },
{ label: "Iron Making", value: "Iron Making" },
{ label: "TMH", value: "TMH" }
];
class MultiSelect2 extends Component {
state = {
selectedOptions: []
};
handleChangeField = selectedOptions => {
this.setState({ selectedOptions });
};
render() {
const { selectedOption } = this.state;
return (
<div className="container">
<div className="row">
<div className="col-md-2"></div>
<div className="col-md-8">
<span>Select Department</span>
<Select
value={selectedOption}
options={Departments}
onChange={this.handleChangeField}
isMulti
/>
{this.state.selectedOptions.map(o => (
<p>{o.value}</p>
))}
</div>
<div className="col-md-4"></div>
</div>
</div>
);
}
}
I am trying to display this in another class in the list item but it is not showing.
export class Confirm extends Component {
state = {
selectedOptions: []
};
render() {
const {
values: {selectedOptions
}
} = this.props;
return (
<List>
<ListItemText primary="Departments" secondary={selectedOptions} />
</List>

Filling a model with a list from Textarea

Now I do not really understand you. Sorry, I just started this whole study not so long ago. I’ll try to explain again what I can’t do.
I have an empty object and an object with data with the same structure.
data: [
{id: 1, title: "title1"},
{id: 2, title: "title1"},
{id: 3, title: "title3"},
{id: 4, title: "title4"},
{id: 5, title: "title3"}
],
item: [
{
itemId: "",
itemname: ""
}
]
And I have select and textarear. Select have data, textarear empty. Textarear displays title.
I want to press a button. Selected item from select. copied to textarear (title only), and also itemId - this selected element id: 5 and itemname - the same title: "title3" element, was recorded in item [].
https://codesandbox.io/s/priceless-hermann-g9flw
Please do check now
import React from "react";
class App extends React.Component {
constructor() {
super();
this.state = {
id: null,
title: "",
filmItem: "",
listFilms: [],
data: [
{ id: 1, title: "title1" },
{ id: 2, title: "title2" },
{ id: 3, title: "title3" },
{ id: 4, title: "title4" }
],
item: []
};
this.onChange = this.onChange.bind(this);
this.onChangeArea = this.onChangeArea.bind(this);
this.addFilm = this.addFilm.bind(this);
this.choice = this.choice.bind(this);
}
addFilm(film) {
const selectedData = this.state.data.find(item => item.id == film);
console.log(selectedData);
this.setState({
listFilms: [...this.state.listFilms, selectedData.title],
item: [
...this.state.item,
{ itemId: selectedData.id, itemname: selectedData.title }
]
});
}
onChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
onChangeArea = e => {
this.setState({ [e.target.name]: e.target.value.split("\n") });
};
choice(title) {
this.setState({ filmItem: title });
}
render() {
return (
<div className="App">
<div className="row App-main">
<div>
<select name="filmItem" size="4" onChange={e => this.onChange(e)}>
{this.state.data.map(film => (
<option key={film.title} value={film.id}>
{film.title}
</option>
))}
</select>
</div>
<div>
<button
className="editButton"
onClick={() => this.addFilm(this.state.filmItem)}
>
button
</button>
</div>
<div>
<textarea
name="films"
onChange={this.onChangeArea}
value={this.state.listFilms.map(r => r).join("\n")}
/>
</div>
<div>
<input type="text" name="text-input" onChange={this.onChange} />
</div>
</div>
<pre style={{ whiteSpace: "pre-wrap" }}>
{JSON.stringify(this.state)}
</pre>
</div>
);
}
}
export default App;

Assigning onClick button to the proper feature. Map function ReactJS

I created this mockup and I am trying to put this into real life
component mockup
I started from something simple so I created 3 buttons and an array
but what happens is that when I click on any button I see all of the features, and my goal was to when I click on SMS I see sms.features etc. But for now I see this that way current result
import React, { Component } from "react";
export default class Test extends Component {
constructor(props) {
super(props);
this.state = {
isHidden: true,
features: [
{
name: "sms.features",
key: "1",
icon: "sms icon"
},
{
name: "pricing.features",
key: "2",
icon: "pricing icon"
},
{
name: "api.features",
key: "3",
icon: "api icon"
}
],
buttons: [
{
name: "sms",
key: 1
},
{
name: "pricing",
key: 2
},
{
name: "api",
key: 3
}
]
};
this.toggleHidden = this.toggleHidden.bind(this);
}
toggleHidden() {
this.setState({
isHidden: !this.state.isHidden
});
}
render() {
return (
<div style={{ marginLeft: "20%" }}>
<div className="features__details__grid">
{!this.state.isHidden &&
this.state.features.map((object, key) => (
<div key={key}>{object.name}</div>
))}
</div>
<div className="buttons">
{this.state.buttons.map((button, key) => (
<div key={key}>
<button onClick={this.toggleHidden}>{button.name}</button>
</div>
))}
</div>
</div>
);
}
}
So, since you want to show only one, the isHidden should really be a pointer to which feature should be visible (by targeting the key property)
import React, { Component } from "react";
export default class Test extends Component {
constructor(props) {
super(props);
this.state = {
visibleFeature: "0",
features: [
{
name: "sms.features",
key: "1",
icon: "sms icon"
},
{
name: "pricing.features",
key: "2",
icon: "pricing icon"
},
{
name: "api.features",
key: "3",
icon: "api icon"
}
],
buttons: [
{
name: "sms",
key: "1"
},
{
name: "pricing",
key: "2"
},
{
name: "api",
key: "3"
}
]
};
this.toggleHidden = this.toggleHidden.bind(this);
}
toggleHidden(key) {
this.setState(state=>{
if (state.visibleFeature === key) return {visibleFeature: 0}
return {visibleFeature: key}
});
}
render() {
const feature = this.state.visibleFeature;
return (
<div style={{ marginLeft: "20%" }}>
<div className="features__details__grid">
{this.state.features.map((object) => (
feature === object.key && <div key={object.key}>{object.name}</div>
))}
</div>
<div className="buttons">
{this.state.buttons.map((button) => (
<div key={button.key}>
<button onClick={()=>this.toggleHidden(button.key)}>{button.name}</button>
</div>
))}
</div>
</div>
);
}
}
Demo at https://codesandbox.io/s/8y5q120wxj

Categories

Resources