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>
Related
The app is loading multiple profiles from an API. When a profile's corresponding button is clicked, that profile's grades should be displayed. The issue is when a button is clicked all profile grades are being displayed.
const Profiles = () => {
const [expand, setExpand] = useState(false)
const ToggleGrades = () => {
setExpand(prev => !prev)
}
return (
<>
<div className="profile-container">
<div className="profile-info">
<h1 className="profile-name">{profile.firstName} {profile.lastName}</h1>
<p className="profile-info">Email: {profile.email}</p>
<p className="profile-info">Company: {profile.company}</p>
<p className="profile-info">Skill: {profile.skill}</p>
<p className="profile-info">Average: {profile.grades}%</p>
{
expand &&
<ul>
<li key={profile.id[0]} className="profile-grades">Test 1: {profile.grades[0]}</li>
<li key={profile.id[1]} className="profile-grades">Test 2: {profile.grades[1]}</li>
<li key={profile.id[2]} className="profile-grades">Test 3: {profile.grades[2]}</li>
<li key={profile.id[3]} className="profile-grades">Test 4: {profile.grades[3]}</li>
<li key={profile.id[4]} className="profile-grades">Test 5: {profile.grades[4]}</li>
<li key={profile.id[5]} className="profile-grades">Test 6: {profile.grades[5]}</li>
<li key={profile.id[6]} className="profile-grades">Test 7: {profile.grades[6]}</li>
<li key={profile.id[7]} className="profile-grades">Test 8: {profile.grades[7]}</li>
</ul>
}
</div>
<div className="profile-grades-expander">
<button className="profile-expand-button" onClick={ToggleGrades}>{expand ? "-" : "+"}</button>
</div>
</div>
</>
);
}
export default Profiles;
You should specify which profile to expand, try to save the id of clicked profile in a state, and use this to check whether you should expand the profile or not.
Note:
Replace in the code profile.id with the correct one, I don't know the structure of the object profile.
const Profiles = () => {
const [profileToExpand, setProfileToExpand] = useState()
const ToggleGrades = (id) => {
setProfileToExpand(id)
}
return (
<>
<div className="profile-container">
<div className="profile-info">
<h1 className="profile-name">{profile.firstName} {profile.lastName}</h1>
<p className="profile-info">Email: {profile.email}</p>
<p className="profile-info">Company: {profile.company}</p>
<p className="profile-info">Skill: {profile.skill}</p>
<p className="profile-info">Average: {profile.grades}%</p>
{(profileToExpand === profile.id) &&
<ul>
<li key={profile.id[0]} className="profile-grades">Test 1: {profile.grades[0]}</li>
<li key={profile.id[1]} className="profile-grades">Test 2: {profile.grades[1]}</li>
<li key={profile.id[2]} className="profile-grades">Test 3: {profile.grades[2]}</li>
<li key={profile.id[3]} className="profile-grades">Test 4: {profile.grades[3]}</li>
<li key={profile.id[4]} className="profile-grades">Test 5: {profile.grades[4]}</li>
<li key={profile.id[5]} className="profile-grades">Test 6: {profile.grades[5]}</li>
<li key={profile.id[6]} className="profile-grades">Test 7: {profile.grades[6]}</li>
<li key={profile.id[7]} className="profile-grades">Test 8: {profile.grades[7]}</li>
</ul>
}
</div>
<div className="profile-grades-expander">
<button className="profile-expand-button" onClick={() => ToggleGrades(profile.id)}>{expand ? "-" : "+"}</button>
</div>
</>
)
})}
</div>
}
</div>
</>
);
}
export default Profiles;
The code example you posted seems incomplete. But reading between the lines, it seems that you have one variable "expand", defined in your Profiles component, which is used by all the profiles.
You should use nested components: A ProfileList component, and a SingleProfile component. The expand state variable should be in the SingleProfile component.
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>
)}
I'm having a strange problem creating a list with Vuejs. I have an array like so:
const sr = new Vue({
el: '#singlerecipe-app',
data: {
checkeditems: [],
},
});
And this is instantiated in my HTML like so:
<div class="container" id="singlerecipe-app">
<singlerecipe :checkeditems="checkeditems"></singlerecipe>
</div>
And declared as a Prop in my component:
Vue.component('singlerecipe', {
props: ['checkeditems'],
template: `
<ul>
<li v-for="item of checkeditems">
{{ item.checkeditems }}
</li>
</ul>
`
})
The checked items code is:
<li v-if="result.strIngredient1">
<input type="checkbox" :value="result.strIngredient1" :id="result.strIngredient1" v-model="checkeditems"> {{result.strIngredient1}} - {{result.strMeasure1}}
</li>
<li v-if="result.strIngredient2">
<input type="checkbox" :value="result.strIngredient2" :id="result.strIngredient2" v-model="checkeditems"> {{result.strIngredient2}} - {{result.strMeasure2}}
</li>
If I click on one of the checkbox it definitely adds the correct value to the array checkeditems[] but oddly, it creates the new list items but doesn't add the value so I end up with this:
<ul>
<li></li>
<li></li>
</ul>
With no value in the list item. Does anyone have any idea what I'm doing wrong?
I think you've just accidentally added a 'checkeditems' in.
It should be:
Vue.component('singlerecipe', {
props: ['checkeditems'],
template: `
<ul>
<li v-for="item of checkeditems">
{{ item }}
</li>
</ul>
`
})
Well, the question is very self-explanatory. I have this code here (inside a render, of course):
const images = [('http://placehold.it/100x100/76BD22'), ('http://placehold.it/100x100/76BD23')];
// ProductPage Views
const ProductPageView =
<section className="page-section ps-product-intro">
<div className="container">
<div className="product-intro">
<div className="product-intro__images">
<div className="product-gallery">
<ul className="product-gallery-thumbs__list">
{images.map(function(image, imageIndex){
return <li key={ imageIndex }>{image}</li>;
})}
</ul>
</div>
</div>
</div>
</div>
</section>
The thing is I don't know how to iterate those images on the array. What's wrong with my code?
Your array is an array of image URLs, not image tags. So your code is close but you need to put the image inside of an image tag inside of your list item tag.
const images = [('http://placehold.it/100x100/76BD22'), ('http://placehold.it/100x100/76BD23')];
// ProductPage Views
const ProductPageView =
<section className="page-section ps-product-intro">
<div className="container">
<div className="product-intro">
<div className="product-intro__images">
<div className="product-gallery">
<ul className="product-gallery-thumbs__list">
{images.map(function(imageSrc) {
return (
<li key={ imgSrc }>
<img src={ imgSrc } />
</li>
);
})}
</ul>
</div>
</div>
</div>
</div>
</section>
I would also recommend against using an array index as a key in general. The imgSrc is unique so it would make a good key here.
Also, make sure to include an alt attribute on the img for screen readers. You might want to make your array like this:
const images = [
{ src: 'http://placehold.it/100x100/76BD22', alt: 'Your description here 1' },
{ src: 'http://placehold.it/100x100/76BD23', alt: 'Your description here 2' }
];
// ...
{images.map(function(imageProps) {
return (
<li key={ imageProps.src }>
<img src={ imageProps.src } alt={ imageProps.alt } />
</li>
);
})}
I assume you want to display them as images, right? You should use img tag then.
<ul className="product-gallery-thumbs__list">
{images.map(function(image, imageIndex){
return <img key={ imageIndex } src={ image } />
})}
</ul>
I am new to angularjs world and am trying to do something that I think should be achievable with a directive.
I have a template which has a list of articles listed using ng-repeat. These articles have a date on them. I want to group the articles by date in the template. So I am thinking of creating a directive that would append a new div before each group of articles in that day. The data in the model is already sorted by date desc.
Should I be using the compile function in the directive to do this ? Any code examples would be great.
If I understand you correctly you want the output to be something like:
<ul>
<li>
Show 3 articles for date 2012-12-07
</li>
<li>
Show 1 articles for date 2012-12-06
</li>
<li>
Show 2 articles for date 2012-12-05
</li>
</ul>
In that case, I would do the grouping before it renders:
function ArticlesController ($scope) {
var groupArticles = function (articles) {
var i,
art = {};
for (i = 0; i < articles.length; i += 1) {
if (!art.hasOwnProperty(articles[i].date)) {
art[articles[i].date] = [];
}
art[articles[i].date].push(articles[i]);
}
return art;
};
$scope.articles = [{ date: '2012-12-07', title: 'Marcus' },
{ date: '2012-12-07', title: 'Zero' },
{ date: '2012-12-06', title: 'Moxxi' },
{ date: '2012-12-05', title: 'Dr Zed' }];
$scope.groupedArticles = groupArticles($scope.articles);
}
And you view:
<ul data-ng-controller="ArticlesController">
<li data-ng-repeat="articles in groupedArticles">
<div data-ng-repeat="article in articles">
{{ articles.title }}
</div>
</li>
</ul>
<ul>
<li ng-repeat="article in articles">
<ng-switch on="$first || article.date != articles[$index-1].date">
<div ng-switch-when="true" class="group_heading">{{article.date}}</div>
</ng-switch>
{{article.title}}
</li>
</ul>
The above is modeled off an existing fiddle I had.
The above assumes (as you stated) that articles is already sorted. If not, the fiddle shows how to use the orderByFilter in a controller to create a sorted array based on any object property.