showing only first element from data - javascript

Hi all I have following code: my code
In this scenario I am receiving some data from backend
const attachments = [
{
id: 1,
name: "someURLL_Name_1",
link: "https://someURLL_Name_1",
img: "https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885__340.jpg"
},
{
id: 2,
name: "someURLL_Name_2",
link: "https://someURLL_Name_2",
img: "https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885__340.jpg"
},
{
id: 3,
name: "someURL_Name_3",
link: "https://someURLL_Name_3",
img: "https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885__340.jpg"
}
];
I need to map them all and show only first element form my data, and show with numbers rest hided data.
In the end it should be like something like this:
someURL_Name_1 https://someURLL_Name_1 +2 more
I successfully mapped all my data and write little logic for + more.
<div className={Styles.attachments}>
{data.map((item) => {
return <Attachment key={item.id} data={item} image={item.img} />;
})}
{data.length > 1 && (
<span className={Styles.more}>+{data.length - 1} more</span>
)}
</div>
Please help me to resolve a problem. Again, I want to show only first element , and then if there are another elements then I should hide them and show hide elements with numbers.
Thanks.

Just don't map over all entries then. The following will work :-
export const Attachments = ({ data }) => {
return (
<div className={Styles.attachments}>
{data[0] && (
<Attachment key={data[0].id} data={data[0]} image={data[0].img} />
)}
{data.length > 1 && (
<span className={Styles.more}>+{data.length - 1} more</span>
)}
</div>
);
};

Related

How to display array data that varies in length

I got 2 objects inside the array, and 1st object is longer than the 2nd object. How can i render all of the properties of the 1st object without getting undefined, i get undefined because there are only 2 properties existing in the second object of the array .Also how can i calculate total sum of exercises?
function App() {
const course = [
{
name: 'Half Stack application development',
id: 1,
parts: [
{
name: 'Fundamentals of React',
exercises: 10,
id: 1
},
{
name: 'Using props to pass data',
exercises: 7,
id: 2
},
{
name: 'State of a component',
exercises: 14,
id: 3
},
{
name: 'Redux',
exercises: 11,
id: 4
}
]
},
{
name: 'Node.js',
id: 2,
parts: [
{
name: 'Routing',
exercises: 3,
id: 1
},
{
name: 'Middlewares',
exercises: 7,
id: 2
}
]
}
]
// calculate total of exercises
const totalExercises = course.reduce((total, course) => total + course.exercises, 0);
return (
<div className="App">
<header className="App-header">
<h1>Seoul</h1>
<Course course={course} totalExercises={totalExercises} />
</header>
</div>
)
}
function Course({ course, totalExercises }) {
return (
<>
<ul>
{course.map((course) => (
<li key={course.id}>
<p>{course.name} {course.exercises}</p>
<p>{course.parts[0].name}</p>
<p>Total exercises: {course.parts[0].exercises},</p>
<p>{course.parts[1].name}</p>
<p>Total exercises: {course.parts[1].exercises}</p>
// Undefined one below
UNDEFINED <p>{course[0].parts[2].name}</p>
</li>
))}
</ul>
</>
);
}
You could use map the parts array to the elements:
function Course({ course, totalExercises }) {
return (
<>
<ul>
{course.map((course) => (
<li key={course.id}>
<p>{course.name} {course.exercises}</p>
{
course.parts.map((part, id)=>(
<React.Fragment key={id}
<p>{part.name}</p>
<p>Total Excercises: {part.exercises}</p>
</React.Fragment>
))
}
</li>
))}
</ul>
</>
);
}
If you are not sure that if a key is present in an object and want to render it if it is there without having any error, use ?. to access keys.
For example
let a ={name:'Shivansh'};
console.log(a?.name,a?.id);
a ={id:3};
console.log(a?.name,a?.id);
Output for 1st console.log
Shivansh undefined
2nd console.log
undefined 3
One more thing you can give a fallback customized text if you want instead of undefined by using ?? operator.
op1 ?? op2
if op1 gives undefined then op2 is executed
Ex->
console.log(a?.name??'',a?.id??'')
//This will ensure you don't receive undefined but empty string.
To calculate total sum of excercies->
let sum = 0;
course.forEach(course => course ? .parts ? .forEach(part => sum = sum + p
parseInt(part ? .exercises ? ? 0)))
function Course({ course, totalExercises }) {
return (
<>
<ul>
{course.map((course) => (
<li key={course.id}>
<p>{course.name} {course.exercises}</p>
{course.parts.map((part,i) => {
return(
<div key={i}>
<p>{part.name}</p>
<p>Total exercises: {part.exercises},</p>
</div>
)
})}
</li>
))}
</ul>
</>
);
}
Same way that you are mapping course.map(... you can then map the parts for each course, code above works without an error for me.
You try to render an array manually... it's a bad idea imagine that your array is dynamic how you can anticipate the number of elements in the array?
Done as follows.
function Course({ course, totalExercises }) {
return (
<>
<ul>
{course.map((course) => (
<li key={course.id}>
<p>{course.name} {course.exercises}</p>
{course.parts?.map((part, index) => (
<div key={index}>
<p>{part.name}</p>
<p>Total exercises: {part.exercises},</p>
</div>
))}
</li>
))}
</ul>
</>
);
}
I hope my English doesn't tire you, I'm French-speaking

Count number of Children in recursive react component

I'm working on a comment system and used a recursive approach to show parent and child comments. When I delete a child, I want to update the count of child comments for its parent.
//json data
data = [{
name: 'Parent1',
childComments: [{
name: 'Child1',
text:'child comment1'
},
{
name: 'Child2',
text:'child comment2'
}]
},{
name: 'Parent2',
childComments: [{
name: 'Child1',
text:'child comment1'
},
{
name: 'Child2',
text:'child comment2'
}]
}]
const Comment = ({ item }) => {
const childComment = item
//delete child element and update the parent count
const deleteChildComment =(item) => {
}
return childComment && (
<>
{name}
Children count : {childComments.length}
<Button
className={styles.replies}
onClick={() => {
setNewCommentAdded(false)
deleteChildComment(childComment)
}}
> Delete This comment </Button>
{childComments && items.map((item) => (
<Comment item={item} />
))}
</>
)
}
Counting the children would be a bad idea and make things way too complicated.
Just use the data you use to generate the comment component.
As a rule, always make a UI represent data. Don't try to derive data from your UI layout.
e.g
commentList.map((comment) => (<Comment childCount={comment.children.length}));

Nested Map is not working properly on react template

I am trying to mapping through three objects in react to render multiple categories on react template , Code doesn't give any error but its not showing any content on react web page.
return (
<div className="container pt-80">
<center>Category Grouping</center>
{categories.map((cate,key)=>{
subCategories.map(subCate=>{
if(subCate.category === cate.id){
pType.map(ptype=>{
if (ptype.category === subCate.id){
console.log("Category : ",cate.category)
console.log("Sub Category : ",subCate.subCatName)
console.log("Product Type : ",ptype.ptype)
console.log("*******************************************")
return(
<Fragment>
<h1 style={{marginLeft:"30px"}}>{cate.category}</h1>
<h1 style={{marginLeft:"60px"}}>{subCate.subCatName}</h1>
<h1 style={{marginLeft:"120px"}}>{ptype.ptype}</h1>
</Fragment>
)
}
})
}
})
})}
</div>
)
Its printing the correct values in console :
Extending what #Akhil said in the comment. You are actually not returning anything in you're first two map calls, only the last.
add return before both nested map calls:
return subCategories.map(subCate=>{...
and
return pType.map(ptype=>{
Also I would add a return null after your if statements. Map expects a return value.
if(subCate.category === cate.id){
....
}
return null;
and
if (ptype.category === subCate.id){
....
}
return null;
Look into the comment by #Akhil. You missed the return for the map.
const categories = [{ id: 1, category: "Foods & Supplements" }];
const subCategories = [{ id: 1, category: 1, subCatName: "Herbal Drinks" }];
const pType = [
{ id: 1, category: 1, ptype: "Herbal Juice" },
{ id: 2, category: 1, ptype: "Herbal Coffee Tea&Soup" }
];
export default function App() {
return (
<div>
<h1>Category Grouping</h1>
{categories.map((cate, key) => (
<div key={key}>
{subCategories.map((subCate, sKey) => (
<div key={sKey}>
{subCate.category === cate.id &&
pType.map((ptype, pKey) => (
<div key={pKey}>
{ptype.category === subCate.id && (
<>
<h1 style={{ marginLeft: "30px" }}>{cate.category}</h1>
<h1 style={{ marginLeft: "60px" }}>
{subCate.subCatName}
</h1>
<h1 style={{ marginLeft: "120px" }}>{ptype.ptype}</h1>
</>
)}
</div>
))}
</div>
))}
</div>
))}
</div>
);
}
Also, use some sort of linting (e.g. Eslint) and format the code, both will help to catch syntax errors.

iterate a list inside another in react

i'm pretty new to react and javascript and i want to know how to iterate a list inside another list.
I have this json variable:
this.state = {
groups: [{
name: '',
permission: [{
name: ''
}]
}]
}
What I want to do is to count the number of elements the second list has, i did this following code but it sends the follwoing error, groups.map is not a function:
render() {
let permissionGroup = this.state.groups.map((groups) => {
let x = 0;
groups.map((permission) => {
x++;
})
})
return (
<div>
{this.state.groups.map((groups) => {
return (<li key={groups.code}>
<Card style={{ width: '20rem' }}>
<Card.Body>
<Card.Title>{groups.name}</Card.Title>
<Card.Subtitle className="mb-2 text- enter code heremuted">Permissions info</Card.Subtitle>
<Card.Text>
This group has {permissionGroup} permissions in it.
</Card.Text>
<Card.Link href="#">Add Permission</Card.Link>
<Card.Link href="#">Remove Permission</Card.Link>
</Card.Body>
</Card>
</li>)
})}
</div>
Inside your first map, it should be groups.permission.map, not groups.map.
let permissionGroup = this.state.groups.map((groups) => {
let x = 0;
groups.permission.map((permission) => {
That's because your first map is defining each "groups" as this:
{name: '', permission: [{name: ''}]}
So groups in this sense is an object, not an array. Access permission to get to the array you want.

React how to get index in search

I have an application to divide between available and non-available coupon, when user clicked available coupon the coupon will go to non-available section (vice versa), everything works fine. But, if I searched the coupon in the search box, the bug happens, turns out I can't get the initial index of the searched coupon (it will always change to index 0)
For instance, Coupon B should have index 1, but when i type Coupon B in the search box the index will change to 0, which break my changedHandler logic. How can i solve this?
You can see my application in Action through this link https://go-coupon-d0fe4.firebaseapp.com/
MainContainer.Jsx
state = {
availableCoupon: ['Coupon A', 'Coupon B', 'Coupon C', 'Coupon D'],
nonAvalailable: ['filter0', 'filter1', 'filter2', 'filter3'],
text: ''
};
searchHandler = text => {
this.setState({ text });
};
changedHandler = i => {
console.log(i);
const r = window.confirm('Use Coupon?');
if (r) {
let newItems = [...this.state.nonAvalailable];
let updatedItems = this.state.availableCoupon.splice(i, 1);
newItems.push(...updatedItems);
this.setState({
nonAvalailable: newItems
});
console.log('THIS IS NEW ITEMS ' + updatedItems);
}
return false;
};
render(){
return(
<SearchBox
searchTerm={this.state.text}
filteredList={this.state.availableCoupon}
searchHandler={this.searchHandler}
/>
<FilteredItem
changed={this.changedHandler}
searchTerm={this.state.text}
availableCoupon={this.state.availableCoupon}
/>
)
}
SearchBox.jsx
<Input
onChange={e => this.props.searchHandler(e.target.value)}
value={this.props.text}
type="text"
name="coupone"
id="exampleCoupon"
placeholder="Coupon Goes Here"
/>
filteredItem.jsx
{this.props.availableCoupon
.filter(
item =>
`${item}`
.toUpperCase()
.indexOf(this.props.searchTerm.toUpperCase()) >= 0
)
.map((item, index) => {
return (
<Col key={index} className="mt-3" md="2" lg="2" sm="3" xs="4">
<Card onClick={() => this.props.changed(index)}>
<CardBody>
<CardTitle>{item}</CardTitle>
</CardBody>
</Card>
</Col>
);
})}
So, the reason it is not working is because the key attribute that you rely on changes every time you actually search. So you have 2 options:
1 - use objects instead of strings, which is kind of more real-world like. Objects have properties that are unique, and not supposed to change, like id for example, or might be something else. For example [{name: 'ABCDE', id: 1}, {name: 'PQRST', id: 2}]. And so you build filtering, deleting etc on them.
2 - Stay with using strings for a while, but rather rely on the index of each element of the initial array.
Here is what I mean:
{this.props.availableCoupon
.filter(
item =>
`${item}`
.toUpperCase()
.indexOf(this.props.searchTerm.toUpperCase()) >= 0
)
.map((item, index) => {
return (
let ind = this.props.availableCoupon.indexOf(item);
<Col key={index} className="mt-3" md="2" lg="2" sm="3" xs="4">
<Card onClick={() => this.props.changed(ind)}>
<CardBody>
<CardTitle>{item}</CardTitle>
</CardBody>
</Card>
</Col>
);
})}
The second one is a realy quick fix but in real world you usually do not do that. And you probably won't need that as long as in real world we have stable id of each object and with it.
As you can see, using the index of the array as a key for each item is unreliable, since the item's key will change whenever its position in the array changes, therefore making the key pretty much useless.
What you should do instead is make it so that your items are objects with unique IDs associated with each one, so that the ID of each item will always match with the item you're working with. Wherever you're using index, use item.id instead.
availableCoupon: [
{name: 'Coupon A', id: 0},
{name: 'Coupon B', id: 1},
{name: 'Coupon C', id: 2},
{name: 'Coupon D', id: 3},
],
nonAvalailable: [
{name: 'filter0', id: 4},
{name: 'filter1', id: 5},
{name: 'filter2', id: 6},
{name: 'filter3', id: 7},
],
Make sure to update the rest of your code accordingly, e.g. by doing <Col key={item.id}>, filtering by item.name instead of item, and so on.

Categories