How can I model data for a datable? - javascript

I have a datatable where I am using a framework.
For now I am only mocking data because I don't have straight directions from my boss yet.
In the datatable docs say this:
rows:
The rows prop is where you provide us with a list of all the rows that you want to render in the table. The only hard requirement is that this is an array of objects, and that each object has a unique id field available on it.
headers:
The headers prop represents the order in which the headers should appear in the table. We expect an array of objects to be passed in, where key is the name of the key in a row object, and header is the name of the header.
The headers are going to be hardcoded:
For that I have this:
const tableHeaders = [
{
key: 'device',
header: t('cancellations.device'),
},
{
key: 'ticketNumber',
header: t('cancellations.ticketNumber'),
},
{
key: 'itemsCancelled',
header: t('cancellations.itemsCancelled'),
},
{
key: 'requestDate',
header: t('cancellations.requestDate'),
},
{
key: 'status',
header: t('cancellations.status'),
},
{
key: 'requestedBy',
header: t('cancellations.requestedBy'),
},
];
And before I had this hardcoded which is what I need to model and keep it exactly as it is, not hardcoded but with real data:
const rows = [
{
id: 'a',
device: t('Device 1'),
ticketNumber: t('Ticket Number'),
itemsCancelled: t('Items Cancelled'),
requestDate: t('Request Date'),
status: t('Status'),
requestedBy: t('Requested By'),
},
{
id: 'b',
device: t('Device 2'),
ticketNumber: t('Ticket Number'),
itemsCancelled: t('Items Cancelled'),
requestDate: t('Request Date'),
status: t('Status'),
requestedBy: t('Requested By'),
},
{
id: 'c',
device: t('Device 3'),
ticketNumber: t('Ticket Number'),
itemsCancelled: t('Items Cancelled'),
requestDate: t('Request Date'),
status: t('Status'),
requestedBy: t('Requested By'),
}
];
And the real data comes like this:
"CancellationRequests": [
{
"accountId": 232279,
"billingCancelReasonId": null,
"createDate": "2018-09-18T11:28:47-07:00",
"id": 17195077,
"modifyDate": "2018-09-18T11:28:48-07:00",
"notes": null,
"statusId": 2,
"ticketId": 65626859,
"account": null,
"items": null,
"status": null,
"ticket": null,
"user": null,
"itemCount": null,
"__typename": "SoftLayer_Billing_Item_Cancellation_Request"
},
{
"accountId": 232279,
"billingCancelReasonId": null,
"createDate": "2018-09-10T11:11:05-07:00",
"id": 17183859,
"modifyDate": "2018-09-10T11:11:06-07:00",
"notes": null,
"statusId": 2,
"ticketId": 65169379,
"account": null,
"items": null,
"status": null,
"ticket": null,
"user": null,
"itemCount": null,
"__typename": "SoftLayer_Billing_Item_Cancellation_Request"
}
]
So, comparing the real data with the hardcoded rows, it should match like this:
id: row.id,
device: row.account,
ticketNumber: row..ticketId,
itemsCancelled: row.itemCount,
requestDate: row.createDate
status: row.status,
requestedBy: row.user,
I am getting the values like this:
data.SoftLayerCancellationRequests.map(item => item);
But I don't know how to assign them to the proper key: value in a new object.
PS: I am using Reactjs.
Library use for components: http://react.carbondesignsystem.com/?selectedKind=DataTable&selectedStory=with%20expansion&full=0&addons=1&stories=1&panelRight=0&addonPanel=REACT_STORYBOOK%2Freadme%2Fpanel

You have already done all the hard work. It's just a matter of creating a new mapped array using your key matching already shown in your question
const rows = APIArray.map(row => {
return {
id: row.id,
device: row.account,
ticketNumber: row.ticketId,
itemsCancelled: row.itemCount,
requestDate: row.createDate
status: row.status,
requestedBy: row.user
}
})

Related

Get data from RichSnippet JSON and set the same string into other variable

I have this JSON generated from external (Reviews-io) script:
https://widget.reviews.co.uk/rich-snippet/dist.js
richSnippet({
store: "www.storedigital.local",
sku:"6647;6647_5;6647_4;6647_3;6647_11;6647_10;6647_2;6647_1;6647_9;6647_8;6647_7;6647_6",
data:{
"url": "store.stg.gsd.local/1/silla-replica-eames.html",
"description": ``,
"mpn": "6647",
"offers" :[{
"#type":"Offer",
"availability": "http://schema.org/InStock",
"price": "559",
"priceCurrency": "MXN",
"url": "https://store.stg.gsd.localx/1/silla-replica-eames.html",
"priceValidUntil": "2022-05-26",
}],
"brand": {
"#type": "Brand",
"name": "Not Available",
}
}
})
I need to get all the string of numbers in "sku", and then put them in another variable as same format (6647; 6647_1; 6647_2)
I try to get the numbers using this JS but doesn't works
var skucollection = JSON.parse(richSnippet, function (key, value) {
if (key == "sku") {
return new Sku(value);
} else {
return value;
}
});
Can you help me check what I am doing wrong, to get this sku's value string, please?
JSON.parse is not too much? ,handle it as it is internally (a JSON indeed)
var richSnippet = {
store: 'www.storedigital.local',
sku: '6647;6647_5;6647_4;6647_3;6647_11;6647_10;6647_2;6647_1;6647_9;6647_8;6647_7;6647_6',
algomas: [],
data: {
url: 'store.stg.gsd.local/1/silla-replica-eames.html',
description: ``,
mpn: '6647',
offers: [
{
'#type': 'Offer',
availability: 'http://schema.org/InStock',
price: '559',
priceCurrency: 'MXN',
url: 'https://store.stg.gsd.localx/1/silla-replica-eames.html',
priceValidUntil: '2022-05-26',
},
],
brand: {
'#type': 'Brand',
name: 'Not Available',
},
},
};
var test;
Object.keys(richSnippet).forEach((key) => {
if (key == 'sku') {
test = richSnippet[key];
}
});
console.log('test', test);

How to patch a reactive form with multi nested json values

I am using the value of a multi nested (Infinity level) reactive form which contains formArray, formGroups and formControls. Which is stored in DB.
Currently, I am patching the form using a recursion function that loops through the entire JSON and makes formArrays, formGroups and formControls based on keys and values.
Now the issue is, this method which I am using is not good as per performance perspective, so is there any better way to patch this kind of multi nested form in one go? (Just create form, no need to show in HTML)
This is simplified JSON for question reference -
Any section can have subSections and then subSections can have some kind of section
const formDataSections = [
{
index: 1,
sectionName: "",
subSections: [
{
index: 1,
subSectionName: "",
sections: [
{
index: null,
sectionName: "",
subSections: [
{
index: null,
subSectionName: "",
sections: [
{
index: null,
sectionName: "",
},
{
index: null,
sectionName: "",
subSections: [
{
index: null,
subSectionName: "",
sections: [
{
index: null,
sectionName: "",
},
{
index: null,
sectionName: "",
subSections: [],
},
],
},
],
},
],
},
],
},
{
index: null,
sectionName: "",
subSections: [
{
index: null,
contentTypes: [],
sections: [
{
index: null,
sectionName: "",
subSections: [],
},
],
},
],
},
],
},
],
},
];
You could create a custom "subform" component using ControlValueAccessor (docs) and call the component recursively (example)
I don't think you can avoid recursion since the list has potentially infinite length
Here's a (not fully working...) StackBlitz example, just to showcase what I'm talking about.

how to append object array to current state in react functional component

this is my state
const [dataItem, setDataItem] = useState({
id: null,
code: null,
title: null,
prent: null,
unitId: null,
});
and i want append file to dataItem state
let file = [
{
uid: '1',
name: items.file,
status: 'done',
},
];
setDataItem({ ...dataItem, file });
but it instead of append to dataItem , it replaced and other elements(e.g id, code, title) will be null
dataItem state after append file
{
"id": null,
"code": null,
"title": null,
"prent": null,
"unitId": null,
"file":[{
"uid": "1",
"name": "u104.svg",
"status": "done"
}]
}
Because the state was initialized to an object instead of an array. It should be
const [dataItem, setDataItem] = useState([{
id: null,
code: null,
title: null,
prent: null,
unitId: null,
}]);
When update dataItem, you have to spread array file too
setDataItem({ ...dataItem, ...file });
Read more =>
Correct modification of state arrays in ReactJS
To append file keeping the previous state intact, you'll need to use functional updates.
let file = [
{
uid: '1',
name: items.file,
status: 'done',
},
];
setDataItem(prevState => ({ ...prevState, file }));

Pushing to array doesn't trigger vue's reactivity

I already know that editing object within an array doesn't work for vue.js due to its limited capability and base on what I read using vue.set should solve this problem easily but I am having a hard time making it work.
this is my sample data. The parent object is called resource and inside resource there are power_generator_groups , inside the power_generator_groups are power_generators.
{
"id": 5,
"bg_member_id": 1,
"code": "G0633",
"name": "namex1",
"power_generator_groups": [
{
"id": 1,
"resource_id": 5,
"code": "GC033",
"power_generators": [
{
"id": 1,
"power_generator_group_id": 1,
"code": "XXXXX",
"name": "test",
"contract_number": "00000003",
"supply_max": 1000,
},
{
"id": 2,
"power_generator_group_id": 1,
"code": "XXXXX",
"name": "test",
"contract_number": "00000003",
"supply_max": 1000,
},
{
"id": 3,
"power_generator_group_id": 1,
"code": "XXXXX",
"name": "test",
"contract_number": "00000003",
"supply_max": 1000,
}
]
},
{
"id": 2,
"resource_id": 5,
"code": "GC033",
"contract_number": "065C001",
"power_generators": [
{
"id": 4,
"power_generator_group_id": 2,
"code": "XXXXX",
"name": "test",
"contract_number": "00000003",
"supply_max": 1000,
}
]
}
]
}
and this is my vue file
<template lang="pug">
.wrapper
.animated.fadeIn
b-container(fluid='')
b-row.my-1
b-col(sm='3')
label(:for='`type-key`') companyName
b-col(sm='9')
b-form-select(v-model='item.bg_member_id' :options="companyList")
b-col(sm='3')
label(:for='`type-key`') code
b-col(sm='9')
b-form-input(v-model='item.code')
b-button(size='sm', #click='addPowerGeneratorGroup', variant="primary")
| Add power_generator_group
template(v-for='(group, group_index) in item.power_generator_groups')
b-card(
header-tag="header"
footer-tag="footer"
)
div(slot="header")
i.fa.fa-align-justify
strong power_generator_groups
button.btn.btn-default.btn-sm(type='button' #click='deletePowerGeneratorGroup(group_index)')
span.fa.fa-trash-o
div
b-row.my-1
b-col(sm='3')
label(:for='`type-key`')
| code
b-col(sm='9')
b-form-input(v-model='group.code')
b-col(sm='3')
label(:for='`type-key`') group name
b-col(sm='9')
b-form-input(v-model='group.name')
b-col(sm='3')
label(:for='`type-key`') contract number
b-col(sm='9')
b-form-input(v-model='group.contract_number')
b-container.bv-example-row(fluid='')
b-button(size='sm', #click='addPowerGenerator(group_index)', variant="primary")
| add power_generator
b-card(
header-tag="header"
footer-tag="footer"
)
div(slot="header")
i.fa.fa-align-justify
strong power_generators
b-table(small v-bind:item="group.power_generators" v-bind:fields="fields" fixed responsive)
template(v-for="field in fields" :slot="field.key" slot-scope="contract")
template(v-if="field.key == 'actions'")
b-button(size='sm', #click='deletePowerGenerator(group_index, contract.index)', variant="primary")
| Del
template(v-else)
b-form-input(:type='types[field.key]' v-model = 'contract.item[field.key]')
b-button(size='sm', #click='save', variant="primary")
| Save
</template>
<script>
import Vue from 'vue';
export default {
props: {
item: {
type: Object,
required: true,
default: () => {
}
},
companyList: Array
},
data() {
return {
companyId: null,
code: null,
name: null,
contract_number: null,
fields: [
{key: 'actions', label: '' },
{key: 'code', label: 'code', sortable: true, sortDirection: 'desc'},
{key: 'name', label: 'name', sortable: true, class: 'text-center'},
{key: 'contract_number', label: 'contractNo'},
{key: 'supply_max', label: 'maxunit'}
],
types: {
code: 'text',
name: 'text',
contract_number: 'text',
supply_max: 'number'
},
items:
{}
}
},
mounted() {
},
computed: {},
methods: {
addPowerGenerator(index) {
console.log(index)
console.log(this.item)
const pgg = this.item.power_generator_groups[index];
const pgs = pgg.power_generators || Vue.set(pgg, 'power_generators', []);
pgs.push(
{
"code": "",
"name": "",
"contract_number": "",
"supply_max": "",
}
)
},
addPowerGeneratorGroup() {
const pggs = this.item.power_generator_groups || Vue.set(this.item, 'power_generator_groups', []);
pggs.push(
{
"resource_id": this.item.id,
"name": "",
"code": "",
"contract_number": "",
"power_generators": []
}
)
},
deletePowerGenerator(group_index, field_index) {
this.item.power_generator_groups[group_index].power_generators.splice(field_index, 1);
},
deletePowerGeneratorGroup(group_index) {
this.item.power_generator_groups.splice(group_index, 1);
},
save: function () {
this.$parent.save(this.item)
}
}
}
</script>
You'll need Vue.set only if you have power_generator_groups that have no power_generators property, since Vue can't detect when you add it otherwise.
Assuming there are no problems with your template (you didn't show it), change your addPowerGenerator method:
addPowerGenerator(index) {
console.log(index)
console.log(this.item)
const pgg = this.item.power_generator_groups[index];
const pgs = pgg.power_generators || Vue.set(pgg, 'power_generators', []);
pgs.push(
{
"code": "",
"name": "",
"contract_number": "",
"supply_max": "",
}
)
}
Vue.set returns the property you just created which is how pgs contains the proper reference in that case.
Do the same thing for the new method you edited in:
addPowerGeneratorGroup() {
const pggs = this.item.power_generator_groups || Vue.set(this.item, 'power_generator_groups', []);
pggs.push(
{
"resource_id": this.item.id,
"name": "",
"code": "",
"contract_number": "",
"power_generators": []
}
)
}
You can see a mockup here where I've assumed this.item refers to the resource itself. I included a 3rd group which has no power_generators property for testing.

react count object properties in an array

I am fetching data by an API. It is a movie, tv show, person database. When I search a word in the search box, it returns the related movie, tv show and person names in objects nested in an array. for example when I search "fight":
[
0:{original_name: "쌈 마이웨이", id: 70813, media_type: "tv", name: "Fight My Way", vote_count: 5,…}
1:{vote_average: 8.2, vote_count: 8057, id: 550, video: false, media_type: "movie", title: "Fight Club",…}
2:{vote_average: 6.1, vote_count: 215, id: 345922, video: false, media_type: "movie",…}
3:{original_name: "Fight", id: 46554, media_type: "tv", name: "Fight", vote_count: 0, vote_average: 0,…}
4:{original_name: "The Good Fight", id: 69158, media_type: "tv", name: "The Good Fight", vote_count: 22,…}
5:{vote_average: 0, vote_count: 0, id: 158301, video: false, media_type: "movie", title: "Fight",…}
]
there are more results but I cut them. As you can see there are media_type properties in each object. there are 3 media types as you can understand (movie, tv, person). I want to count each type.
actually; I want the same thing in the link I guess: React: Syntax for calling setState in Switch Return
but it doesn't work for me. I tried to change simply the state of movieCount to 3 like this:
countType() {
this.props.movies.map(movie => {
return() => {
if(movie.media_type === 'movie') {
this.setState({ movieCount: 3});
console.log(this.state);
}
}
});
}
but it doesn't work too.and I researched on the internet this stuff in javascript documentation and forums. not about just react. but I couldn't do anything. I know it's simple.
so how can I count objects in an array according to their property types?
Assuming that the data you fetched from API is stored in data variable, you can try the following code to find the count of movie media type in your data array:
const movies = data.filter(item => item.media_type === 'movie'));
const moviesCount = movies.length;
You can also dynamically calculate count of every media_type in your data array:
const mediaTypes = data
.map(dataItem => dataItem.media_type) // get all media types
.filter((mediaType, index, array) => array.indexOf(mediaType) === index); // filter out duplicates
const counts = mediaTypes
.map(mediaType => ({
type: mediaType,
count: data.filter(item => item.media_type === mediaType).length
}));
Then counts will be something like this:
[
{
"type": "tv",
"count": 3
},
{
"type": "movie",
"count": 3
}
]
ok i found the solition. thank you to poohitan for answer. i solved it
through his answer.
countType(type) {
const countTypes = this.props.movies.filter(movie => movie.media_type === type);
return countTypes.length;
}
and while i am rendering my tv results, i just call the method above with type. for example:
return (
<div>
movie count: {this.countType('movie')}
tv show count: {this.countType('tv')}
</div>
);
var data = [
{ original_name: "쌈 마이웨이", id: 70813, media_type: "tv", name: "Fight My Way", vote_count: 5 },
{ vote_average: 8.2, vote_count: 8057, id: 550, video: false, media_type: "movie", title: "Fight Club" },
{ vote_average: 6.1, vote_count: 215, id: 345922, video: false, media_type: "movie" },
{ original_name: "Fight", id: 46554, media_type: "tv", name: "Fight", vote_count: 0, vote_average: 0 },
{ original_name: "The Good Fight", id: 69158, media_type: "tv", name: "The Good Fight", vote_count: 22 },
{ vote_average: 0, vote_count: 0, id: 158301, video: false, media_type: "movie", title: "Fight" },
]
this.types = {};
data.forEach((d) => {
if (!this.types[d["media_type"]]) {
this.types[d["media_type"]] = 1;
} else {
this.types[d["media_type"]] += 1;
}
})
console.log(this.types);
// you will get answer { tv: 3, movie: 3 }
Here's one possible way:
render() {
let countTypes = ' '
return ({
list.length > 0
?
<span> {countTypes = (list.filter(moviesFilter =>
moviesFilter.type.id === this.props.typeId)).length}
</span>
:
<DisplayMessage message="0" />
})
}

Categories