I am attempting to create a simple portfolio website and am having a hard time with the portfolio item details component. I have created a list of the portfolio items as a JSON data list that will fetch assets within the app. I decided to hard-code this rather than host the data because it won't be changing too often and the artist will be updating their portfolio once or twice a year.
Here is the simple list of data in JSON:
[
{
"id": "1",
"img_code": "florida.jpg",
"creation_medium": "Adobe Illustrator",
"meta": ["graphic design", "logo", "Adobe Illustrator", "Florida Graphics & Marketing"]
},
{
"id": "2",
"img_code": "musicapp.png",
"creation_medium": "Adobe XD",
"meta": ["app design", "music app", "Adobe XD", "Florida Graphics & Marketing"]
},
{
"id": "3",
"img_code": "dreamroom.jpg",
"creation_medium": "Sketch for iPad Pro",
"meta": ["hand sketch", "digital art", "Apple Sketch", "dream office"]
},
...
]
And I am attempting to filter that list in a component to display the appropriate item on a details page. Here is the code:
import React, { Component } from 'react'
import Data from '../data/portfolio.json';
export class PortfolioDetails extends Component {
constructor(props) {
super(props);
this.state = {
itemId: this.props.location.state ? this.props.location.state.id : window.location.pathname.split('/')[2],
portfolioItem: {}
}
}
componentDidMount() {
this.fetchPortfolioItems();
}
fetchPortfolioItems() {
const data = Data.filter(item => item.id = 1);
this.setState({portfolioItem: {data} });
}
render() {
....
}
}
export default PortfolioDetails
However, instead of returning the one item with the id of 1, it changes every item's id to one. Here is what I am getting when I console log the results ...
0: {id: 1, img_code: "florida.jpg", creation_medium: "Adobe Illustrator", meta: Array(4)}
1: {id: 1, img_code: "musicapp.png", creation_medium: "Adobe XD", meta: Array(4)}
2: {id: 1, img_code: "dreamroom.jpg", creation_medium: "Sketch for iPad Pro", meta: Array(4)}
What am I missing? I thought this would be a simple use of the filter() method.
Your code explicitly tells Javascript to assign the value of 1 to every id, and of course, 1 is truthy so it returns true to the filter function.
Change
const data = Data.filter(item => item.id = 1);
to
const data = Data.filter(item => item.id == 1);
Related
I have the following output coming from my backend
[
{
"_id": null,
"counts": [
{
"department": "Cleaning",
"number": 1
},
{
"department": "Engineering",
"number": 2
},
{
"department": "Transportation",
"number": 1
}
]
}
]
I would like to convert the following data into google chart format and consequently display it on a pie Chart in reactjs.
This is my first time of working with google-charts, i really have no idea how to do the conversion.
From what i read online, I could actually do something like this
class ChartPie extends React.Component {
state={
data:[]
}
componentDidMount(){
axios.get(`/api/v1/employee/departCount`)
.then(({data}) => { // destructure data from response object
// {department,number} from data
const restructuredData = data.map(({department, number}) =>
[department,number])
this.setState({data: restructuredData});
})
.catch(function (error) {
console.log(error);
})
}
if this where to be the case, then my other challenge will be how to make use of the new state inside the google chart API
render() {
return (
<div>
<Chart
width={'500px'}
height={'300px'}
chartType="PieChart"
loader={<div>Loading Chart</div>}
data={[
// how do I add the new state ?
]}
options={{
title: 'Work data',
is3D: true,
}}
I would appreciate any help whatsoever.
Here is some sample state should look like:
const data = [
["Element", "Density", { role: "style" }],
["Copper", 8.94, "#b87333"], // RGB value
["Silver", 10.49, "silver"], // English color name
["Gold", 19.3, "gold"],
["Platinum", 21.45, "color: #e5e4e2"] // CSS-style declaration
];
You need a couple of array manipulations to create a correct data state. Working sample: https://codesandbox.io/s/react-google-charts-column-chart-forked-spjmz?file=/src/index.js:577-845
I am using mongoose in nodejs(express) in backend. My array structure has THREE levels. At third level, some files are present. But I need to add entries at any level as per user demand.
[
{
"name": "A folder at",
"route": "level1_a"
},
{
"name":"Another folder at Level1",
"route": "level1_b",
"children":
[
{
"name": "A folder at Level2",
"route": "level1_b/level2_a",
"children":
[
{
"name": "A folder at Level3",
"route": "level1_b/level2_a/level3_a",
"children":
[
{
"name": "A file at last level",
"route": "level1_b/level2_a/level3_a/file1"
},
{
"name": "Add a new File",
"route":"level1_b/level2_a/level3_a/new_file"
}
]
},
{
"name": "Add Folder at Level3",
"route":"level1_b/level2_a/new_folder"
}
]
},
{
"name": "Add Folder at level2",
"route":"level1_b/new_folder"
}
]
},
{
"name": "Add Folder at Level1",
"route":"new_folder"
}
]
Now I have to add an entry at a specified position. Suppose at level2, I need to add a folder. For adding, two parameters are sent from angular to the backend. These will be 'name' and a 'route'. So my entry would be having {name: 'Products', route: 'level1_a/products'} and similarily should be placed at correct position i.e. inside the children of level1_a.
My backend has a schema which would be like:
const navSchema = mongoose.Schema({
name:{type:String,required:true},
route:{type:String},
children:{
type: {
name:{type:String,required:true},
route:{type:String},
}}
});
module.exports = mongoose.model('NatItems',navSchema);
And the API would be like:
router.post('/navlist',(req,res,next)=>{
const name= req.body.folder;
const route= req.body.url;
console.log(folder,url);//it will be required parameters like name: 'Products', route:'level1_a/products'
//let pathArray = route.split('/'); //if you want you can split the urls in the array
//Help me write the code here
res.status(201).json({
message:"Post added successfully!"
})
})
Please help me in adding entries in db. I know navlist.save() adds an entry directly but I am not able to add entries in a nested manner.
PS: I can't change the array structure because this array is easily read by angular and a complete navigation menu is made!! I am working for first time in nodejs and mongoose, so I am having difficulty in writing code with mongoose function.
For the scenario you've provided ({name: 'Products', route: 'level1_a/products'}) the update statement is pretty straightforward and looks like this:
Model.update(
{ route: "level1_a" },
{ $push: { children: {name: 'Products', route: 'level1_a/products'} } })
Things are getting a little bit more complicated when there are more than two segments in the incoming route, e.g.
{ "name": "Add a new File", "route":"level1_b/level2_a/level3_a/new_file2" };
In such case you need to take advantage of the positional filtered operator and build arrayFilters and your query becomes this:
Model.update(
{ "route": "level1_b"},
{
"$push": {
"children.$[child0].children.$[child1].children": {
"name": "Add a new File",
"route": "level1_b/level2_a/level3_a/new_file2"
}
}
},
{
"arrayFilters": [
{
"child0.route": "level1_b/level2_a"
},
{
"child1.route": "level1_b/level2_a/level3_a"
}
]
})
So you need a function which loops through the route and builds corresponding update statement along with options:
let obj = { "name": "Add a new File", "route":"level1_b/level2_a/level3_a/new_file2" };
let segments = obj.route.split('/');;
let query = { route: segments[0] };
let update, options = {};
if(segments.length === 2){
update = { $push: { children: obj } }
} else {
let updatePath = "children";
options.arrayFilters = [];
for(let i = 0; i < segments.length -2; i++){
updatePath += `.$[child${i}].children`;
options.arrayFilters.push({ [`child${i}.route`]: segments.slice(0, i + 2).join('/') });
}
update = { $push: { [updatePath]: obj } };
}
console.log('query', query);
console.log('update', update);
console.log('options', options);
So you can run:
Model.update(query, update, options);
I have a two history objects that are podcasts and articles, i want to display both in the same screen in descending order by which time they were clicked,
Here are the variables of original article and podcast from DB
var { articles, articlesInHistory, podcastsInHistory, podcasts } = this.props.stores.appStore;
Here is my article Object from history: console.log("dataItem", articlesInHistory)
dataItem Array [
Object {
"currentTime": 1585439646,
"id": "156701",
Symbol(mobx administration): ObservableObjectAdministration {
"defaultEnhancer": [Function deepEnhancer],
"keysAtom": Atom {
"diffValue": 0,
"isBeingObserved": true,
"isPendingUnobservation": false,
"lastAccessedBy": 26,
"lowestObserverState": 2,
"name": "appStore#1.articlesInHistory[..].keys",
"observers": Set {},
},
"name": "appStore#1.articlesInHistory[..]",
"pendingKeys": Map {
Symbol(Symbol.toStringTag) => false,
"hasOwnProperty" => false,
"toJSON" => false,
},
"proxy": [Circular],
"target": Object {
"currentTime": 1585439646,
"id": "156701",
Symbol(mobx administration): [Circular],
},
"values": Map {
"id" => "156701",
"currentTime" => 1585439646,
},
},
},
,]
And podcast from history: console.log("dataItem", podcastsInHistory)
dataItem Array [
Object {
"currentTime": 1585439636,
"id": "4",
Symbol(mobx administration): ObservableObjectAdministration {
"defaultEnhancer": [Function deepEnhancer],
"keysAtom": Atom {
"diffValue": 0,
"isBeingObserved": true,
"isPendingUnobservation": false,
"lastAccessedBy": 26,
"lowestObserverState": 2,
"name": "appStore#1.podcastsInHistory[..].keys",
"observers": Set {},
},
"name": "appStore#1.podcastsInHistory[..]",
"pendingKeys": Map {
Symbol(Symbol.toStringTag) => false,
"hasOwnProperty" => false,
"toJSON" => false,
},
"proxy": [Circular],
"target": Object {
"currentTime": 1585439636,
"id": "4",
Symbol(mobx administration): [Circular],
},
"values": Map {
"id" => "4",
"currentTime" => 1585439636,
},
},
},
]
now i want to order the two components using currentTime in condition
for example if this podcast was first then i should return
<PodcastList navigate={navigate} podcast={podcast} key={index} />)
Or if the article is first then show
<SmallArticle key={index} article={article} />
i need them mixed not like articles on top and podcast bottom, i been searching arrays sort but couldn't solve it.
I want a condition based on currentTime and using an id to identify or match objects thanks.
As you don´t know from the data if its an article or a podcast (there is no attribute in your objects that tells you that), you can´t put them in the same list-array.
The only way to know if you should render an Article or a Podcast component is based on what list you are reading.
Keep two indexes, articleIndex = 0 and podcastIndex = 0 (you can keep that in your state), and read the actual article and podcast for respective list, and compare the current time. Then you will know what component to render, and advance the corresponding list index.
In pseudo code:
while articleIndex < articlesList.length && podcastIndex < podcastList.length do:
if articlesList[articleIndex].currentTime < podcastList[pocastIndex].currentTime do:
render <SmallArticle article={articlesList[articleIndex]} key ={articleIndex}/>//render SmallArticle
articleIndex += 1; //advance index
else do:
render <PodcastList podcast={podcastList[postcastIndex]} key={podcastIndex} />
podcastIndex +=1;
when the while statement finishes, is because one of the list has been fully traversed. You need to traverse the rest of the other and render the respect component.
If you show me some of your components code can help you with code in more detail, but I don´t know the context.
I've defined an empty array in the react component constructor which I wish to assign with json response data from an API call
class Grid extends Component {
constructor(props) {
super(props);
this.state = {
blogs : []
};
}
I call the componentDidMount method to load data on this component where I'm using setState to assign values
componentDidMount(){
Axios.get("/api/blogs").then(response => {
const blogData = response.data;
this.setState({blogs: blogData.data});
});
}
The JSON response data is as follows (Laravel collection resource with meta and links)
{
"data": [
{
"title": "Experiments in DataOps",
"status": true,
"publish_date": "2020-01-29",
"slug": "experiments-in-dataops"
},
{
"title": "What is it about certifications anyway?",
"status": true,
"publish_date": "2020-01-29",
"slug": "what-is-it-about-certifications-anyway"
}
],
"links": {
"self": "link-value",
"first": "http://adminpanel.test/api/blogs?page=1",
"last": "http://adminpanel.test/api/blogs?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"path": "http://adminpanel.test/api/blogs",
"per_page": 15,
"to": 2,
"total": 2
}
}
the blogs array however remains undefined when I'm calling it later in populating the grid data
<BootstrapTable data={this.blogs} version="4" striped hover pagination search options={this.options}>
I get an empty table, calling console.log on blogs and this.blogs reveals it's undefined.
I'm using reactstrap and react-bootstrap-table for this grid component.
You are not accessing the state correctly to access the blogs use this.state.blogs:
<BootstrapTable data={this.state.blogs} version="4" striped hover pagination search options={this.options}>
Something weird is going on:
This is my initial state (a .js file)
import moment from 'moment';
let date = moment();
var previousDate = moment("2015-12-25");
export const projects = [
{
"id": 0,
"metadata": {
"fields":
[{
"id": 1,
"order": 1,
"name": "Name",
"value": "Collection 1"
},
{
"id": 2,
"order": 2,
"name": "Created On",
"value": date
},
{
"id": 3,
"order": 3,
"name": "Last Modified On",
"value": previousDate
},
{
"id": 4,
"order": 4,
"name": "Status",
"value": "Filed"
}],
"tags":
[{
"id": 1,
"order": 1,
"value": "tag1"
},
{
"id": 2,
"order": 2,
"value": "tag2"
},
{
"id": 3,
"order": 3,
"value": "tag3"
},
{
"id": 4,
"order": 4,
"value": "tag4"
}]
}
}
This is ProjectsList.js:
import React from 'react';
import Project from './Project';
import { projects } from 'initialState';
export default (props) => {
return(
<div className="projectsList">
{projects.map(project => (
<article key={project.id}><Project fields={project.metadata.fields} /></article>
))}
</div>
)
}
And this one's Project.js:
import React from 'react';
export default (props) => {
return(
<ul className="fields">
{props.fields.map(field => <li key={field.id}>{field.name}</li>) }
</ul>
)
}
I am trying to render a bunch of projects in a list, and every project contains a bunch of metadata key-value pairs that it shows.
So basically, the wiring does not matter, it all works fine.
Except for this:
If you look up at the initial state file (first one up there), there is an array of multiple objects in fields. Each object shows 4 key-value pairs
id
order
name
value
Now, in Project.js, the line where I go
{props.fields.map(field => <li key={field.id}>{field.name}</li>) }
looks like I can switch the {field.name} for {field.id}, to show the id in text. Or I can go {field.order}, to display the order.
But weirdly enough, if I want to show the actual value of the field, like so {field.value}, it throws.
invariant.js?4599:38
Uncaught Invariant Violation: Objects are not valid as a React child (found: Mon Jun 20 2016 21:40:33 GMT-0400). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of `StatelessComponent`.
I even went as far (sigh) as changing the string value in every fields to val, juste to make sure value wasn't some kind of a reserved word.
Still threw.
Anybody can help me understand what I have done wrong, here?
Thanks Guys.
You are assigning to variable values to the value property in your state file, which are most likely not strings, but objects:
export const projects = [{
"id": 0,
"metadata": {
"fields":
[
...
{
"id": 2,
"order": 2,
"name": "Created On",
"value": date // one
},
{
"id": 3,
"order": 3,
"name": "Last Modified On",
"value": previousDate // and another one
},
...
]
...
}
}
If typeof children returns "object" (and children is neither an array, nor a ReactElement), it throws:
https://github.com/facebook/react/blob/dc6fc8cc0726458a14f0544a30514af208d0098b/src/shared/utils/traverseAllChildren.js#L169
Here's a simplest example to demonstrate this:
const IllegalComponent = () => <span>{{}}</span>
You are supposed to supply a string (or number) so that React could inline that as the children in <li>. Children should be something that's renderable and implements ReactNode.
If the children is an object, React would not know how to render it. You should explicitly convert the value to String.
Try this to see if it works:
{props.fields.map(field => <li key={field.id}>{field.value.toString()}</li>) }