Apex Line Area chart is not getting displayed on the page in Vuejs - vue.js

I am stuck on a page where i am not able to display the charts on the page.
To make it simplify what I have done is, here is the code sandbox:
I see there an error in console about the data, I am not sure about it.
https://codesandbox.io/s/compassionate-snyder-bckoq
I want to display the chart like this (as an example), but I am not able to display on the code sandbox
Please help.

The format of series is not aligned with ApexCharts.
You need to transform the data to match with ApexChart format.
Please see the changes in the codesandbox.
https://codesandbox.io/s/small-dew-eztod?file=/src/components/HelloWorld.vue
options: {
// X axis labels
xaxis: {
type: 'date',
categories: ["2021-05-04", "2021-05-05", "2021-05-07"]
},
},
series: [
{
name: "total",
data: [2, 2, 1],
},
{
name: "pending",
data: [0, 1, 0],
},
{
name: "approved",
data: [2, 1, 1],
},
{
name: "rejected",
data: [0, 0, 0],
},
],
Transform data to fit ApexChart
const data = {
"2021-05-04": {
total: 2,
pending: 0,
approved: 2,
rejected: 0,
},
"2021-05-05": {
total: 2,
pending: 1,
approved: 1,
rejected: 0,
},
"2021-05-07": {
total: 1,
pending: 0,
approved: 1,
rejected: 0,
},
};
const xaxis = {
type: "date",
categories: Object.keys(data).map((key) => key), // ['2021-05-04', '2021-05-05', '2021-05-07']
};
let statusObj = [];
for (const dataValue of Object.values(data)) { // get the values from keys '2021-05-04', '2021-05-05' ...
// loop the values, e.g. 1st loop: { total: 2, pending: 0, approved: 2, rejected: 0, }
for (const [key, value] of Object.entries(dataValue)) {
// take 'total' as example, find if statusObj already has { name: 'total', data: [x] }, e.g. statusObj = { name: 'total', data: [1] }
const existingStatusIndex = Object.keys(statusObj).find(
(sKey) => statusObj[sKey].name === key
);
// if yes, return the index of it
if (existingStatusIndex) {
// add new data value to existing data object. e.g. { name: 'total', data: [1, 2] }
statusObj[existingStatusIndex].data.push(value);
continue;
}
// if no, create a new object and add it to statusObj
statusObj.push({
name: key,
data: [value],
});
}
}
Output:
xaxis {
type: 'date',
categories: [ '2021-05-04', '2021-05-05', '2021-05-07' ]
}
statusObj [
{ name: 'total', data: [ 2, 2, 1 ] },
{ name: 'pending', data: [ 0, 1, 0 ] },
{ name: 'approved', data: [ 2, 1, 1 ] },
{ name: 'rejected', data: [ 0, 0, 0 ] }
]

Related

Ramda - how to use multiple functions on the same data structure

I am trying to use multiple ramda functions on this example:
const data = {
"tableItems": [
{
"id": 1,
"name": "1",
"startingPoint": true,
"pageNumber": 15,
"nodes": [
100,
200
]
},
{
"id": 2,
"name": "2",
"startingPoint": true,
"pageNumber": 14,
"nodes": [
300,
400
]
}
],
"nodes": [
{
"id": 100,
"tableItemId": 1,
"content": "test"
},
{
"id": 200,
"tableItemId": 1,
"content": "test"
},
{
"id": 300,
"tableItemId": 2,
"content": "test"
},
{
"id": 400,
"tableItemId": 2,
"content": "test"
}
]
}
I am trying to create new JSON which should look like this where nodes array should be filled with another ramda function:
const newJSON = [
{
"id": "chapter-1",
"name": "2",
"nodes": []
},
{
"id": "chapter-2",
"name": "1",
"nodes": []
}
]
I started with:
let chapters = [];
let chapter;
const getChapters = R.pipe(
R.path(['tableItems']),
R.sortBy(R.prop('pageNumber')),
R.map((tableItem) => {
if(tableItem.startingPoint) {
chapter = {
id: `chapter-${chapters.length+1}`,
name: tableItem.name,
nodes: []
}
chapters.push(chapter);
}
return tableItem
})
)
But how to combine getNodes which needs access to the whole scope of data?
I tried pipe but something is not working.
Example:
const getNodes = R.pipe(
R.path(['nodes']),
R.map((node) => {
console.log(node)
})
)
R.pipe(
getChapters,
getNodes
)(data)
Any help would be appreciated.
We could write something like this, using Ramda:
const {pipe, sortBy, prop, filter, map, applySpec, identity, propEq, find, __, addIndex, assoc} = R
const transform = ({tableItems, nodes}) => pipe (
filter (prop ('startingPoint')),
sortBy (prop ('pageNumber')),
map (applySpec ({
name: prop('name'),
nodes: pipe (prop('nodes'), map (pipe (propEq ('id'), find (__, nodes))), filter (Boolean))
})),
addIndex (map) ((o, i) => assoc ('id', `chapter-${i + 1}`, o))
) (tableItems)
const data = {tableItems: [{id: 1, name: "1", startingPoint: true, pageNumber: 15, nodes: [100, 200]}, {id: 2, name: "2", startingPoint: true, pageNumber: 14, nodes: [300, 400]}], nodes: [{id: 100, tableItemId: 1, content: "test"}, {id: 200, tableItemId: 1, content: "test"}, {id: 300, tableItemId: 2, content: "test"}, {id: 400, tableItemId: 2, content: "test"}]}
console .log (transform (data))
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script>
First we filter the tableItems to include only those with startingPoint of true, then we sort the result by pageNumber. Then for each, we create name and nodes elements, based on the original data and on a function that maps the node values to the element in the initial nodes property. Finally, for each one, we add the chapter-# id element using addIndex (map).
This works, and is not horrible. It would take a fair bit of work to make this entirely point-free, I believe. And I don't find it worthwhile... especially because this Ramda version doesn't add anything to a simpler vanilla implementation:
const transform = ({tableItems, nodes}) =>
tableItems
.filter (x => x .startingPoint)
.sort (({pageNumber: a}, {pageNumber: b}) => a - b)
.map (({name, nodes: ns}, i) => ({
id: `chapter-${i + 1}`,
name,
nodes: ns .map (n => nodes .find (node => node .id == n)) .filter (Boolean)
}))
const data = {tableItems: [{id: 1, name: "1", startingPoint: true, pageNumber: 15, nodes: [100, 200]}, {id: 2, name: "2", startingPoint: true, pageNumber: 14, nodes: [300, 400]}], nodes: [{id: 100, tableItemId: 1, content: "test"}, {id: 200, tableItemId: 1, content: "test"}, {id: 300, tableItemId: 2, content: "test"}, {id: 400, tableItemId: 2, content: "test"}]}
console .log (transform (data))
.as-console-wrapper {max-height: 100% !important; top: 0}
This works similarly to the above except that it assigns the id at the same time as name and nodes.
I'm a founder of Ramda and remain a big fan. But it doesn't always add anything to vanilla modern JS.
You can use a curried function. Because the pipe will always pipe the result of the previous function call into the next function. You can use R.tap if you want to step over.
However, I guess you want to have the data object and the output of the previous function call both in your getNodes function. In that case you can use a curried function, where you pass the response of the previous function as last parameter.
const getNodes = R.curryN(2, function(data, tableItemList){
console.log(tableItemList) // result of previous function call
return R.pipe(
R.path(['nodes']),
R.map((node) => {
console.log('node:', node);
})
)(data)
})
And use it like:
R.pipe(
getChapters,
getNodes(data)
)(data)
I would split the solution into two steps:
Prepare the tableItems and nodes to the required end state using R.evolve - filter, sort, and then use R.toPairs the tableItems to get an array that includes the index and the object. Group the nodes by id so you can pick the relevant nodes by id in the combine step.
Combine both properties to create the end result by mapping the new tableItems, and using R.applySpec to create the properties.
const {pipe, evolve, filter, prop, sortBy, toPairs, groupBy, map, applySpec, path, flip, pick} = R
const transform = pipe(
evolve({ // prepare
tableItems: pipe(
filter(prop('startingPoint')),
sortBy(prop('pageNumber')),
toPairs
),
nodes: groupBy(prop('id'))
}),
({ tableItems, nodes }) => // combine
map(applySpec({
id: ([i]) => `chapter-${+i + 1}`,
name: path([1, 'name']),
nodes: pipe(path([1, 'nodes']), flip(pick)(nodes)),
}))(tableItems)
)
const data = {tableItems: [{id: 1, name: "1", startingPoint: true, pageNumber: 15, nodes: [100, 200]}, {id: 2, name: "2", startingPoint: true, pageNumber: 14, nodes: [300, 400]}], nodes: [{id: 100, tableItemId: 1, content: "test"}, {id: 200, tableItemId: 1, content: "test"}, {id: 300, tableItemId: 2, content: "test"}, {id: 400, tableItemId: 2, content: "test"}]}
console.log(transform(data))
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script>

How do I perform a SQL update on a list inside one of my table rows?

I have a table with parameters as shown below.
{
id: 1,
title: 'waccos',
description: 'Making an operating system in wacc',
est_duration: 420,
exp_req: 'any',
langs: [ 1 ],
owner: 1,
members: [ 1, 2 ]
},
I want to use SQL to add a new member into the member list, but I do not know how to. The table is called testprojects. I've tried using
(update testprojects
set members = members || $1
where title is $2;', [name, title])
but I think that is wrong. Could anyone help me please?
This is the table of members so far.
[
{ id: 1, name: 'A' },
{ id: 2, name: 'K' },
{ id: 3, name: 'S' },
{ id: 5, name: 'd' },
{ id: 6, name: 'J' },
{ id: 7, name: 'E' },
{ id: 8, name: 'a' }
]

Is there a to set index of a data array within this.setState?

so lets say i have the following data
data: [
{ key: 1, id: 1, uri: "", image:false },
{ key: 2, id: 2, uri: "", image:false },
{ key: 3, id: 3, uri: "", image:false },
{ key: 4, id: 4, uri: "", image:false }
]
I want to update the uri using setState()and so far I have come up with the following using React.
`data: update(this.state.data, {1: {uri: {$set: result.uri}, image:{$set: true}}})`
however, instead of just having 1, I want to be able to pass in index, i know i can do this with if statements but im sure theres an easier and cleaner way??
You should make a copy of data, update it and then setState. For example:
copy
let newData = { ...this.state.data }
update
newData[0].uri = '';
newData[0].image = true
setState
this.setState({data: newData})

How to calculate array of numbers in vuejs

I have array. in that array there is a field name debit. I want to add all the debit on this array and find the total. I am trying to do this with reduce function. but it's adding number as character not calculating the sum of the array number. here is the code
export default {
data() {
return {
fields: {
debit: 0,
credit: 0,
type: '',
},
fields: [],
allDebit: 0,
allCredit: 0,
}
},
methods: {
newfield() {
this.fields.push({
debit: 0,
credit: 0,
type: '',
})
},
dataRemove(index) {
Vue.delete(this.fields, index);
},
calculate() {
this.allDebit = this.fields.reduce((acc, item) => acc + item.debit, 0);
}
}
}
output:
{
"fields": [
{
"debit": "4",
"credit": "2",
"type": ""
},
{
"debit": "4",
"credit": "2",
"type": ""
}
],
"allDebit": "044",
"allCredit": 0
}
fields: {
debit: 0,
credit: 0,
type: '',
},
fields: [],
You specify object fields and array in the data. You cannot have an object with two identical keys in the object literal. That is not a valid JS. I wouldn't be surprised if that was the reason.
Also, your values in output seem to all be strings. Try parseInt function in the reduce function.
convert string to number and then sum them
calculate() {
this.allDebit = this.fields.reduce((acc, item) => Number(acc) + Number(item.debit), 0);
}
Rename first fields to field, or remove it completely, I do not see where do you use it.
Parse to integer item.debit either in the accumulator or in the place where do you set it.
The possible fix:
export default {
data() {
return {
field: {
debit: 0,
credit: 0,
type: '',
},
fields: [],
allDebit: 0,
allCredit: 0,
}
},
methods: {
newfield() {
this.fields.push({
debit: 0,
credit: 0,
type: '',
})
},
dataRemove(index) {
Vue.delete(this.fields, index);
},
calculate() {
this.allDebit = this.fields.reduce((acc, item) => acc + parseInt(item.debit), 0);
}
}
}
export default {
data() {
return {
fields: { // this is identical to the fields: [] array
// you need to rename it to something like field (Singular)
debit: 0,
credit: 0,
type: '',
},
// maybe you ment
field: { // field (Singular)
debit: 0,
credit: 0,
type: '',
},
//
fields: [], // THIS !!!
allDebit: 0,
allCredit: 0,
}
},
methods: {
newfield() {
this.fields.push({
debit: 0,
credit: 0,
type: '',
})
},
calculate() {
const { debit } = this.fields.reduce((acc, item) => {
return { debit: acc.debit + item.debit };
}, { debit: 0 })
this.allDebit = debit;
}
}
}
You can't have 2 identical keys in the data function property.
I would do this in a computed property instead, so that the value is calculated again if fields changes.
computed: {
allDebit() {
return this.fields.reduce((acc, item) => acc + parseInt(item.debit), 0);
}
}
EDIT: You can't have two properties with the same key in your data function. You have fields two times.

LokiJS: insert existing value for index doesn't error - how to make unique indices?

if I try to override an existing indexed field, I do not get an error.
It should error, because it is not update()!
var loki = require('lokijs');
var db = new loki('test.json');
var users = db.addCollection('users', { indices: ['userID']});
users.insert(
{
'name': 'Anna',
'userID': 1
},
{
'name': 'Bernd',
'userID': 2
},
{
'name': 'Christa',
'userID': 3
});
db.save();
users.insert({'name': 'Dieter','userID': 2}); // this should error!!
How can I make an unique index to get an error when trying to inset an existing userID ?
the indices option creates an index on the field, which allows for faster retrieval because the index lives in a separate sorted array within the collection (so Loki can use binary-search instead of a full loop to fetch records). However, you're looking for a unique index, which is created with ensureUniqueIndex (check here, scroll down to Finding Documents, there's a section on unique indexes.). With that, you can use the collection method by(field, value) (which can even be curried if you only pass the field value), which uses the unique index to full potential (about 2x the speed of an indexed field). Remember that you need to explicitly call ensureUniqueIndex because unique indexes cannot be serialized and persisted.
update: once the ensureUniqueIndex method is called, the collection will throw an error if you try to insert a duplicate key record. If you have repository checked out you can take a look at spec/generic/unique.spec.js for an example ( here )
var loki = require('lokijs');
var db = new loki('test.json');
var users = db.addCollection('users', { indices: ['userID']});
users.ensureUniqueIndex('userID');
users.on('error',function(obj){
console.log('error ... adding 1 to userID');
obj.userID = obj.userID+1;
return obj;
});
users.insert(
{
'name': 'Anna',
'userID': 1
});
users.insert(
{
'name': 'Bernd',
'userID': 2
});
users.insert(
{
'name': 'Christa',
'userID': 3
});
db.save();
console.log(users.data);
try {
users.insert({'name': 'Dieter','userID': 2}); // this should error!!
} catch(e){
var i = 2+1;
users.insert({'name': 'Dieter','userID': i}); // this should error!!
}
db.save();
db2 = new loki('test.json');
db2.loadDatabase({}, function () {
var users2 = db2.getCollection('users')
console.log(users2.data);
});
Either users.on('error',...) nor try{ users.insert...} catch(e){// id+1} handles the thrown error
That's my console:
[ { name: 'Anna',
userID: 1,
meta: { revision: 0, created: 1436186694342, version: 0 },
'$loki': 1 },
{ name: 'Bernd',
userID: 2,
meta: { revision: 0, created: 1436186694342, version: 0 },
'$loki': 2 },
{ name: 'Christa',
userID: 3,
meta: { revision: 0, created: 1436186694342, version: 0 },
'$loki': 3 } ]
Duplicate key for property userID: 2
[ { name: 'Anna',
userID: 1,
meta: { revision: 0, created: 1436186694342, version: 0 },
'$loki': 1 },
{ name: 'Bernd',
userID: 2,
meta: { revision: 0, created: 1436186694342, version: 0 },
'$loki': 2 },
{ name: 'Christa',
userID: 3,
meta: { revision: 0, created: 1436186694342, version: 0 },
'$loki': 3 },
{ name: 'Dieter',
userID: 2,
meta: { revision: 0, created: 0, version: 0 },
'$loki': 4 } ]