Change all keys in array also deeper inside object with array - arrays

Currently for our navigation structure we have the following array:
{
childNodes: [
{title: "Mijn afdeling", type: "Department", relativeUri: "/mijnafdeling"},
{title: "contact", type: "Department", relativeUri: "/contact"}
]
RelativeUri: '/',
title: 'test'
},
{
childNodes: null
RelativeUri: '/',
title: 'test'
}
]
Now I want to change all the 'childNodes' keys to 'child' and also all the relativeUri keys to href.
My desired result should be
{
child: [
{title: "Mijn afdeling", type: "Department", href: "/mijnafdeling"},
{title: "contact", type: "Department", href: "/contact"}
]
href: '/',
title: 'test'
},
{
child: null
href: '/',
title: 'test'
}
]
I know that I can do something like this.navigationArray = this.navigationArray.map(({ childNodes, relativeUri }) => ({ childNodes: child, href: relativeUri })) However I don't know how to get all the keys in the array under the childNodes object too. So it basically needs to 'find' or loop over all the objects inside the array, and find the specic keys. Also a 'childNodes' object can be null.
For different pages I have a different number of navigation items, so I rather don't target a specific index as that can mess up the navigation.
Thanks a lot!

This should do it:
const nu = orig
.map(
({
childNodes,
RelativeUri,
title
}) => ({
child: childNodes ?
childNodes.map(({
title,
type,
relativeUri
}) => ({
title,
type,
href: relativeUri
})) : childNodes,
href: RelativeUri,
title
}));
console.log(nu);
DEMO
const orig = [
{
childNodes: [{
title: "Mijn afdeling",
type: "Department",
relativeUri: "/mijnafdeling"
},
{
title: "contact",
type: "Department",
relativeUri: "/contact"
}
],
RelativeUri: '/',
title: 'test'
},
{
childNodes: null,
RelativeUri: '/',
title: 'test'
}
];
//console.log( orig );
const nu = orig
.map(({childNodes,RelativeUri,title}) => ({child: childNodes ? childNodes.map(({title,type,relativeUri}) => ({title,type,href:relativeUri})) : childNodes, href:RelativeUri, title}));
console.log( nu );

Related

How to create an Option Group in Antd Design?

I'm trying to implement a categories input with this data returned from my DB
[
{
_id: '63e59f91bd2a21368188ff4b',
title: 'Uncategorized',
slug: 'uncategorized',
categoryType: 'blog',
createdAt: '2023-02-10T01:36:17.704Z',
updatedAt: '2023-02-10T01:36:17.704Z',
},
{
_id: '63e5984028745af5bad2c015',
parentCategory: {
_id: '63e5974a786719dd4bb2d37b',
title: 'Projects',
},
title: 'YTDownloader',
slug: 'ytdownloader',
categoryType: 'blog',
createdAt: '2023-02-10T01:05:04.919Z',
updatedAt: '2023-02-10T01:05:04.919Z',
},
{
_id: '63e597c3786719dd4bb2d387',
parentCategory: {
_id: '63e5974a786719dd4bb2d37b',
title: 'Projects',
},
title: 'Song Finder',
slug: 'song-finder',
categoryType: 'blog',
createdAt: '2023-02-10T01:02:59.742Z',
updatedAt: '2023-02-10T01:02:59.742Z',
},
]
What I'm trying is to create the example given in the documentation since my categories are pretty much 'parents' or 'childrens' and don't want to have them unorganized.
So far this is what I've been trying but to not success:
<Select
placeholder="Select category"
defaultValue={category}
onChange={(e) => {
setObjectData({
...objectData,
category: e,
})
}}
value={category}
options={[
categories.map((c, i) => [
{
label: c.parentCategory ? c.parentCategory.title : c.title,
},
]),
]}
/>
This returns literally nothing, not even an error. What I was expecting is the following:
<Select
defaultValue={category}
onChange={(e) => {
setObjectData({
...objectData,
category: e,
})
}}
value={category}
options={[
{
label: 'Projects',
options: [
{
label: 'YTDownloader',
value: '63e5984028745af5bad2c015',
},
{
label: 'Song Finder',
value: '63e597c3786719dd4bb2d387',
},
],
},
{
label: 'Uncategorized',
value: '63e59f91bd2a21368188ff4b'
],
},
]}
/>
Has anyone done something like this before? It will be great if you guys can help me solve this little issue that's been giving a headache for the last 2 hours, LOL
My guess would be you have only passed objects to options that only have a label and no value. This is speculation, but it's possible nothing is rendered in the dropdown if there is no corresponding value to each label.
The label, which is what the user sees for each option, isn't necessarily its underlying value.
Keep in mind the value is ultimately the thing that will be passed to onChange, so to only have a label with no value could explain why it just does nothing -- because a valid option must have a value.
Map each option such that its value represents that option uniquely:
categories.map((c, i) => [
{
label: c.parentCategory ? c.parentCategory.title : c.title,
value: c._Id
},
]),

How to fetch item from array (first image in an array of images) from SanityClient?

I have a group of sets, I want to show an image from each set on my webpage which users can use as a link to their respective galleries. So I want to fetch an item (an image) from an array of images. I don't have a specific image picked for each category, so I would just be getting the first image within its array of images to use. I am getting this error: description: "expected '}' following object body"
import React, { useState, useEffect } from 'react';
import { client, urlFor } from '../lib/client';
import { Header, Footer } from '../components';
import Link from 'next/link';
const gallery = () => {
const [ galleryData, setGalleryData ] = useState(null);
useEffect(() => {
client.fetch(
`*[_type == 'set']{
set_name,
set_images[]->{
image{->asset{
_id,
url
}}
}
}`
).then((data) => setGalleryData(data))
.catch(err => console.error(err))
})
return (
<div>
<Header />
<main className="main-gallery">
<div className="title">
<div className="title-line-left"></div>
<h2>gallery</h2>
<div className="title-line-right"></div>
</div>
<div className="categories">
<ul className="categories-container">
{galleryData && galleryData.map((set, index) => (
<li key={index}>
<Link href="/sets"><img src={urlFor(set.set_images.image[0]).auto('format').url()} alt={set.set_name}/></Link>
</li>
))}
</ul>
</div>
</main>
<Footer />
</div>
)
}
This is my sanity schema:
export default {
name: 'set',
type: 'document',
title: 'Set',
fields: [
{
name: 'set_name',
type: 'string',
title: 'Set Name',
},
{
name: 'set_images',
type: 'array',
title: 'Set Images',
of: [
{
name: 'image',
type: 'image',
title: 'Image',
options: {
hotspot: true,
},
fields: [
{
name: 'alt',
type: 'string',
title: 'Alternative Text',
options: {
isHighlighted: true
}
},
{
name: 'name',
type: 'string',
title: 'Name',
options: {
isHighlighted: true
}
},
{
name: 'date',
type: 'string',
title: 'Date',
options: {
isHighlighted: true
}
},
{
name: 'size',
type: 'string',
title: 'Size',
options: {
isHighlighted: true
}
},
{
name: 'materials',
type: 'string',
title: 'Materials',
options: {
isHighlighted: true
}
},
]
},
]
},
{
name: 'slug',
title: 'Slug',
type: 'slug',
options: {
source: 'set_name'
}
}
]
}
This fixed it:
useEffect(() => {
client.fetch(
`*[_type == 'set']{
set_name,
'setSelect' : set_images[0].asset->{_id,url}}`
).then((data) => setGalleryData(data))
.catch(err => console.error(err))
})
and then {set.setSelect}

Getting error of undefined when fetching data from sanity.io in next.js

I'm pretty new to the headless cms of sanity.io. As I'm trying to fetch my data im getting this error but couldn't figure out why or where the problem could be exactly.
Anybody some ideas?
Error: Error serializing .images returned from getServerSideProps in "/company/[slug]".
Reason: undefined cannot be serialized as JSON. Please use null or omit this value.
//the slug file
export const Company = ({ title, slug, logo, images, currency, categories, body, url, location }) => {
console.log(title, slug, logo, images, currency, categories, body, url, location )
return <>Content</>
};
export const getServerSideProps = async pageContext => {
const pageSlug = pageContext.query.slug;
if (!pageSlug) {
return {
notFound: true
}
}
const query = encodeURIComponent(`*[ _type == "company" && slug.current == "${pageSlug}" ]`);
const url = `https://op5ktqwm.api.sanity.io/v1/data/query/production?query=${query}`;
const result = await fetch(url).then(res => res.json());
const post = result.result[0];
if (!post) {
return {
notFound: true
}
} else {
return {
props: {
title: post.title,
slug: post.slug,
logo: post.logo,
images: post.images,
currency: post.currency,
categories: post.categories,
body: post.body,
url: post.url,
location: post.location
}
}
}
}
export default Company;
//backend code structure
export default {
name: 'company',
title: 'Company',
type: 'document',
fields: [
{
name: 'title',
title: 'Title',
type: 'string',
},
{
name: 'slug',
title: 'Slug',
type: 'slug',
options: {
source: 'title',
maxLength: 96,
},
},
{
name: 'logo',
title: 'Logo',
type: 'image',
},
{
name: 'images',
title: 'Images',
type: 'array',
of: [{type: 'companyImage'}]
},
{
name: 'currency',
title: 'Currency',
type: 'array',
of: [
{
type: 'reference',
to: {type: 'currency'},
},
],
},
{
name: 'categories',
title: 'Categories',
type: 'array',
of: [
{
type: 'reference',
to: {type: 'category'},
},
],
},
{
name: 'body',
title: 'Body',
type: 'localeBlockContent',
},
{
name: 'url',
title: 'URL',
type: 'string',
},
{
name: 'location',
title: 'Location',
type: 'geopoint',
},
],
preview: {
select: {
title: 'title',
manufactor: 'manufactor.title',
media: 'defaultProductVariant.images[0]',
},
},
}

Using props in functional component

I am getting array in props which is props.logsInfo.logs and I want to use it according to the number of elements in array instead of hard coding it like props.logsInfo.logs[0]['id']. I want to use map.Logs array size can be more than one.I don't want to write one more cells: [
{ key: 'cell-0', children: props.logsInfo.logs[1]['id'] },How can i achieve it??
import React from 'react';
import Table from 'terra-table';
const StripedTable = props => (
<Table
summaryId="striped-table"
summary="This table displays striped rows."
numberOfColumns={4}
dividerStyle="horizontal"
headerData={{
cells: [
{ id: 'header-Id', key: 'id', children: 'Id' },
{ id: 'header-vendorId', key: 'vendorId', children: 'VendorId' },
{ id: 'header-userId', key: 'userId', children: 'UserId' },
{ id: 'header-payLoad', key: 'payLoad', children: 'PayLoad' },
],
}}
bodyData={[
{
rows: [
{
key: 'row-0',
cells: [
{ key: 'cell-0', children: props.logsInfo.logs[0]['id'] },
{ key: 'cell-1', children: props.logsInfo.logs[0]['vendorId'] },
{ key: 'cell-2', children: props.logsInfo.logs[0]['userId'] },
{ key: 'cell-3', children: props.logsInfo.logs[0]['payLoad']},
],
},
],
},
]}
/>
);
export default StripedTable;
Yes, you can use .map:
bodyData={[
{
rows: props.logsInfo.logs.map(log => ({
key: log.id,
cells: [
{ key: 'cell-0', children: log.id },
{ key: 'cell-1', children: log.vendorId },
{ key: 'cell-2', children: log.userId },
{ key: 'cell-3', children: log.payLoad},
],
}),
},
]}
You can also do the same for cells if you keep an array with the field names around:
const fields = ['id', 'vendorId', 'userId', 'payLoad'];
// ...
bodyData={[
{
rows: props.logsInfo.logs.map(log => ({
key: log.id,
cells: fields.map(field => ({key: field, children: log[field]})),
}),
},
]}

Filter Array based on a property in the array of its objects

Given is following data structure
const list = [
{
title: 'Section One',
data: [
{
title: 'Ay',
},
{
title: 'Bx',
},
{
title: 'By',
},
{
title: 'Cx',
},
],
},
{
title: 'Section Two',
data: [
{
title: 'Ay',
},
{
title: 'Bx',
},
{
title: 'By',
},
{
title: 'Cx',
},
],
},
];
What i want to do ist to filter this list based on title property in the data array of each object.
An example would be to have the list where the title property of the childs starts with "B", so the list will look like that:
const filteredList = [
{
title: 'Section One',
data: [
{
title: 'Bx',
},
{
title: 'By',
}
],
},
{
title: 'Section Two',
data: [
{
title: 'Bx',
},
{
title: 'By',
}
],
},
];
What i tried so far was something like that:
const items = list.filter(item =>
item.data.find(x => x.title.startsWith('A')),
);
or
const filtered = list.filter(childList => {
childList.data.filter(item => {
if (item.title.startsWith('B')) {
return item;
}
return childList;
});
});
But i think i am missing a major point here, maybe some of you could give me a tip or hint what i am doing wrong
Best regards
Your issue is that you're doing .filter() on list. This will either keep or remove your objects in list. However, in your case, you want to keep all objects in list and instead map them to a new object. To do this you can use .map(). This way you can map your objects in your list array to new objects which contain filtered data arrays. Here's an example of how you might do it:
const list=[{title:"Section One",data:[{title:"Ay"},{title:"Bx"},{title:"By"},{title:"Cx"}]},{title:"Section Two",data:[{title:"Ay"},{title:"Bx"},{title:"By"},{title:"Cx"}]}];
const filterByTitle = (search, arr) =>
arr.map(
({data, ...rest}) => ({
...rest,
data: data.filter(({title}) => title.startsWith(search))
})
);
console.log(filterByTitle('B', list));

Resources