I m running into some trouble trying to render bootstrap elements with ReactJS script.
To give you my user case, I got to display cards depending on some list of data created from DB. However when I loop to create my 'card's to show in a "card-desk", I observe on my browser the "card-deck" is correctly generated by react while cards elements in the loop do not to seemed generated by react in the rendered page.
So far I tried with lists of data to avoid mixing problem with DB
function DisplayUnes(){
var i = 0
const nbrArticle = 3
const items = []
const idUnes =
[
1,
2,
3
]
const titleUnes =
[
]
const dateUnes =
[
]
const bodyUnes =
[
]
//string href to github storage
const imgUnes =
[
]
for(i = 0; i<nbrArticle; i++) {
items.push(
<div className="card" key={idUnes}>
<div className="card-body">
<h5 className="card-title">{titleUnes[i]}</h5>
<p className="card-text">{bodyUnes[i]}</p>
<a>{dateUnes[i]}</a>
Go somewhere
</div>
</div>
)
}
return (items)
}
... later in the code I use the tag:
<main>
<h1>A la une</h1>
<div className="card-columns">
<DisplayUnes />
</div>
</main>
I have tried other approach like calling the function, storing the generated html and displaying it in the "card-columns" block. It seems the problem comes from the loop.. When I inspect rendered code on a browser, jsx id are not generated for elements in
Would you have any idea on how to fix this problem?
I verified multiple times all necessary dependencies are installed (using nextjs, react-bootstrap) but if someone is able to provide me a recap of them, it might still be useful.
Thx in advance for your time,
Have a nice day,
Benjamin
use this
let i = 0 instead of this var i=0;
and
for (const [index, value] of idUnes.entries()) {
items.push(
<div className="card" key={index}>
<div className="card-body">
<h5 className="card-title">{titleUnes[index]}</h5>
<p className="card-text">{bodyUnes[index]}</p>
<a>{dateUnes[index]}</a>
Go somewhere
</div>
</div>
)
}
and
change const items = [] to let items = [].
Related
I have a json object messages that I want to display and iterate over using the map function. This is loaded at the very beginning. There are 23 elements in it, but it takes a short moment until all elements are displayed. I would like to write a loading function, i.e. as soon as all messages have been iterated over, a function should be called.
I have tried this here, but this function is not executed.
Now my question, how can I execute the function loading, as soon as over all elements was iterated over?
Note: I have update the message Json and this send also works in real time, but only the initial loading takes too long and therefore I would like to show the user something. A loading bar should be displayed and as soon as the complete list has been iterated over, the list should be removed or no longer displayed and the user should receive the complete loaded list.
function MessageSide(props) {
const [loaded, setLoaded] = useState(false); // added
const loading = () => {
console.log("LOADED")
setLoaded(true) // added
}
return (
<div class="col flex-fill background--chat">
<div className="content__body">
// added
{loaded? false :
<div>
<Ellipsis color="#5869FF" style={{left:"50", right:"50", top:"50", bottom:"50",}}/>
</div>
} // added
<div className="item" style={loaded? {} : {display: 'none'}}>
{messages.map((message) => {
// onLoad={() =>test()} that didn't work
return (
<div>
<Message
message={message.body}
id={message.id}
timestamp={message.timestamp}
chatid={message.chatid}
onLoad={() =>loading()} // this is what I tried
/>
</div>
);
})}
</div>
<div ref={messagesEndRef}/>
</div>
</div>
);
}
export default MessageSide;
The loading is rather not to be determined in return, let alone inside a loop.
You should include code of <Message> to your question.
const [initialLoad, setInitialLoad] = useState(false)
useEffect(()=>{
if(message.length > 0) { setInitialLoad(true) }
},[message])
useEffect(()=>{ if(message.length > 0) {
/*stop showing loading screen */
} },[initialLoad])`
This way, variable initialLoad will be false at first render, but will be changed into true after load. However it will not change afterwards, causing the last useEffect hook to be executed only once
I want the image src for to change based on the value of the "p" element. I have imported all of my images like this:
import food from '../../images/food.png'
I've tried to use if/else statements and wrapping them in a function, then mounting them with componentDidMount when the page loads up, but that doesn't work for me. Then I tried :
images = () => {
const image = document.querySelectorAll('img');
let src = image.attr('src');
if (src.valueOf() === 'Food') image.src = {food};
// Changed src.val() because that didn't work //
}
componentDidMount() {
this.images()
)}
And this does nothing for me either. Any suggestions?
MAIN BODY OF CODE:
(top of code not show)
return (
<GuideDiv>
<div className='top'>
<h1>Guides</h1>
<NewGuide to='/GuideForm'>
<h2> Add <img src={travel} alt='ravel'/> Guide </h2>
</NewGuide>
</div>
{guided.map(guide =>
<GuidePost key={guide.id}>
<div>
<UserIcon>
<img id='guide' alt='type' src={guide.guide_type}/>
</UserIcon>
<label className='under'>Guide Type</label>
<br/>
<p>{guide.guide_type}</p>
<br/>
(rest of code not shown)
Why don't you try an mapping. Something like this if its predefined set
import food from '../../images/food.png'
import car from '../../images/car.png'
let mapping = {
FOOD: food,
CAR: car
}
const images = () => {
const image = document.querySelectorAll('img');
let srcVal = image.attr('src')?.valueOf;
image.src = mapping[srcVal];
//....rest of your code
}
Check this one and let me know whether it helped you
THANK YOU!!!
With a little modification, I did the suggested object map and then:
let imgURL = {
Food: food,
Stay: stay,
Sites: sites,
Tips: tips
}
<img id='guide' alt='user' src={imgURL[guide.guide_type]}/>
I have a json file that looks like this:
"skills":[
{
"type":"Languages",
"skill":[
{
"name":"Python"
},
{
"name":"Java"
},
{
"name":"JavaScript"
},
{
"name":"HTML"
},
{
"name":"Bash"
},
{
"name":"MySQL"
}
]
},
{
"type": "Flavours",
"skill": [
{
"name":"Reactjs"
},
{
"name":"Angularjs"
},
{
"name":"Agile"
},
{
"name":"Waterfall"
},
{
"name":"Kanban"
}
]
},
{
"type": "Technologies",
"skill": [
{
"name":"Jira"
},
{
"name":" BitBucket"
},
{
"name":"Git"
}
]
}
]
},
And i am trying to render it using a nested mapping function:
var skills = this.props.data.skills.map((skills) =>{
var skill = skills.skill.map(function(skill){
return <li key={skill.name}>{skill}</li>
})
return <ul key={skills.type}>{skills}</ul>
})
However it says "Error: Objects are not valid as a React child (found: object with keys {name}). If you meant to render a collection of children, use an array instead."
So i tried it like this:
var skills = this.props.data.skills.map(function(skills){
var skillsArr = []
var skill = skills.skill.map(function(skill){
var skillArr = []
skillArr.push(<li key={skill.name}>{skill}</li>)
return <span>{skillArr}</span>
})
skillsArr.push(<div key={skills.type}><h3>{skills.type}</h3>
<ul>
{skill}
</ul>
</div>);
return <div>{skillsArr}</div>
})
But this too gives me the exact same error, i dont get what is wrong here because if i do a single mapping of just the skill types it works, it is only when i try to render the inner mapped items does this error occur and break my code
This is how i am calling it btw:
<div className="bars">
<ul className="skills">
{skills}
</ul>
</div>
If we are talking about using React, you should think more about how to organize your code in order to follow a proper component structure, that will let clear what you want to render and how to properly split your data and responsibilities.
Looking to your JSON, we have a set of "skills" that have skills inside it (let's call them "innerSkills").
We can easily split it into 3 components, let's think together:
We can have a List that will render all your Skills.
We can have a Skill that will be responsible for rendering each Skill data, inside it, we will need to render the InnerSkills, so let's split it to another component.
We have then InnerSkill, that will be responsible for rendering each innerSkill that we have for each skill.
So, long story short, what we have is:
List -> Skill -> InnerSkills
Great, now that we established the split, let's see how we can make each component responsible for rendering its data.
Let's say we want to simply call <List skills={data} />. Following this, we can then start on the list itself, which would look something like:
const List = ({ skills }) => (
<ul>
{skills.map((skill, i) => (
<Skill key={i} skill={skill} />
))}
</ul>
);
Now that we are looping through all Skills and calling the Skill component for rendering it, we can take a look at how Skill should look, since it will also need to loop through skill.
const Skill = ({ skill }) => (
<li>
<p>Type: {skill.type}</p>
<ul>
{skill.skill.map((innerSkill, i) => (
<InnerSkill key={i} innerSkill={innerSkill} />
))}
</ul>
</li>
);
Great. Now we already have the two loops you need to render all the data, so it's just missing the definition on how each InnerSkill should look like, and we can take a simplified approach and say we just want to render the name, so it could be something like:
const InnerSkill = ({ innerSkill }) => (
<li>
<p>Name: {innerSkill.name}</p>
</li>
);
To summarize this implementation, I made a simple code sandbox so you can See it live! and play around with the components.
I hope this clarifies your question and helps you to think better in the future on how you want to organize stuff, first check how to split, later how to render. Don't try to start rendering everything inside loops because it will get nasty.
There are two things in your code causing this error:
var skills = this.props.data.skills.map((skills) =>{
var skill = skills.skill.map(function(skill){
// should be <li key={skill.name}>{skill.name}</li>
return <li key={skill.name}>{skill}</li>
})
// should be <ul key={skills.type}>{skill}</ul>
return <ul key={skills.type}>{skills}</ul>
})
Assuming you want a single unordered list of all skill names, I'd suggest using the flatMap() function to re-write this as follows:
<div className="bars">
<ul className="skills">
{this.props.data.skills.flatMap((skillGroup) =>
skillGroup.skill.map((skill) => (
<li key={skill.name}>{skill.name}</li>
))
)}
</ul>
</div>
I am trying to render the following json response.
"tickets": {
"tickets": [
"A Nuisance in Kiribati",
"A Nuisance in Saint Lucia"
]
}
My attempt is as below.
const display4 = Object.keys(this.state.ticketsList).map(
(keyName, keyIndex) => {
return (
<div className="my-posts">
<li key={keyIndex}>{keyName}_{keyIndex}:</li>
<li key={keyIndex}>{this.state.ticketsList[keyName]}</li>
</div>
);
}
);
But it will display the tickets array in a single line without any separation even. I tried all most all the things on the internet. But nothing works yet. How can I fix this?
You are reading the raw array and displaying it - that's why it displays all in one line. this.state.ticketsList[keyName] is the array. So you need to iterate through it in an additional loop to display each item.
Try this:
const display4 = Object.values(this.state.ticketsList).map(
tickets => tickets.map((ticketName, index) =>
<div className="my-posts">
<li key={index}>{ticketName}_{index}:</li>
<li key={index}>{ticketName}</li>
</div>
)
);
In Cyress Test writing an test of react application when I click on a Listbox in the drop down it get list of data.
eg : 123a, 1233, 111c etc suppose have count 50
then select each 1 by 1 however need to compare each that if its certain account perform certain checks
in details:
have searched and clicked the listbox but the issue i am facing how can i find the total number of elements in that listbox and need to traverse each item/value 1 by 1 and when select verify certain asserts.
so 3 challenges where i am stuck
1) How to get total number of elements have tried initial count=cy.get('#alias').length seems not working.
2) after we get how can I iterate through the loop 1 at a time as after selecting 1 item as have to certain assertions.
Thanks
Varun Awasthi
First:
cy.get("alias").length can never work because of the async structure of cypress. The get() returns never the wrapped element but a chainable. Thus you would have to write something like get(..).then(obj => ...)
Second:
Given this HTML structure:
<div>
<div class="item">
...many other html code
</div>
<div class="item">
...many other html code
</div>
<div class="item">
...many other html code
</div>
</div>
You can get the length ( = the mount of item elements) like this:
it("test", () => {
cy.get(".item").should($items => {
cy.log(`amount: ${$items.length}`)
})
})
Third:
Please try something like this:
it("test", () => {
cy.get(".item").each($item => {
cy.wrap($item).should($e => {
expect($e.text()).to.eq("test")
})
})
})
But you must not use cypress commands here. Something like this should also work:
cy.get(".item").should($items => {
for(var i = 0; i < $items.length; i++) {
expect($items[i].text()).to.eq(...)
}
})
So you can also work with a combination of cypress commands and jQuery.
Let me know if you need furhter assistance
I am new to this, but to get the count of elements returned I would use something like this:
cy.get('.item').its('length')
Then, if you want to work with specific elements from that array:
.then(size => {
for(i= 0; i < size: i++) {
cy.get('.item').eq(size).should('have.value', 'list item')
}
})