Final Form calculate set object to a position in array values - reactjs

I am setting up a parser for one of my fields, if user types 'Honda' for example, it will get matching DB values like: {make: 'Honda', id: 5, year: '2012'} and etc.
I would like to set field values when I get response from API.
Is it possible instead of the following
updates(value, name, allValues) => {
return {
['vehicle[0].make']: 'Honda',
['vehicle[0].year']: '2012',
....
}
}
to set values like following:
updates(value, name, allValues) => {
return {
['vehicle[0]']: {
make: 'Honda',
id: 5,
year: '2012'
....
}
}

Related

React: render objects based on value type

I have an object array with a structure similar to this:
export interface obj {
id: number,
date: string,
source: string,
}
const obj: obj[] | undefined = [
{ id: 1, date: "2021-01-17", source: "data" },
{ id: 2, date: "2021-11-23", source: "data" },
{ id: 3, date: "2020-05-03", source: "draft" },
{ id: 4, date: "2022-09-08", source: "draft" },
{ id: 5, date: "2021-12-04", source: "data" },
{ id: 6, date: "2021-09-08", source: "empty" },
];
const [objectData, setObjectData] = useState<obj[]>();
I'm trying to return and render the first occuranses of each source type, sorted by the nearest date. So in the example above I'd like to return the object with id: 5 for "data", id: 4 for "draft" and id: 6 for "empty".
This is what I got so far:
Sorting object by dates descending in useEffect and store variable in useState
const sortByDate = obj?.slice().sort((a, b) => {
return b.date.valueOf() - a.date.valueOf();
})
And then trying to map out my component like so:
{objectData?.map((m) =>
m.source === "draft" ? (
<Data id={m.id} date={m.date} source={m.source} />
) : m.applicationType === "data" ? (
<Data id={m.id} date={m.date} source={m.source} />
) : m.applicationType === "empty" ? (
<Data id={m.id} date={m.date} source={m.source} />
)
)}
But this will ofcourse render out every object..How can I render out only the one instance of each object source type that i want?
Given your approach, I would
a) Sort the items in the list in a descending manner.
b) Create a list of possible unique source names
c) Render the unqiue source names and get the first item matching the source name in my descending ordered array.
You can get rid of b) if you want to define your list of source names statically. If that is the case, you need to handle if there is no item found with the source name that is selectecd.
const items = [
{ id: 1, date: "2021-01-17", source: "data" },
{ id: 2, date: "2021-11-23", source: "data" },
{ id: 3, date: "2020-05-03", source: "draft" },
{ id: 4, date: "2022-09-08", source: "draft" },
{ id: 5, date: "2021-12-04", source: "data" },
{ id: 6, date: "2021-09-08", source: "empty" },
];
// a) Sort the array with date object (descending)
const sortedArray = items.sort((a, b) => {
return new Date(b.date).valueOf() - new Date(a.date).valueOf();
});
// b) This will let you get all possible sources dynamically and create an array of unique entries
const uniqueSources = [...new Set(sortedArray.map(item => item.source))];
// c) Map over (existing) unqiue entries in the sorted list and get the first one found
uniqueSources.map((source) => {
const firstObject = sortedArray.find((entry) => entry.source === source);
console.log('source:', source, firstObject);
});
I think you probably do (or should) know the possible values of source, and in fact those should be the type for source, ex:
export interface obj {
id: number,
date: string,
source: 'data' | 'draft' | 'empty',
}
Then in your useEffect you have the internal variable sortedByMostRecent which is your array of data sorted by the date value.
With that you can use a constant array (defined at the top of your file, outside the component definition around the interface definition) of the source options:
const availableSources: interface['source'][] = ['data', 'draft', 'empty'];
To find the first object in the sorted array matching each available (possible) source. Something like:
const topSourceItems = [];
for (source of availableSources) {
const topSource = sortedByMostRecent.find(item => item.source == source);
if (topSource) {
topSourceItems.push(topSource);
}
}
topSourceItems would then be stored in state and rendered with a regular iteration in the markup.
Notes:
Your .slice() isn't doing anything. Also calling an array "obj" is probably not the best decision, but I understand this is likely just dummy code for the example.

Find object in state and update property

I have a problem with a dynamic state I am setting. My first state looks like this:
const [exercises, setExercises] = useState([{
id: 123,
title: "Title here",
category: "someCategory"
}])
A user then selects an item of this state. I create a second state representing the selected object, but adding additional properties to it. For instance I am adding and initializing the properties 'amount' and 'unit'.
const [selectedExercises, setSelectedExercises] = useState([{
id: 123,
title: "Title here",
category: "someCategory",
amount: 0,
unit: ''
}])
I want the user to choose amount and unit from a form. How do I access and change those two properties in the state? Since I don't know the user's selection, I have to find the object within the state first.
I have tried things like (el being called from an input element somewhere):
setSelectedExercises([
...selectedExercises,
(selectedExercises.find(exercise => exercise.title === el.title).amount = 1),
])
How do I find the object in question and update its amount property (for example in an onChange method)?
const [selectedExercises, setSelectedExercises] = useState([{
id: 123,
title: "Title here",
category: "someCategory",
amount: 0,
unit: ''
}]);
// Your handler should look like this and
// you should call handleAmountChange(el.id, 1)
function handleAmountChange(amount, id) {
setSelectedExercises(prev => prev.map(selectedExercise => {
if (selectedExercise.id === id) {
return {
...selectedExercise,
amount
}
}
return selectedExercise;
}));
}
A more generic function to change any property would look like this.
function handleChange(id, property, value) {
setSelectedExercises(prev => prev.map(selectedExercise => {
if (selectedExercise.id === id) {
return {
...selectedExercise,
[property]: value
}
}
return selectedExercise;
}));
}

Graphql mutation query : how to access the data elements

const MUTATION_QUERY = gql`
mutation MUTATION_QUERY(
$name: bigint!
) {
insert_name(
objects: {
name: $name
}
) {
returning {
id
name
}
}
}
`;
const [onClick, { error, data }] = useMutation<{}, {}>(MUTATION_QUERY, {
variables: {
name: 1234,
},
});
My mutation query is inserting name in my table and autogenerating the id. On console logging the data variable I can view the fields id and name in the data object. But I am not able to access them them individually. How can I console.log "id". Thank you.
the console.log(data) looks like : {insert_name: {...}}
which expands to :
insert_name:
returning: Array(1)
0: {id: 1, name: 1234}
length: 1
_proto_: Array(0)
_typename: "insert_name_mutation_response
You can access the fields of an object with .
For example, if your object looks like this -
data = {
id: 1,
name: 'Jane',
}
You can get just the id with data.id
This works no matter how many layers deep your object may go, so take this example -
data = {
person: {
id: 1,
name: 'Jane',
}
}
You could get the id of person with data.person.id.
console.log(data.insert_name.returning[0].id) will give you the id returned.
For it to work in typescript we need to change the query to add the return type of data
const [onClick, { error, data }] = useMutation<{ReturnInsertNameProps}, {}>(MUTATION_QUERY, {
variables: {
name: 1234,
},
});
interface ReturnInsertNameProps {
insert_name: ReturnQueryProps;
}
interface ReturnProps {
returning: MessageProps[];
}
interface NameProps {
id: number;
name: number;
}
We can also use onCompleted method provided in useMutation if we want to process the result of the query.

In an array of obects watched with Vue-watch, how to get index of object that was changed?

I have an array of objects, like this:
myArray: [{
name: "First",
price: 10,
rebate: 5,
listPrice: 15,
outcome: 0
},{
name: "Second",
price: 11,
rebate: 5,
listPrice: 16,
outcome: 0
}
I want to recalculate the outcome-value whenever any of the other values in the same object change.
I already have a setup like this, but it looks for changes in any object and then recalculates the whole array. I've managed to set this up by using a combination of computed and watch functions. However they watch the whole array for changes and then recalculate the outcome-value for all objects in the array.
How can I watch for changes and then recalculate only the changed object?
Below is my current functions for recalculating the whole array (watching another property), but what I'm looking for could be completely different.
computed:
myArrayWasChanged() {
return [this.myArray.reduce((a, {vendors}) => a + vendors, 0), this.myArray.filter(item => item.discounted == false).length]
watch:
myArrayWasChanged: {
handler: function (val, oldVal) {
this.recalculateIsVendor();
Given the outcome is completely dependent on the other properties, it isn't really part of the component's state. Thus, in the component's data you could store the array without the outcome, and then calculate a new version of the array with the outcome as a computed property.
data: function () {
return {
myArrayWithoutOutcome: [
{
name: "First",
price: 10,
rebate: 5,
listPrice: 15
},
{
name: "Second",
price: 11,
rebate: 5,
listPrice: 16
}]
}
},
computed: {
myArrayWithOutcome: function () {
return this.myArrayWithoutOutcome.map(x => {
return {...x, outcome: this.calculateOutcome(x)}
})
}
},
methods: {
calculateOutcome(item) {
// Logic to calculate outcome from item goes here
return 0
}
}

How do you select a particular field from a response string which we receive in form of JSON

I have a sample response which I received, the structure is something like this:
A = [{ user:
{ score_level: 16,
is_system: false,
location: 'Mumbai',
email: 'abc#xyz.org',
image: 'example.org',
firstname: Steve},
details: { solution_count: 1, average_rating: 1, recommendation_count: 0 },
score: 45},
{ user:
{ score_level: 17,
is_system: false,
location: 'Miami',
email: 'ab.org',
image: 'example.net',
firstname: Mark},
details: { solution_count: 1, average_rating: 1, recommendation_count: 0 },
score: 50}]
We are getting some information about the user, so what I would like to do is to get only the fistname for every user from this file.
I tried using:
var read = JSON.parse(A);
var firstname = read["user"]["firstname"];
But this dosent seem to work, can you suggest a solution for this?
You can map through the array of objects, check if the object is a user object, and if so, return the firstname. This will yield an array of firstname values.
const names = A.map((obj) => {
if (obj.user) {
return obj.user.firstname;
}
});

Resources