Filtering a JSON with Javascript - javascript

I am trying to filter a JSON using filter and I'm not getting the clubProducts to return as I hoped (allProducts works fine). Any help is appreciated. Thank you
const state = {
added: [],
all: [
{
id: 'bcd755a6-9a19-94e1-0a5d-426c0303454f',
name: 'Iced Coffee',
description: 'Coffee, now featuring ice.',
image: 'https://images.com',
price: 899,
fxCategory: 'Coffee'
},
{
id: 'cc919e21-9a19-94e1-ace9-426c0303454f',
name: 'The 2ndItem',
description: 'Wouldn't you like to know.',
image: 'https://images.com',
price: 499,
fxCategory: 'Club'
}
]
}
const getters = {
allProducts: state => state.all,
clubProducts: state => function () {
return state.all.filter(item => item.fxCategory == 'Club')
}
}
EDIT: Updated with latest attempt as per suggestions

You made two mistakes: you can use filter() only on an array (ie state.all in your case), and in your comparison you didn't quote the string 'Club'.
Also, your filter() can be written in a shorter way, as such:
clubProducts: state.all.filter(item => item.fxCategory == 'Club')
See documentation for more.

As mentioned by #Reyedy you can call filter function directly in 'clubProducts' field and this example is works.
But you may get an error because you use single quotes in 'description' field.
Try in state.all
description: "Wouldn't you like to know.",
instead of
description: 'Wouldn't you like to know.',
This is the only place I got an error trying to repeat your example.

Related

How to Make a Reusable Function that Removes Duplicates

I am trying to make a function as re-usable as possible.
I have a JSON file containing "products" for now.
export let productList = [
{
id: 0,
productName: "Men's Merrel Hiking Boots",
price: 65.00,
brand: "Merrell",
},
{
id: 1,
productName: "Women's Merrel Hiking Boots",
price: 65.00,
brand: "Merrell",
},
{
id: 2,
productName: "Natural Walking Stick",
price: 22.00,
brand: "Fayet",
}
]
In my case, I am trying to map through these products and return all the brands without duplicates. I know I can do that with this Set function:
function dedupeCheckboxOptions() {
return [...new Set(productList.map(product => product.brand))];
}
This works, but I am struggling to figure out a way to make this more re-usable. I would think it would look something like this so I could also use the function to maybe return the prices:
function dedupeCheckboxOptions(fullList, item) {
return [...new Set(fullList.map(product => product.item))];
}
However, this syntax is not correct. Is there a way to accomplish this?
Update:
function dedupeCheckboxOptions(fullList, item) {
return [...new Set(fullList.map(product => product[item]))];
}
This looks promising from what #samathingamajig said, but when I pass through the productList from the JSON file and run the app (React app), it says the productList is undefined.
Use the bracket notation property accessor since you're using a variable.
Also, you don't need to pass in individualItem because that already gets defined when you set that as the name of the argument passed into the callback function.
function dedupeCheckboxOptions(productList, item) {
return [...new Set(productList.map(individualItem => individualItem[item]))];
}

Using multiple filters on a dynamically generated table with pure JavaScript

I have a table that is dynamically generated using PHP and a MySQL table/database... I also have figured out how to use filters. The problem is that it only lets you use one filter at a time... Here is a screenshot of what I mean: screenshot
You can only filter by description or by date... not both.
Is there some way to do this? I can't really provide you any HTML/JavaScript code as you won't see anything because the table data comes from a database but let me know if you need any more detail...
Thanks!
If I understood your question properly, you can do something like this:
Let's assume we have an array of objects
const data = [
{
id: 0,
date: '1609084588132',
description: 'something'
},
{
id: 1,
date: '1609087588132',
description: 'anything'
},
{
id: 2,
date: '1609087588132',
description: 'anything'
}
]
And to filter this array by two properties, you can do something like:
const filteredData = data.filter((item) => {
if (item.date > 'some date' && item.description.includes('anyth')) {
return true;
}
return false;
});
console.log(filteredData)
I think you got an idea, we filtered the array above with two conditions: id must be bigger than 0 and description string must contain 'anyth'.

How to access the img value? javascript

I have an array of objects with several properties, one of them is called 'file', of which there are two types as represented below
const products = [
{
functional_id: "2_recharges",
quantity: 1,
title: "Coffret empreinte rouge",
file: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAA…em3dIEUUE1O4fn/M8l6v+f6VPgptdk2plAAAAAElFTkSuQmCC"
},
{
functional_id: "sacs_blancs",
quantity: 1,
title: "Sacs blancs",
file: "data:image/;base64,"
}
]
It's the first time I work with image files and I don't know how to differentiate to create a condition so that only those containing the word 'png' in its value are displayed, in the case of the example the first one, since those that are like the second one don't display any image
I tried to treat them as a string to check if they contained the value string but it doesn't work, as I understand that they are not strings.
If someone can give me an idea of how to create my condition. Thank you very much in advance
You will want to use the js filter method to check whether the file includes 'png'.
const products = [{
functional_id: "2_recharges",
quantity: 1,
title: "Coffret empreinte rouge",
file: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAA…em3dIEUUE1O4fn/M8l6v+f6VPgptdk2plAAAAAElFTkSuQmCC"
},
{
functional_id: "sacs_blancs",
quantity: 1,
title: "Sacs blancs",
file: "data:image/;base64,"
}
]
const pngImages = products.filter(product => product.file.includes('png'))
console.log(pngImages)
this simple filter returns you just only those products that have png in file string
products.filter(product => product.file.match('png').length);

Normalizr - is it a way to generate IDs for non-ids entity model?

I'm using normalizr util to process API response based on non-ids model. As I know, typically normalizr works with ids model, but maybe there is a some way to generate ids "on the go"?
My API response example:
```
// input data:
const inputData = {
doctors: [
{
name: Jon,
post: chief
},
{
name: Marta,
post: nurse
},
//....
}
// expected output data:
const outputData = {
entities: {
nameCards : {
uniqueID_0: { id: uniqueID_0, name: Jon, post: uniqueID_3 },
uniqueID_1: { id: uniqueID_1, name: Marta, post: uniqueID_4 }
},
positions: {
uniqueID_3: { id: uniqueID_3, post: chief },
uniqueID_4: { id: uniqueID_4, post: nurse }
}
},
result: uniqueID_0
}
```
P.S.
I heard from someone about generating IDs "by the hood" in normalizr for such cases as my, but I did found such solution.
As mentioned in this issue:
Normalizr is never going to be able to generate unique IDs for you. We
don't do any memoization or anything internally, as that would be
unnecessary for most people.
Your working solution is okay, but will fail if you receive one of
these entities again later from another API endpoint.
My recommendation would be to find something that's constant and
unique on your entities and use that as something to generate unique
IDs from.
And then, as mentioned in the docs, you need to set idAttribute to replace 'id' with another key:
const data = { id_str: '123', url: 'https://twitter.com', user: { id_str: '456', name: 'Jimmy' } };
const user = new schema.Entity('users', {}, { idAttribute: 'id_str' });
const tweet = new schema.Entity('tweets', { user: user }, {
idAttribute: 'id_str',
// Apply everything from entityB over entityA, except for "favorites"
mergeStrategy: (entityA, entityB) => ({
...entityA,
...entityB,
favorites: entityA.favorites
}),
// Remove the URL field from the entity
processStrategy: (entity) => omit(entity, 'url')
});
const normalizedData = normalize(data, tweet);
EDIT
You can always provide unique id's using external lib or by hand:
inputData.doctors = inputData.doctors.map((doc, idx) => ({
...doc,
id: `doctor_${idx}`
}))
Have a processStrategy which is basically a function and in that function assign your id's there, ie. value.id = uuid(). Visit the link below to see an example https://github.com/paularmstrong/normalizr/issues/256

Manipulating data in nested arrays in Redux with immutable.js

So, I've been working on making an APP in React Native for which i have programmed a RESTFul API in Java, which returns some data in JSON format. I will have a datastructure that looks something like this - it is also the initial state for this Reducer, I have simply deleted some of the values as they are irrelevant:
categories: [{
id: 1,
name: '',
image: '',
subcategories: [
{
name: '',
id: 1,
products: [{
name: '',
description: 'This is a good product',
id: 55,
quantity: 4
}, {
name: '',
description: 'This is a good product',
id: 3,
quantity: 0
}]
},
{
name: '',
id: 2,
products: [{
name: '',
description: 'This is a good product',
id: 4,
quantity: 0
}]
}]
}, {
id: 2,
name: '',
image: '',
subcategories: [
{
name: '',
id: 3,
products: [{
name: '',
description: 'This is a good product',
id: 15,
quantity: 0
}]
}
]
}]
I will be saving this in my Redux store but where i struggle is when I have to update the quantity of a certain product with only the products id.
So far I've found a solution using immutable.js but it is quite ugly and I'm really unsure if this is the way to go.
I've searched for solutions but have not yet found one with a solution without normalizing the datastructure. For now I want to see if I can avoid normalizing the data, as I want to keep the same format for posting stuff back to the server. (and for learning purposes)
My solution in my Reducer with immutable.js looks like this:
case types.ADD_PRODUCT:
const oldState = fromJS(state).toMap();
var findCategoryIndex = oldState.get('categories').findIndex(function (category) {
return category.get("subcategories").find(function (subcategories) {
return subcategories.get("products").find(function (product) {
return product.get("id") === action.productId;
})
})
})
var findSubcategoryIndex = oldState.getIn(['categories', findCategoryIndex.toString()]).get('subcategories').findIndex(function (subcategory) {
return subcategory.get("products").find(function (product) {
return product.get("id") === action.productId;
});
})
var findProductIndex = oldState.getIn(['categories', findCategoryIndex.toString(), 'subcategories', findSubcategoryIndex.toString()]).get('products').findIndex(function (product) {
return product.get("id") === action.productId;
})
var newState = oldState.setIn(['categories', findCategoryIndex.toString(),
'subcategories', findSubcategoryIndex.toString(), 'products', findProductIndex.toString(), 'quantity'],
oldState.getIn(['categories', findCategoryIndex.toString(), 'subcategories', findSubcategoryIndex.toString(), 'products', findProductIndex.toString(), 'quantity'])+1);
const newStateJS = newState.toJS();
return {...state, categories: [...newStateJS.categories]}
I know all this may seem overcomplicated for the case, but I am simply trying to learn different approaches to this as I am very new to everything that has to do with JavaScript.
I am not looking for optimization on the data format itself, but I am looking for ways to manipulate data in nested arrays in Redux
I hope to get some good feedback on this and hopefully find out if I am on the right track :)
EDIT: It works with spread operators aswell without using Immutable.js, but I don't really understand what the difference is. Is there a performance difference and why choose one over the other?
case types.ADD_PRODUCT:
return {
...state,
categories:[...state.categories.map(category => ({...category,
subcategories:[...category.subcategories.map(subcategory => ({...subcategory,
products:[...subcategory.products.map(product => product.id === action.productId ? {...product, quantity: product.quantity+1} : product)]}))]}))]
}
When things the data to become a bit too deep, you can still use helper like Immutable.js Map. I am not sure this is the correct way to use Immutable.js since I am also experimenting it. It lets you return new state in a less verbose way like this :
import { fromJS } from 'immutable';
export default function reducer(state = initialState, action) {
const iState = fromJS(state);// Immutable State
switch (action.type) {
case type.ACTION:
return iState.setIn(['depth1','depth2', 'depth3'], 'foobar').toJS()
// return a copy of the state in JavaScript
// {depth1: {depth2: {depth3: 'foobar'} } }
default:
return state;
}
and from what I heard, using Immutable is more performant but it adds an another dependency to your project. Careful tough, if you are using combineReducers(reducers), it expects to be pass a plain object, so be sure to pass a plain object and not an Immutable object.
You said you are not specifically looking for optimization on the data format itself. Correct me if I am wrong, I think normalizr will help you to gain in flatness and be easier to update your store

Categories

Resources