Curtis Olson
Curtis Olson

Reputation: 315

List view throwing TypeError

What you were expecting: Just went through the tutorial (successfully) and tried to modify code to use my API. List view is not showing data and console has error.

I was able to add the API call for login and on the list view I can see my API is successfully called.

What happened instead: Page shows title and "No results found"

Console error

index.js:2178 uncaught at handleFetch TypeError: newRecords.map is not a function
    at http://localhost:3001/static/js/bundle.js:69772:52
    at http://localhost:3001/static/js/bundle.js:69828:24
    at http://localhost:3001/static/js/bundle.js:69917:40
    at Array.reduce (<anonymous>)
    at ./node_modules/ra-core/lib/reducer/admin/resource/index.js.exports.default (http://localhost:3001/static/js/bundle.js:69914:30)
    at combination (http://localhost:3001/static/js/bundle.js:134671:29)
    at combination (http://localhost:3001/static/js/bundle.js:134671:29)
    at resettableAppReducer (http://localhost:3001/static/js/bundle.js:63329:16)
    at dispatch (http://localhost:3001/static/js/bundle.js:134907:22)
    at http://localhost:3001/static/js/bundle.js:119507:18
    at http://localhost:3001/static/js/bundle.js:132848:22
    at dispatch (http://localhost:3001/static/js/bundle.js:134462:18)
    at http://localhost:3001/static/js/bundle.js:134352:12
    at http://localhost:3001/static/js/bundle.js:133375:52
    at exec (http://localhost:3001/static/js/bundle.js:134015:5)
    at flush (http://localhost:3001/static/js/bundle.js:134056:5)
    at asap (http://localhost:3001/static/js/bundle.js:134029:5)
    at runPutEffect (http://localhost:3001/static/js/bundle.js:133372:69)
    at runEffect (http://localhost:3001/static/js/bundle.js:133321:307)
    at next (http://localhost:3001/static/js/bundle.js:133201:9)
    at currCb (http://localhost:3001/static/js/bundle.js:133274:7)

API Response Data from DevTools (Couldn't figure out how to format the data so it's a screen cap.) API Response

API Response from Postman

{
"matches": [
    {
        "id": 1,
        "status": "DRAFT"
    },
    {
        "id": 2,
        "status": "DRAFT"
    },
    {
        "id": 3,
        "status": "DRAFT"
    },
    {
        "id": 4,
        "status": "READY"
    },
    {
        "id": 5,
        "status": "DRAFT"
    },
    {
        "id": 6,
        "status": "DRAFT"
    },
    {
        "id": 7,
        "status": "DRAFT"
    }
]

}

Response Headers

Access-Control-Allow-Origin: * 
Access-Control-Expose-Headers: Content-Range 
Connection: keep-alive 
content-range: matches 0-5/5 
Date: Fri, 20 Jul 2018 16:33:12 GMT 
ETag: W/"a5-KZYtsf9f1aSutDA6i7vGzddXNZk" 
X-Powered-By: Express 

Matches.js code

import React from 'react';
import { List, Edit, Create, Datagrid, ReferenceField, TextField, EditButton, DisabledInput, LongTextInput, ReferenceInput, SelectInput, SimpleForm, TextInput } from 'react-admin';

export const MatchList = (props) => (
    <List {...props}>
        <Datagrid>
            <TextField source="id" />
            <TextField source="status" />
        </Datagrid>
    </List>
);

The tutorial was using the dummy api and I switched to ra-data-simple-rest. I had to make a few changes to my API output to match the format expected, so I'm guessing this might be the source of the problem, but the error is not helpful.

I originally had many columns and some were null, so I just left ID and Status. I do have 1 additional field returned in my results ("success": true). I removed that but got the same results.

Other information:

Environment

Upvotes: 2

Views: 1324

Answers (1)

Christiaan Westerbeek
Christiaan Westerbeek

Reputation: 11137

The output of your API is still not an immediate array. Either you alter your API a bit more or you alter your dataProvider.

Option A: The server-side solution

Alter your API to output:

[
    {
        "id": 1,
        "status": "DRAFT"
    },
    {
        "id": 2,
        "status": "DRAFT"
    },
    ...
]

You don't need the success property* if your leveraging HTTP statuses that can tell the client whether the server succeeded or not (200, 404, 500, etc). You also don't need the total property, since your API is already telling that to the client in the Content-range response header.

Content-range: matches 0-5/5
                           ^ total

Option B. The client-side solution

You're probably using some form of a Dataprovider which is a ra-something-client. It probably has a part that looks similar to this.

const convertHTTPResponseToREST = (response, type, resource, params) => {
    const { headers, json } = response;

    switch (type) {
        case GET_LIST:
        case GET_MANY_REFERENCE: {
            if (!headers.has('content-range')) {
                throw new Error(
                    'The Content-Range header is missing in the HTTP Response. ' +
                        'The PostgREST client expects responses for lists of resources to contain ' +
                        'this header with the total number of results to build the pagination. ' +
                        'If you are using CORS, did you declare Content-Range in the ' +
                        'Access-Control-Expose-Headers header?'
                );
            }
            return {
                data: json.slice(),
                total: parseInt(
                    headers
                        .get('content-range')
                        .split('/')
                        .pop(),
                    10
                ),
            };
        }
        case CREATE:
            return { data: { ...params.data, id: json.id } };
        case DELETE:
            return { data: {} };
        default:
            return { data: json };
    }
};

You can change a part of it to:

return {
    data: json.data.slice(),
    total: json.total || parseInt(
        headers
            .get('content-range')
            .split('/')
            .pop(),
        10
    ),
};

Or just:

return json;

* You may be used to sending the success property due to some Sencha/Ext JS clients. I know I was.

Upvotes: 1

Related Questions