react-table TypeError: Cannot read properties of undefined (reading 'forEach') - react-table

TypeError: Cannot read properties of undefined (reading 'forEach')
This is an error message I get when I am trying to render OrderTable component. I struggled fixing it for a good few hours and I don't have idea what is wrong.
Other almost similar tables works fine.
const orderProducts = useSelector((state) => state.orders.order.products)
I use this structure instead of state.orders.order because from serializer I got nested data that does not works. Tried to take products from order after selector and it does not also work. Data seems to be fine, but I attach JSON anyway.
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { getOrder } from "../../features/orders/orderSlice";
import {
useTable,
useRowSelect,
useSortBy,
useFilters,
useGlobalFilter,
} from "react-table";
import {
Table,
TableBody,
TableCell,
TableHead,
TableRow,
} from "#mui/material";
import Paper from "#mui/material/Paper";
import KeyboardArrowUpIcon from "#mui/icons-material/KeyboardArrowUp";
import KeyboardArrowDownIcon from "#mui/icons-material/KeyboardArrowDown";
import TableContainer from "#mui/material/TableContainer";
import IndeterminateCheckbox from "../Checkbox";
import ColumnFilter from "../ColumnFilter";
// import GlobalFilter from "../GlobalFilter";
const OrderTable = () => {
const dispatch = useDispatch();
useEffect(() => {
const id = window.location.pathname.split("/orders/order/").pop();
dispatch(getOrder(id));
}, []);
const loading = useSelector((state) => state.orders.loading);
const orderProducts = useSelector((state) => state.orders.order.products);
const data = React.useMemo(() => orderProducts, [orderProducts]);
const columns = React.useMemo(
() => [
{ Header: "ID", accessor: "id", Filter: ColumnFilter },
{ Header: "Nazwa", accessor: "product.title", Filter: ColumnFilter },
{ Header: "Ilość", accessor: "quantity", Filter: ColumnFilter },
{ Header: "Cena", accessor: "product.price", Filter: ColumnFilter },
{ Header: "Wartość", accessor: "total_price", Filter: ColumnFilter },
{
Header: "Zamówiony",
accessor: (d) => (d.ordered ? "Tak" : "Nie"),
Filter: ColumnFilter,
},
],
[]
);
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
state,
setGlobalFilter,
prepareRow,
selectedFlatRows,
} = useTable(
{ columns, data },
useGlobalFilter,
useFilters,
useSortBy,
useRowSelect,
(hooks) => {
hooks.visibleColumns.push((columns) => [
// Let's make a column for selection
{
id: "selection",
// The header can use the table's getToggleAllRowsSelectedProps method
// to render a checkbox
Header: ({ getToggleAllRowsSelectedProps }) => (
<div>
<IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />
</div>
),
// The cell can use the individual row's getToggleRowSelectedProps method
// to the render a checkbox
Cell: ({ row }) => (
<div>
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
</div>
),
},
...columns,
]);
}
);
const { globalFilter } = state;
return (
<>
{loading ? (
"loading"
) : (
<TableContainer component={Paper} sx={{ ml: 3, mt: 2 }}>
<Table {...getTableProps()} size="small">
<TableHead>
{headerGroups.map((headerGroup) => (
<TableRow {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<TableCell {...column.getHeaderProps()}>
<div {...column.getSortByToggleProps()}>
{column.render("Header")}
{column.isSorted ? (
column.isSortedDesc ? (
<KeyboardArrowUpIcon fontSize="small" />
) : (
<KeyboardArrowDownIcon fontSize="small" />
)
) : (
""
)}
</div>
<div>
{column.canFilter ? column.render("Filter") : null}
</div>
</TableCell>
))}
</TableRow>
))}
</TableHead>
<TableBody {...getTableBodyProps()}>
{rows.map((row) => {
prepareRow(row);
return (
<TableRow {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<TableCell {...cell.getCellProps()}>
{cell.render("Cell")}
</TableCell>
);
})}
</TableRow>
);
})}
</TableBody>
</Table>
</TableContainer>
)}
</>
);
};
export default OrderTable;
JSON
{
"id": 37,
"products": [
{
"id": 68,
"product": {
"id": 1,
"created": "2021-11-11T02:01:15.897446Z",
"active": true,
"title": "Kapustka",
"description": "biała",
"quantity": -143,
"price": "3.24",
"category": 1
},
"quantity": 8,
"total_price": "25.92",
"ordered": true,
"user": 1
},
{
"id": 69,
"product": {
"id": 2,
"created": "2021-11-12T17:16:43.422467Z",
"active": true,
"title": "Marchew",
"description": null,
"quantity": 10,
"price": "2.00",
"category": null
},
"quantity": 11,
"total_price": "22.00",
"ordered": true,
"user": 1
},
{
"id": 70,
"product": {
"id": 5,
"created": "2021-11-13T20:03:01.336712Z",
"active": true,
"title": "Makaron",
"description": null,
"quantity": 0,
"price": "0.00",
"category": null
},
"quantity": 1,
"total_price": "0.00",
"ordered": true,
"user": 1
},
{
"id": 71,
"product": {
"id": 6,
"created": "2021-11-13T20:03:12.384605Z",
"active": true,
"title": "Pomidor",
"description": null,
"quantity": 0,
"price": "0.00",
"category": null
},
"quantity": 1,
"total_price": "0.00",
"ordered": true,
"user": 1
}
],
"title": "Zamowienie",
"created": "2021-11-13T19:26:59.545602Z",
"value": "49.92",
"is_paid": false,
"ordered": true,
"user": 1
}

Related

ReduxToolKit | CreateEntityAdaptor userSelectors.selectAll giving Cannot read properties of undefined (reading 'map')

Hi i am using ReduxToolKit CreateEntityAdaptor for crud, when i get all users from API by using userSelectors.selectAll, it gives "Cannot read properties of undefined (reading 'map')".
let me show my API response.
{
"data": [
{
"id": 16,
"name": "Admin",
"email": "admin#admin.com",
"assigned_roles": [
"Administrator"
],
"created_at": "2022-10-06T20:08:32.000000Z"
}
],
"links": {
"first": "http://laravel-api.test/api/users?page=1",
"last": "http://laravel-api.test/api/users?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"links": [
{
"url": null,
"label": "« Previous",
"active": false
},
{
"url": "http://laravel-api.test/api/users?page=1",
"label": "1",
"active": true
},
{
"url": null,
"label": "Next »",
"active": false
}
],
"path": "http://laravel-api.test/api/users",
"per_page": 15,
"to": 1,
"total": 1
}
}
using AsyncThunk for getting data from API services/userService file
import { createAsyncThunk} from "#reduxjs/toolkit";
import axios from "axios";
import { API_URL, ACCESS_TOKEN } from "../constants";
export const fetchUsers = createAsyncThunk(
'user/fetchUsers',
async (page) => {
const data = await axios(API_URL+'/users?page='+page,
{ method:'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${ACCESS_TOKEN}`
},
});
return data.data;
}
)
features/userSlice.js
import { createSlice, createEntityAdapter } from "#reduxjs/toolkit";
import { HTTP_STATUS } from "../constants";
import { fetchUsers } from "../services/userService";
const userAdapter = createEntityAdapter({
selectId: (user) => user.id,
});
const userSlice = createSlice({
name: "user",
initialState: {
loading: false,
status: null,
message: "",
},
reducers:{
pageByNumber: (state,{payload}) => {
state.page = payload.page
},
nextPage: (state, {payload}) => {
state.page = state.page++
},
previousPage: (state, {payload}) => {
state.page = state.page--
},
clear: (state) => {
state.status = null
state.message = null
}
},
extraReducers: {
[fetchUsers.pending]: (state, action) => {
state.loading = true
state.status = HTTP_STATUS.PENDING
},
[fetchUsers.fulfilled]: (state, { payload }) => {
console.log(payload.data);
state.loading = false
state.page = payload.meta.current_page
state.total_pages = Math.ceil(payload.meta.total/payload.meta.per_page)
userAdapter.setAll(state, payload.data)
state.status = HTTP_STATUS.FULFILLED
},
[fetchUsers.rejected]: (state, { payload }) => {
state.loading = false
state.status = HTTP_STATUS.REJECTED
},
},
});
export const userSelectors = userAdapter.getSelectors(
(state) => state.user
)
export const {pageByNumber, nextPage, previousPage,clear} = userSlice.actions
export default userSlice.reducer
views/users/index.js
i am not getting understand why there is map array error.
Hi i got the answer actually i had not passed my initial state to create Entity Adapter, below i have shown latest code for initial state.
initialState: userAdapter.getInitialState({ //Initial state should be wrapped in Adapter
loading: false,
status: null,
message: "",
}),

Normalizr with Redux with nested array of objects

I'm just getting started with using normalizr with Redux, and I can't make it work. Even though I can do it with plain JavaScript.
I have an array of objects
const data = [
{
data_detail: [
{
category: 'newCategory',
_id: '123',
},
],
_id: 'abc_id',
customer: {
_id: '456',
email: 'hello#gmail.com',
name: 'Bob',
},
date: '2021-01-10T01:51:24.387Z',
},
];
And I need to transform it to
const normalizedResponse = {
customers: {
'456': {
_id: '456',
email: 'hello#gmail.com',
name: 'Bob',
},
},
details: {
'123': {
category: 'newCategory',
_id: '123',
},
},
orders: {
'abc_id: {
order_detail: [123],
_id: 'abc_id',
customer: '456',
date: '2021-01-10T01:51:24.387Z',
},
},
};
Step 1: Display just orders
What I do:
const userSchema = new schema.Entity(
'orders',
);
const userListSchema = new schema.Array(userSchema);
const normalizedData = normalize(data, userListSchema);
What I get
{
"entities": {
"orders": {
"abc_id": {
"data_detail": [
{
"category": "newCategory",
"id": "123"
}
],
"id": "abc_id",
"customer": {
"id": "456",
"email": "hello#gmail.com",
"name": "Bob"
},
"date": "2021-01-10T01:51:24.387Z"
},
"abc_id-02": {
"data_detail": [
{
"category": "newCategory1",
"id": "123-02"
}
],
"id": "abc_id-02",
"customer": {
"id": "456-02",
"email": "hello#gmail.com",
"name": "Bob"
},
"date": "2001-01-10T01:51:24.387Z"
}
}
},
"result": [
"abc_id",
"abc_id-02"
]
}
What I'm trying to get:
orders: {
'abc_id: {
order_detail: [123],
_id: 'abc_id',
customer: '456',
date: '2021-01-10T01:51:24.387Z',
},
},
The question: How to remove some fields from orders and add new ones?
You have 3 different entity types in your data object. First draft out a schema for each of them:
const detail = new schema.Entity('details');
const customer = new schema.Entity('customers');
const order = new schema.Entity('orders');
Then go back and fill in the relationships. It looks like order is the outermost entity. An order contains an array of details/categories and a single customer.
const order = new schema.Entity('orders', {
data_detail: [detail],
customer,
});
All of your entities use _id instead of id, so you need to set the idAttribute.
Your data is an array of order. You can use new schema.Array(order) but you can also just use [order].
Here's your final code:
const customer = new schema.Entity("customers", {}, { idAttribute: "_id" });
const detail = new schema.Entity("details", {}, { idAttribute: "_id" });
const order = new schema.Entity(
"orders",
{
data_detail: [detail],
customer
},
{ idAttribute: "_id" }
);
const normalizedData = normalize(data, [order]);
That gives you:
{
"entities": {
"details": {
"123": {
"category": "newCategory",
"_id": "123"
}
},
"customers": {
"456": {
"_id": "456",
"email": "hello#gmail.com",
"name": "Bob"
}
},
"orders": {
"abc_id": {
"data_detail": ["123"],
"_id": "abc_id",
"customer": "456",
"date": "2021-01-10T01:51:24.387Z"
}
}
},
"result": ["abc_id"]
}

Redux action (fetch from db) not firing when useEffect() is called

I am trying to build an eCommerce website to learn Redux.
At the moment I am trying to fetch the categories when the component mounts. Since I am using functional components, I understood that this is achieved by calling the useEffect() method.
Also, I am using json-server as a REST Api.
I am quite sure I have managed to compose my enhancers to pass to the store (dev tools and thunk), created actions, reducers and all.
My problem is that the action doesn't fire when the component mounts.
N.B. before introducing the Middleware and therefore the fetch request, everything worked just fine. Also consider that the fetch request is successful.
Hereafter is the code involved.
'src/index.js'
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { createStore, applyMiddleware, compose } from 'redux'
import { Provider } from 'react-redux'
import rootReducer from './reducers'
import thunk from 'redux-thunk'
const composedEnhancers = compose(applyMiddleware(thunk), window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__())
const store = createStore(
rootReducer, /* preloadedState, */
composedEnhancers
);
ReactDOM.render(
<Provider store={store}>
<React.StrictMode>
<App />
</React.StrictMode>
</Provider>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
serviceWorker.unregister();
the action type in 'actions/index.js':
export const FETCH_CATEGORIES = 'FETCH_CATEGORIES'
the action creator in 'actions/index.js':
export const fetchCategories = () => (dispatch) => {
fetch("http://localhost:7000/categories")
.then(response => response.json())
.then(categories => {
return {
type: FETCH_CATEGORIES,
payload: categories
}
})
}
'reducers/index.js'
import * as actions from './../actions'
const initState = {
categories: [],
currentCategory: 'any',
toggler: 'hidden'
}
const rootReducer = (state = initState, action) => {
switch (action.type) {
case actions.SELECT_CATEGORY:
return { ...state, currentCategory: action.payload.value }
case actions.FETCH_CATEGORIES:
return { ...state, categories: action.payload }
case actions.TOGGLE:
return { ...state, toggler: action.payload.toggler }
default:
return state
}
}
export default rootReducer
the 'Filter.js' component
import React, { useEffect } from 'react';
import { connect } from 'react-redux'
import { selectCategory, fetchCategories } from '../../../../actions'
const Filter = (props) => {
// const [minPrice, setMinPrice] = useState(0)
// const handleMinPrice = event => {
// setMinPrice(event.target.value)
// }
// const [maxPrice, setMaxPrice] = useState(0)
// const handleMaxPrice = event => {
// setMaxPrice(event.target.value)
// }
// const [department, setDepartment] = useState("select")
// const handleDepartment = event => {
// console.log(event.target.value)
// setDepartment(event.target.value)
// }
// console.log(props);
const handleChange = event => {
event.preventDefault()
props.selectCategory(event.target.value)
}
useEffect(() => {
props.fetchCategories()
})
return (
<div className="filter-form col-12">
<form id="filter-category">
<label htmlFor="category">Category</label>
<select className="col-12" id="category" name="category" size="5" value={props.currentCategory} onChange={(event) => handleChange(event)}>
{props.categories.map(category => <option key={category.value} value={category.value}>{category.name}</option>)}
</select>
</form>
{props.currentCategory !== 'any' && <form id="filter-department">
<label htmlFor="department">Department</label>
<select className="col-12" id="department" name="department" size="5" value='{department}' onChange='{handleDepartment}'>
<option value="select">--- Select ---</option>
<option value="desktop PCs">Desktop PCs</option>
<option value="laptops">Laptops</option>
<option value="gamepads">Gamepads</option>
<option value="headphones">Headphones</option>
<option value="microphones">Microphones</option>
<option value="keyboards">Keyboards</option>
</select>
</form>}
{/* <form id="filter-price">
<label htmlFor="minimum-price">Min. Price: {minPrice}£</label>
<input type="range" min="1" max="100" value={minPrice} className="slider col-xs-12" id="minimum-price" onChange={handleMinPrice} />
<label htmlFor="maximum-price">Max. Price: {maxPrice}£</label>
<input type="range" min="100" max="1000" value={maxPrice} className="slider col-xs-12" id="maximum-price" onChange={handleMaxPrice} />
</form> */}
</div>
);
}
const mapStateToProps = (state) => {
return {
categories: state.categories,
currentCategory: state.currentCategory
}
}
const mapDispatchToProps = (dispatch) => {
return {
selectCategory: (value) => {
dispatch(selectCategory(value))
},
fetchCategories: () => {
dispatch(fetchCategories())
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Filter);
Also, here is 'db.json'
{
"categories": [
{
"id": "1",
"value": "any",
"name": "--- Any ---",
"departments": []
},
{
"id": "2",
"value": "computers-and-accessories",
"name": "Computers and Accessories",
"departments": [
{
"id": "1",
"value": "desktop-pc",
"name": "Desktop PCs"
},
{
"id": "2",
"value": "laptops",
"name": "Laptops"
},
{
"id": "3",
"value": "keyboards",
"name": "Keyboards"
},
{
"id": "4",
"value": "headphones",
"name": "Headphones"
},
{
"id": "5",
"value": "mouses",
"name": "Mouses"
},
{
"id": "6",
"value": "gamepads",
"name": "Gamepads"
}
]
},
{
"id": "3",
"value": "fashion",
"name": "Fashion",
"departments": [
{
"id": "1",
"value": "dresses",
"name": "dresses"
},
{
"id": "2",
"value": "shoes",
"name": "Shoes"
},
{
"id": "3",
"value": "pants",
"name": "Pants"
},
{
"id": "4",
"value": "sunglasses",
"name": "Sunglasses"
},
{
"id": "5",
"value": "handbags",
"name": "Handbags"
},
{
"id": "6",
"value": "hats",
"name": "Hats"
}
]
},
{
"id": "4",
"value": "digital-music",
"name": "Digital Music",
"departments": [
{
"id": "1",
"value": "rock",
"name": "Rock"
},
{
"id": "2",
"value": "pop",
"name": "Pop"
},
{
"id": "3",
"value": "house-and-techno",
"name": "House and Techno"
},
{
"id": "4",
"value": "trap",
"name": "Trap"
},
{
"id": "5",
"value": "indie",
"name": "Indie"
},
{
"id": "6",
"value": "hip-hop",
"name": "Hip-Hop"
}
]
},
{
"id": "5",
"value": "house",
"name": "House",
"departments": [
{
"id": "1",
"value": "kitchen",
"name": "kitchen"
},
{
"id": "2",
"value": "garden",
"name": "Garden"
},
{
"id": "3",
"value": "bedroom",
"name": "Bedroom"
},
{
"id": "4",
"value": "bathroom",
"name": "Bathroom"
},
{
"id": "5",
"value": "livingroom",
"name": "Livingroom"
},
{
"id": "6",
"value": "cleaning",
"name": "Cleaning"
}
]
},
{
"id": "6",
"value": "grocery",
"name": "Grocery",
"departments": [
{
"id": "1",
"value": "vegetables",
"name": "Vegetables"
},
{
"id": "2",
"value": "pasta and rice",
"name": "Pasta and Rice"
},
{
"id": "3",
"value": "snacks",
"name": "Snacks"
},
{
"id": "4",
"value": "canned-food",
"name": "Canned Food"
},
{
"id": "5",
"value": "frozen",
"name": "Frozen"
},
{
"id": "6",
"value": "dairy",
"name": "Dairy"
}
]
}
]
}
What am I missing here?
Try dispatching like this in the action which will fire the reducer FETCH_CATEGORIES:
export const fetchCategories = () => (dispatch) => {
fetch("http://localhost:7000/categories")
.then(response => response.json())
.then(categories => {
// **Changes start here
dispatch ({
type: FETCH_CATEGORIES,
payload: categories
})
// **Changes end here
})
}

how to solve this in javascript?

> Locate the `displayBirthdate` function you initially defined, which took no parameter. Modify it to use object de-structuring to get just the 'dob' property of the parameter object it will receive
here's the code
```javascript
const displayBirthdate = () => {};
const displayAddress = () => {};
const displayExtraUserInfo = (extra) => {
document.getElementById("btn-birthdate").addEventListener("click", ()=>
{ displayBirthdate(extra) })
document.getElementById("btn-phone").addEventListener("click", () =>
{ displayPhone(extra) })
document.getElementById("btn-address").addEventListener("click", () =>
{ displayAddress(extra) })
```
adding to the above question
this is the expected response passed as parameter extra
{
"results": [
{
"gender": "female",
"name": {
"title": "ms",
"first": "ceyhan",
"last": "dizdar"
},
"location": {
"street": "3826 şehitler cd",
"city": "tekirdağ",
"state": "bitlis",
"postcode": 11689,
"coordinates": {
"latitude": "79.1017",
"longitude": "27.1350"
},
"timezone": {
"offset": "+5:45",
"description": "Kathmandu"
}
},
"email": "ceyhan.dizdar#example.com",
"login": {
"uuid": "34eb65b2-0535-4656-bd68-4da69dc6d016",
"username": "orangefish864",
"password": "grandpa",
"salt": "vowzvAS2",
"md5": "cf4a7f3210ef97e8e72defafd80b94c8",
"sha1": "4f2af3439862b9bf25757ee73df8cd410ce201a2",
"sha256":
"1497acbca446b5fa47d4bc5ffe4e82c17818176596b66d94f213f091c8ed8077"
},
"dob": {
"date": "1979-08-10T22:03:55Z",
"age": 39
},
"registered": {
"date": "2008-05-24T13:30:20Z",
"age": 10
},
"phone": "(873)-801-4132",
"cell": "(751)-606-5317",
"id": {
"name": "",
"value": null
},
"picture": {
"large": "https://randomuser.me/api/portraits/women/59.jpg",
"medium": "https://randomuser.me/api/portraits/med/women/59.jpg",
"thumbnail":
"https://randomuser.me/api/portraits/thumb/women/59.jpg"
},
"nat": "TR"
}
],
"info": {
"seed": "008a9fe3a638239b",
"results": 1,
"page": 1,
"version": "1.2"
}
}
Now the question is this:
write an arrow function example displayBirthdate(), pass in this object(extra) as a parameter. using de-structuring method, grab the "dob" property in the object(extra).
below is how i have attempted to solve the question:
const displayBirthdate = (obj) =>{
const{results} = obj;
const[{dob}] = results;
}
but it appears to be incorrect. please any help would be appreciated. thank you
const displayBirthdate = ({dob}) => {};
const displayAddress ({location}) =>{};
In your attempted solution, you were trying to obtain the dob object
from results, but const{results} = obj; evaluates results to
an array. const {dob} = results[0]; in my answer gets the dob object from the first element in the results array. Cheers!
const displayBirthdate = (obj) =>{
const{results} = obj;
const[{dob}] = results;
}
const displayBirthdate = (obj) =>{
const {results} = obj;
console.log(results); // this is an array with the required object at index = 0
const {dob} = results[0];
console.log(dob); // dob is the object you are looking for
}

How to add array of ids to entity that doesn't have them

I have my schema set up almost exactly how I want it in redux state, except I want to add an array of form ids to the formTemplate object.
It would look like this:
// Normalized Form Templates
{
1: {
id: '1',
isGlobal: true,
name: 'Form Template Name',
forms: [1, 2], // This is the line I want to add...but how?
},
}
// Normalized Forms
{
1: {
id: '1',
createdAt: '2016-12-28T23:30:13.547Z',
name: 'Form 1',
parentTemplate: '1',
pdfs: [1, 2],
},
2: {
id: '2',
createdAt: '2016-12-28T23:30:13.547Z',
name: 'Form 2',
parentTemplate: '1',
pdfs: [],
},
}
Here is my schema
import { schema } from 'normalizr'
const formTemplate = new schema.Entity('formTemplates', {}, {
processStrategy: value => ({
id: value.id,
name: value.attributes.title,
isGlobal: value.attributes.is_global,
}),
})
const form = new schema.Entity('forms', {
pdfs: [pdf],
}, {
processStrategy: value => ({
id: value.id,
createdAt: value.attributes.created_at,
name: value.attributes.title,
parentTemplate: value.attributes.form_template_id,
pdfs: [...value.relationships.documents.data],
}),
})
const pdf = new schema.Entity('pdfs')
export default {
data: [form],
included: [formTemplate],
}
This is an example of the API response that I'm normalizing
{
"data": [
{
"id": "5",
"type": "provider_forms",
"attributes": {
"title": "Form 1",
"created_at": "2017-01-02T06:00:42.518Z",
"form_template_id": 1
},
"relationships": {
"form_template": {
"data": {
"id": "1",
"type": "form_templates"
}
},
"documents": {
"data": [ // some pdf data here ]
}
}
}
],
"included": [
{
"id": "1",
"type": "form_templates",
"attributes": {
"title": "Form Template",
"created_at": "2016-12-29T22:24:36.201Z",
"updated_at": "2017-01-02T06:00:20.205Z",
"is_global": true
},
}
]
}
You won't be able to do this with Normalizr because the form template entity has no context back to the forms entities. Your actions/reducer need to handle this.
Okay I figured out a way to do this. I changed my formTemplate entity to map them in manually like so:
const formTemplate = new schema.Entity('formTemplates', {}, {
processStrategy: (value, parent) => {
// eslint-disable-next-line eqeqeq
const childrenForms = parent.data.filter(form => form.attributes.form_template_id == value.id)
return {
id: value.id,
name: value.attributes.title,
isGlobal: value.attributes.is_global,
forms: childrenForms.map(form => form.id),
}
},
})

Resources