Splitting a single dynamic list in multiple lists using React? - reactjs

I am new around here. Doing my first own project with React, I am stuck to achieve this. After mapping a list using .map(), how can I have multiple lists split? I want them to be split by the first letter on each new <ul>, regardless the number of titles. Some titles have more than 5 or 10, for each letter. Some are not even showed, because there are no titles with that letter.
My code
<ul>
{list.map((i) => (
<li>
{i.title}
</li>
))}
</ul>
Result
<ul>
<li>title aa</li>
<li>title ab</li>
<li>title ac</li>
<li>title ba</li>
<li>title bb</li>
<li>title bc</li>
<li>title ca</li>
<li>title cb</li>
<li>title cc</li>
…
</ul>
Desired
<ul>
<li>title aa</li>
<li>title ab</li>
<li>title ac</li>
</ul>
<ul>
<li>title ba</li>
<li>title bb</li>
<li>title bc</li>
</ul>
<ul>
<li>title ca</li>
<li>title cb</li>
<li>title cc</li>
</ul>
…
Thanks for any help and possible solution.

You should reduce the list values following the desired pattern, then iterate over the sub-items one by one:
const grouped = list.reduce((acc, obj) => {
const key = obj.title.charAt(6);
acc[key] = acc[key] || [];
acc[key].push(obj);
return acc;
}, {});
which will lead grouped values as follows:
{
a: [{
title: "title aa"
}, {
title: "title ab"
}],
b: [{
title: "title ba"
}, {
title: "title bb"
}],
c: [{
title: "title ca"
}, {
title: "title cb"
}]
}
You can then go through the grouped object and map to your proper layout:
Object.values(grouped).map(list => (
<ul>
{list.map((i) => (
<li>
{i.title}
</li>
))}
</ul>
});

It will depends on what is the condition to split your lists, but you can use reduce to generate a new list that will contains the splits that you need and then apply those splits to a new list.
function splitList(list) {
return list.reduce((acc, cur) => {
const lastSplit = acc[acc.length -1];
if(lastSplit && lastSplit[0][0] === cur[0]) {
return [...acc.slice(0, -1), [...lastSplit, cur]];
} else {
return [...acc, [cur]];
}
}, []);
}
After having your splits, you do the same thing you are doing for the li items, but for ul as well: (Replace the names of the variables)
{splitList(list).map(item) => (
<ul>
{item.map((i) => (
<li>
{i.title}
</li>
))}
</ul>
)}

Related

Simple List Rendering in Vue with finding Index and passing props

so I do the beginning todo list stuff. I have this array
state() {
return {
news: [
{
id: 1,
title: "Titel 1",
text: "Beispieltext 1"
},
{
id: 2,
title: "Titel 2",
text: "Beispieltext 2"
}
]
}
},
I want to list items (NewsItem) in a list (NewsItemList) for every entry in the news-array. As simple as that.
This is my NewsItem
<template>
<div class="newsitem">
<h1
v-for="nachricht in news"
:key="nachricht.id"
>{{nachricht.title}}</h1>
<p
v-for="nachricht in news"
:key="nachricht.id"
>{{nachricht.text}}</p>
</div>
</template>
<script>
export default {
data() {
return {};
}
};
</script>
And this is my NewsItemList
<template>
<ul>
<li
v-for="nachricht in news"
:key="nachricht.id"
>
<NewsItem />
</li>
</ul>
</template>
<script>
import NewsItem from "#/components/NewsItem";
export default {
components: {
NewsItem,
},
computed: {
news() {
return this.$store.getters.getNewsList;
}
}
};
</script>
I want to map through my array in NewsItemList and give the information as props to my NewsItem. What is the simplest way?
In React, I needed to find the index with the findIndex() function. How can I do this in vue?
As I am just beginning, could you help me to find a simple way? Thank you!
Props
NewsItem
<template>
<div class="newsitem">
<h1>{{ title }}</h1>
<p>{{ text }}</p>
</div>
</template>
<script>
export default {
props: {
title: String,
text: String,
},
data() {
return {}
},
}
</script>
Now you can use that in your NewsItemList
<template>
<ul>
<li v-for="nachricht in news" :key="nachricht.id">
<NewsItem :title="nachricht.title" :text="nachricht.text"/>
</li>
</ul>
</template>
If I understood you correctly, you just need to pass prop with news item object :
Vue.component('NewsItem', {
template: `
<div class="newsitem">
<h1 >{{item.title}}</h1>
<p>{{item.text}}</p>
</div>
`,
props: ['item']
})
new Vue({
el: "#demo",
data() {
return {
news: [
{
id: 1,
title: "Titel 1",
text: "Beispieltext 1"
},
{
id: 2,
title: "Titel 2",
text: "Beispieltext 2"
}
]
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<ul>
<li
v-for="nachricht in news"
:key="nachricht.id"
>
<news-item :item="nachricht"></news-item>
</li>
</ul>
</div>

How to return a tree of react tags from a Map() object in React?

I want to return a return a structure like :
<div>
<div label=Category 1>
<ul>
<li>item1</li>
<li>item2</li>
</ul>
<br/>
</div>
<div label=Category 2>
<ul>
<li>item3</li>
<li>item4</li>
</ul>
<br/>
</div>
</div>
In order to achieve this, I created a Map() object an I want to iterate through categories and items. Desperately tried all sorts of ideas with no luck. I am not sure if is very simple or impossible in react. I am imagining to run stg. like this and 1) yet it does not return any value 2) splitting the ul tag is not allowed, apparently.
for (let [key, values] of lists) {
<div label={key}><ul>;
values.map(item => <li key={item.id}>{item.name}</li>);
</ul>
</div>
}
This is a working version of #Expressd3v's code (possibly with a couple of edits). I tried to add this to #Expressd3v answer but the edit's not been approved so maybe that wasn't the right way to go about it. Please don't upvote this as it's basically #Expressd3v answer.
Edited to use Map().
const Lists = ({ lists }) =>
<React.Fragment>
{
[...lists].map(([key, values]) => (
<div label={key} key={key}>
<ul>
{ values.map(item => <li key={item.id}>{item.name}</li>) }
</ul>
</div>
))
}
</React.Fragment>;
const App = () => {
let lists = new Map();
lists.set('Category 1', [
{ id: 1, name: 'item1' },
{ id: 2, name: 'item2' },
]);
lists.set('Category 2', [
{ id: 3, name: 'item3' },
{ id: 4, name: 'item4' },
]);
return <Lists lists={lists} />;
};
ReactDOM.render(<App />, document.getElementById('root'));
<script crossorigin src="https://unpkg.com/react#17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#17/umd/react-dom.development.js"></script>
<div id="root"></div>
Missing
For loop is not returning any value.
So you need to include a return.
for example:
for (let [key, values] of lists) {
return(
<div label={key}>
<ul>
{values.map(item => <li key={item.id}>{item.name}</li>);}
</ul>
</div>
)
}
My suggestion
Object.entries(lists).map(([key,values])=>(
<div label={key} key={key}>
<ul>
{values.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
</div>
)
))

Vue 2 - How to v-for a property from an array that is inside an object

I am trying to infer the time property from the TimeMode array which is inside the main array called girlsList, but i have nothing displayed, You can see this example in codesandbox
<template>
<div>
<p>The time property is not displayed</p>
<ul>
<li v-for="(item, index) in girlsList.TimeMode" :key="index">
{{ item.time }}
</li>
</ul>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
girlsList: [
{
avatarSrc: "https://i.ibb.co/G0nLSQ8/Girl-1.png",
girlName: "Milena Williams",
girlTime: "12:00 - 16:00 PM",
TypeTime: "Cosplay",
TimeMode: [
{
time: 60,
},
],
},
{
avatarSrc: "https://i.ibb.co/qJB12x6/Girl-2.png",
girlName: "Milena Williams",
girlTime: "12:00 - 16:00 PM",
TypeTime: "Cosplay1",
TimeMode: [
{
time: 60,
},
],
},
],
};
},
};
</script>
<ul v-for="(i, index) in girlsList" :key="index">
<li v-for="(item, index) in i.TimeMode" :key="index">
{{ item.time }}
</li>
</ul>
GirList and TimeMode are arrays, so you need do a for beetween both (two for) or put a position in TimeMode array:
<li v-for="(item, index) in girlsList" :key="index">
{{ item.TimeMode[0].time }}
</li>

Datapicker React - Having a hard time displaying the date

I am trying to render several inputs (name, location, # of plants and 2 dates).
The 2 dates dont want to get displayed for some reasons they stay in an array format... I tried trooble shooting in several ways but nothing does :(
Any idea?
Here is the App part
let InitialOwners = [
{ nameOwner: 'Julie S', locationOwner: "Eixample", plantsOwner: "2" , startDateOwner: [{}] , endDateOwner : [] }
];
function App() {
const [owners, setOwners] = useState(InitialOwners);
// to get the data from PO form
function handleOwnerData(ownerData) {
let newOwners = [...owners, ownerData];
setOwners(newOwners)
console.log(`Owner Data: ${ownerData.locationOwner} ${ownerData.nameOwner} ${ownerData.plantsOwner} ${ownerData.startDateOwner} ${ownerData.endDateOwner}`)
}
Here is the list part where the data should be displayed
import React from "react";
function DashboardUsers(props){
return (
<div className ="Dashboard">
<h2> Welcome to the Dashboard</h2>
<h4> Here are the current owners </h4>
<ul>
{
props.owners.map((owners,i) => (
<div key={i}>
<li> Name: {owners.nameOwner}</li>
<li> Location: {owners.locationOwner} </li>
<li> # of plants: {owners.plantsOwner} </li>
<li> Start Date: [owners.startDateOwner] </li>
<li> End Date:[owners.endDateOwner] </li>
</div>
))
}
</ul>
</div>
)
}
export default DashboardUsers;
And here is how it looks like on the browser :D
browser image
When you are mapping over an array with objects each entry in the map, in your case 'owners', represents the current object. In that case owners.startDateOwner is an array of objects inside an array of objects. If you want to iterate over it you need to nest another map:
{
props.owners.map((owners,i) => (
<div key={i}>
<li> Name: {owners.nameOwner}</li>
<li> Location: {owners.locationOwner} </li>
<li> # of plants: {owners.plantsOwner} </li>
<li> Start Date: {owners.startDateOwner.map((ownerStartDate) => <span>{ownerStartDate}</span>)} </li>
<li> End Date:[owners.endDateOwner] </li>
</div>
))
}
this will iterate over the dates and print them in a <span>

Compare two lists in angularJs

I have two list that creat from two different json object:
<ul ng-repeat="a in user.data">
<li>
<md-checkbox>
{{ a.name }}
</md-checkbox>
</li>
</ul>
and :
<ul ng-repeat="x in job.data">
<li>
<md-checkbox>
{{ x.user.name }}
</md-checkbox>
</li>
</ul>
I have to compare two lists and remove {{ a.name }} that the same as {{ job.user.name }} . Comparing json objects that have different structure is hard. How can I compare this two list and remove repeated items?
You can use the filter filter ;) using a function instead of a string in the expression argument. Remember this is the syntax of filter
{{ filter_expression | filter : expression : comparator}}
The expression can be a string, an object or a function. Something like this will do
$scope.filterUnemployed = function(value) {
var jobs = $scope.job.data;
for (var i = 0; i < jobs.length; i++) {
// Search every object in the job.data array for a match.
// If found return false to remove this object from the results
if (jobs[i].user.name === value.name) {
return false;
}
}
// Otherwise return true to include it
return true;
}
And then apply the filter to your ng-repeat directive like this
<ul ng-repeat="a in user.data | filter:filterUnemployed">
<li>
<md-checkbox>
{{ a.name }}
</md-checkbox>
</li>
</ul>
Note that this will not modify your original collection but will result in a new copy beign displayed in your html since this is usually the desired effect.
Check the sample for a working demo
angular.module('app', [])
.controller('SampleCtrl', function($scope) {
$scope.user = {
data: [{
name: 'John'
}, {
name: 'Mary'
}, {
name: 'Peter'
}, {
name: 'Jack'
}, {
name: 'Richard'
}, {
name: 'Elizabeth'
}]
};
$scope.job = {
data: [{
jobTitle: 'CEO',
user: {
name: 'John'
}
}, {
jobTitle: 'CFO',
user: {
name: 'Mary'
}
}, {
jobTitle: 'Analist',
user: {
name: 'Jack'
}
}]
};
$scope.filterUnemployed = function(value) {
var jobs = $scope.job.data;
for (var i = 0; i < jobs.length; i++) {
if (jobs[i].user.name === value.name) {
return false;
}
}
return true;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="SampleCtrl">
<h1>All Users</h1>
<ul ng-repeat="a in user.data">
<li>
<md-checkbox>
{{ a.name }}
</md-checkbox>
</li>
</ul>
<h1>Unemployed users</h1>
<ul ng-repeat="a in user.data | filter:filterUnemployed">
<li>
<md-checkbox>
{{ a.name }}
</md-checkbox>
</li>
</ul>
<h1>Employed</h1>
<ul ng-repeat="x in job.data">
<li>
<md-checkbox>
{{ x.user.name }}
</md-checkbox>
</li>
</ul>
</div>
You can create a new array made from filtering one of your arrays :
var newArray = job.data.filter(function(jobData) {
return user.data.some(function(userData) {
return userData.name === jobData.user.name;
});
});
Something like this should help :
for(i=0; i<user.data.length;i++){
for(j=0; j<job.data.length;j++){
if(user.data[i].name === job.data[j].name){
user.date.splice(i,1);
}
}
}
I would appreciate some feedback, at least to know that my code helped you
You can use vanilla javascript, jQuery or library undescore.
Please check related links:
How can I merge two complex JSON objects with only unique or different values only showing in resultant array
How to merge two object values by keys
How to merge two arrays of JSON objects - removing duplicates and preserving order in Javascript/jQuery?
Merging two json objects in Java script?

Resources