I'm trying to make getter in vuex store with flat data from google dosc api. All what I need is to take textRun content and keep this in array (because there will be few messages). Now I hardcoded this response in state like:
state: {
googleResponse: [
{
"body": {
"content": [
{
"endIndex": 75,
"paragraph": {
"elements": [
{
"endIndex": 75,
"startIndex": 1,
"textRun": {
"content": "This is an ordinary paragraph. It is the first paragraph of the document",
"textStyle": {}
}
}
],
"paragraphStyle": {
"direction": "LEFT_TO_RIGHT",
"namedStyleType": "NORMAL_TEXT"
}
},
"startIndex": 1
},
{
"endIndex": 102,
"paragraph": {
"elements": [
{
"endIndex": 102,
"startIndex": 75,
"textRun": {
"content": "Here's a level one heading",
"textStyle": {}
}
}
],
"paragraphStyle": {
"direction": "LEFT_TO_RIGHT",
"headingId": "h.o1fkftgl5zwf",
"namedStyleType": "HEADING_1"
}
},
"startIndex": 75
},
]
}
}
],
}
and after that I make a getter message and used map from lodash:
message: (state) => {
let message = '';
map(state.googleResponse, (element) => ({
content: map(element.body.content, (content) => {
map(content.paragraph.elements, (obj) => {
message += get(obj, 'textRun', '')
})
})
}))
}
But when I'm checking message in vuex it says is undefined... I want to have array with textRun objects. Where might be the problem ?
i am wondering whether you can get the message keep in Array by this way?
you can write like this may your want
let messageArray = state.googleResponse.map(
item => item.body.content.map(
itemCotent => itemCotent.paragraph.elements.map(
itemElements => itemElements.textRun.content)))
You need to return themessage variable in your getter.
Related
The issue I'm having is difficult to explain but in my API, calling a GQL query results in data aggregated in fields where should be an empty object
An example of the query usage
Seeing the above example if you check the results I have the objects and inside you see
callReminders
siteAppointments
Which are aliases of events from the query and give back us results based on the types filter
As you see the result is the same for both objects
{
"id": "33116",
"startTime": "2023-01-10T08:57:00.000Z",
"type": "APPOINTMENT_PHONE"
}
the second object siteAppointments should result as nodes: [] as that candidate has only APPOINTMENT_PHONEbut that is duplicated to the results of the second object and I don't know why.
The resolver for the event
events: {
selectionSet: '{ id }',
resolve(candidate, args, context, info) {
return batchDelegateToSchema({
schema: event,
operation: 'query',
fieldName: 'eventsByOwner',
key: candidate.id,
transforms: [transformEventsByOwner],
argsFromKeys: keys => ({
...args,
filter: {
...(args?.filter ?? {}),
ownerTypes: ['CANDIDATE'],
ownerIds: keys,
},
}),
valuesFromResults: (results, keys) =>
keys.map(findByOwnerId(results)).map(mapToConnection),
context,
info,
});
},
},
The methods used inside
export function findByOwnerId(results) {
return id => results?.find(item => item?.ownerId === id);
}
export function mapToConnection(result) {
return {
totalCount: result?.totalCount ?? 0,
nodes: result?.nodes ?? [],
};
}
I believe there is a problem with the valuesFromResultsbut have no clue what to change and how to have the expected result as
{
"data": {
"candidate": {
"id": "CY-001745",
"callReminders": {
"nodes": [
{
"id": "33116",
"startTime": "2023-01-10T08:57:00.000Z",
"type": "APPOINTMENT_PHONE"
}
],
"totalCount": 1
},
"siteAppointments": {
"nodes": [],
"totalCount": 0
}
}
}
}
I want to display values from my json but I don't know how to do it. Is it possible to loop inside an object array ? i don't know if the keyvalue pipe can help me but I want to do without.
how to get the student2 and also the name to display it ?
thanks everyone.
json
{
"student": {
"student1": [],
"student2": [
{
"id": "123",
"name": "boot"
},
"student3": [],
]
},
"teacher": {
"teacher1": [],
"teacher2": [
{
"id": "123456",
"name": "toto"
},
]
}
}
ts.file
get(){
this.service.getAll().subscribe((data:any) => {
object.keys(data).length > 0;
})
}
Assuming your JSON object from your GET request looks like the one you posted above simply do:
get(){
this.service.getAll().subscribe((data:any) => {
data.student.forEach(element => {
for (let key in element) {
console.log(" key:", key, "value:", element[key]);
for (let val in element[key]) {
console.log(" value:", val);
}
}
});
})
}
I have the following data :
const data=
{
"1": [
{
"sales_project_id": 5,
"sales_project_name": "name",
"sales_project_est_rev": "123.00",
"project_status": {
"id": 1,
"label": "Start",
"description": null
}
},
{
"sales_project_id": 6,
"sales_project_name": "name2",
"sales_project_est_rev": "123.00",
"project_status": {
"id": 1,
"label": "Start",
"description": null
}
}
],
"2": [],
"4": []
}
These data are grouped in my backend based on their Status , in this case im only showing 2 status , but they are dynamic and can be anything the user defines.
What i wish to do is to transform the above data into the format below :
const data =
{
columns: [
{
id: // id of status here,
title: //label of status here,
cards: [
{
id : //sales_project_id here,
title: //sales_project_name here,
},
]
},
{
id: // id of status here,
title: //label of status here,
cards: [
{
id : //sales_project_id here,
title: //sales_project_name here,
},
]
}
]}
My guess would be to iterate over the data , however i am pretty unfamiliar with doing so , would appreciate someone's help!
Here is what i could come up with so far:
const array = []
Object.keys(a).map(function(keyName, keyIndex) {
a[keyName].forEach(element => {
#creating an object of the columns array here
});
})
after some trial and error , manage to accomplish this , however , im not sure if this is a good method to do so.
Object.keys(projects).map(function(keyName, keyIndex) {
// use keyName to get current key's name
// and a[keyName] to get its value
var project_object = {}
project_object['id'] = projects[keyName][0].id
project_object['title'] = projects[keyName][0].label
project_object['description'] = projects[keyName][0].description
console.log( projects[keyName][1])
var card_array = []
projects[keyName][1].forEach(element => {
var card = {}
card["id"] = element.sales_project_id
card["title"] = element.sales_project_name
card["description"] = element.sales_project_est_rev
card_array.push(card)
});
project_object["cards"] = card_array
array.push(project_object)
})
Im basically manipulating some the scope of the variables inorder to achieve this
See my solution, I use Object.keys like you, then I use reduce:
const newData = { columns: Object.keys(data).map((item) => {
return data[item].reduce((acc,rec) => {
if (typeof acc.id === 'undefined'){
acc = { id: rec.project_status.id, title: rec.project_status.label, ...acc }
}
return {...acc, cards: [...acc.cards, { id:rec.sales_project_id, title:rec.sales_project_name}]}
}, {cards:[]})
})}
See full example in playground: https://jscomplete.com/playground/s510194
I'd just do this. Get the values of data using Object.values(data) and then use reduce to accumulate the desired result
const data=
{
"1": [
{
"sales_project_id": 5,
"sales_project_name": "name",
"sales_project_est_rev": "123.00",
"project_status": {
"id": 1,
"label": "Start",
"description": null
}
},
{
"sales_project_id": 6,
"sales_project_name": "name2",
"sales_project_est_rev": "123.00",
"project_status": {
"id": 1,
"label": "Start",
"description": null
}
}
],
"2": [],
"4": []
};
const a = Object.values(data)
let res =a.reduce((acc, elem)=>{
elem.forEach((x)=>{
var obj = {
id : x.project_status.id,
title : x.project_status.label,
cards : [{
id: x.sales_project_id,
title: x.sales_project_name
}]
}
acc.columns.push(obj);
})
return acc
},{columns: []});
console.log(res)
I am trying to pass through an object that looks like this
{
"nodes": [
{
"attributes": null
},
{
"attributes": {
"nodes": [
{
"attributeId": 1,
"name": "pa_color",
"options": [
"gray"
]
},
{
"attributeId": 2,
"name": "pa_size",
"options": [
"large"
]
}
]
}
},
{
"attributes": {
"nodes": [
{
"attributeId": 1,
"name": "pa_color",
"options": [
"blue"
]
}
]
}
}
]
}
into a react component that renders all the different options under all the unique names. However, the way the data is structured means that I receive duplicates of names and options.
I am trying to convert the object into this object
{
"node": {
"attributeId": 1,
"name": "pa_color",
"values": [
{
"name": "gray"
},
{
"name": "blue"
}
]
},
"node": {
"attributeId": 2,
"name": "pa_size",
"values": [
{
"name": "large"
}
]
},
}
Current code looks like this
export interface Category_products_edges_node_attributes_edges_node {
__typename: "ProductAttribute";
/**
* Attribute Global ID
*/
name: string;
/**
* Attribute options
*/
options: (string | null)[] | null;
/**
* Attribute ID
*/
attributeId: number;
}
export interface ProductFiltersProps {
attributes: Category_products_edges_node_attributes_edges_node[]
}
export const ProductFilters: React.FC<ProductFiltersProps> = ({
attributes,
}) => (
<div className="product-filters">
<div className="container">
<div className="product-filters__grid">
{attributes.map(attribute => (
I have tried to do
{groupBy(attributes, 'attributeId').map(attribute => (
With the Lodash library, but receive the error
This expression is not callable. Type
'Category_products_edges_node_attributes_edges_node[]' has no call
signatures.
What is the best way to do this?
Thank you
lodash groupBy returns an Object not an Array therefore the javascript .map call will not work on it. Also groupBy is used to group items with similar property under one key inside an object, it isn't used to remove duplicates.
To remove duplicates use the lodash uniqBy method. This method can be called on an array and returns an array without duplicates.
Update:
To view in more detail how you can remove duplicates based on more than one property of object please see great answer
Also the output object you are trying to achieve has similar keys, I think that is not what you want, a Javascript object should not have duplicate keys. So my output gives keys as node0, node1 instead of node
You can achieve this as follows:
const nodes = {
nodes: [
{ attributes: null },
{
attributes: {
nodes: [
{ attributeId: 1, name: "pa_color", options: ["gray"] },
{ attributeId: 2, name: "pa_size", options: ["large"] }
]
}
},
{
attributes: {
nodes: [{ attributeId: 1, name: "pa_color", options: ["blue"] }]
}
}
]
}
const attributes = []
nodes.nodes.forEach(e => {
if (e.attributes && Array.isArray(e.attributes.nodes)) {
attributes.push(...e.attributes.nodes)
}
})
const uniqueAttributes = _.uniqBy(attributes, (obj) => [obj.attributeId, obj.name, obj.options].join())
const uniqueNodes = uniqueAttributes.map((e, i) => ({ ["node" + i]: e }))
console.log("Unique Nodes: ", uniqueNodes)
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.10/lodash.min.js"></script>
I'm trying to filter this objects array and keep the original one aside.
{"departments":
[
{
“name": “AAA",
“selected”: true,
"courses": [
{
"name": “course1",
“selected”: true,
“titles”:
[{
"name": “title1",
“selected”: true
},
{
"name": “title2",
“selected”: false
}]
},
{
"name": “course2",
“selected”: false,
“titles”:
[{
"name": “title1",
“selected”: false
}]
}
]
},
{
“name": “BBB",
“selected”: false,
"courses": [{...}]
{...}
]
}
I want to find all the selected departments, courses and titles. And it should be in the same format.
I tried with below code, but it change original data. I want to keep that aside too.
const depts = departments.filter((dept: any) => {
if (dept.selected) {
dept.courses = dept.courses.filter((course: any) => {
if (course.selected) {
if (course.titles) {
course.titles = course.titles.filter(({selected}: any) => selected);
}
return true;
}
return false;
});
return true;
}
return false;
});
What would be considered the best solution in this case?
Shorter alternative can be to use the JSON.parse reviver parameter :
var arr = [{ name: "AAA", selected: true, courses: [{name: "course1", selected: true, titles: [{ name: "title1", selected: true }, { name: "title1", selected: false }]}, { name: "course2", selected: false, titles: [{ name: "title1", selected: false }]}]}]
var result = JSON.parse(JSON.stringify(arr), (k, v) => v.map ? v.filter(x => x.selected) : v)
console.log( result )
your filtering logic seems to be correct. only problem is that code changes original array. in order to overcome this problem just create a deep clone of original array and run filtering logic on it
filterArray() {
const clone = JSON.parse(JSON.stringify(this.departments));
const depts = clone.filter((dept: any) => {
if (dept.selected) {
dept.courses = dept.courses.filter((course: any) => {
if (course.selected) {
if (course.titles) {
course.titles = course.titles.filter(({ selected }: any) => selected);
}
return true;
}
return false;
});
return true;
}
return false;
});
console.log(depts);
}
here is a demo https://stackblitz.com/edit/angular-xx1kp4
const filterSelected = obj => {
return {
...obj,
departments: obj.departments.map(dep => {
return {
...dep,
courses: dep.courses.map(course => {
return {
...course,
titles: course.titles.filter(title => title.selected),
};
}).filter(course => course.selected),
};
}).filter(dep => dep.selected),
};
}
const all = {
departments: [
{
name: "AAA",
selected: true,
courses: [
{
name: "course1",
selected: true,
titles: [
{
name: "title1",
selected: true
}, {
name: "title1",
selected: false
}
]
}, {
name: "course2",
selected: false,
titles: [
{
name: "title1",
selected: false
}
]
},
]
}
]
};
console.log(filterSelected(all));
I don't know if you prefer an API false. Here is my tip:
You can to use an API Json Server.
Install JSON Server
npm install -g json-server
Create a db.json file with some data
{
"posts": [
{ "id": 1, "title": "json-server", "author": "typicode" }
],
"comments": [
{ "id": 1, "body": "some comment", "postId": 1 }
],
"profile": { "name": "typicode" }
}
Start JSON Server
json-server --watch db.json
Now if you go to http://localhost:3000/posts/1, you'll get
{ "id": 1, "title": "json-server", "author": "typicode" }
you can search your array of objects using various shapes and it will come filtered. More about the API here: https://github.com/typicode/json-server
(Use a filter to do your searches on the Angular, it will bring you right what you need, use a method inside your component)