Closed lsaul closed 5 years ago
Please follow the issue template
What you were expecting: The expected behavior is to create 'Resource' items based on an API call, and dynamically add them to the known Resource array
What happened instead: Admin fails to load and returns TypeError: child.props is undefined on the CoreAdminRouter react element
Steps to reproduce: Please see below code example
Environment react-admin version: 2.9.6 react-dom version: 16.8.6 browser: Firefox Error: TypeError: child.props is undefined
Any ideas on how to resolve are appreciated! The code is below:
import 'babel-polyfill';
import React from 'react';
import { Admin, Resource } from 'react-admin';
import { restClient } from 'ra-data-feathers';
import { Route } from 'react-router-dom';
import feathersClient from './feathersClient';
import englishMessages from 'ra-language-english';
// import customRoutes from './customRoutes';
import { createBrowserHistory as createHistory } from 'history';
import createRealtimeSaga from "./createRealtimeSaga";
import { Contacts } from './services/contacts';
import { Group, GroupMember } from './services/groups';
import { Albums, Photos } from './services/photos';
import UserIcon from '@material-ui/icons/AccountCircle';
import GroupIcon from '@material-ui/icons/Group';
import GroupIcon from '@material-ui/icons/GroupWork';
import StarIcon from '@material-ui/icons/StarRate';
import FolderSpecialIcon from '@material-ui/icons/FolderSpecial';
const authClientOptions = {
storageKey: 'feathers-jwt',
authenticate: { strategy: 'local' }
};
const history = createHistory();
const options = {
usePatch: false, // Use PATCH instead of PUT for UPDATE requests. Optional.
contacts: { // Options for individual resources can be set by adding an object with the same name. Optional.
id: 'ContactId' // If this specific table uses an id field other than 'id'. Optional.
},
group: { // Options for individual resources can be set by adding an object with the same name. Optional.
id: 'GroupId' // If this specific table uses an id field other than 'id'. Optional.
},
groupmember: { // Options for individual resources can be set by adding an object with the same name. Optional.
id: 'GroupMemberID' // If this specific table uses an id field other than 'id'. Optional.
},
albums: { // Options for individual resources can be set by adding an object with the same name. Optional.
id: 'AlbumId' // If this specific table uses an id field other than 'id'. Optional.
},
photos: { // Options for individual resources can be set by adding an object with the same name. Optional.
id: 'PhotoId' // If this specific table uses an id field other than 'id'. Optional.
},
"photos/albums/1/": { // Options for individual resources can be set by adding an object with the same name. Optional.
id: 'AlbumId' // If this specific table uses an id field other than 'id'. Optional.
},
"photos/albums/2/": { // Options for individual resources can be set by adding an object with the same name. Optional.
id: 'AlbumId' // If this specific table uses an id field other than 'id'. Optional.
},
}
const dataProvider = restClient(feathersClient, options)
const realTimeSaga = createRealtimeSaga(dataProvider);
const messages = {
en: englishMessages,
}
const i18nProvider = locale => messages[locale];
const knownResources = [
<Resource name="contacts" list={ContactsList} show={ContactsShow} icon={UserIcon} />,
<Resource name="group" list={GroupList} show={GroupShow} icon={GroupIcon}/>,
<Resource name="groupmember" list={GroupMemberList} show={GroupMemberShow} icon={GroupIcon}/>,
<Resource name="albums" list={AlbumList} show={AlbumsShow} icon={GroupIcon}/>,
<Resource name="photos" list={PhotoList} show={PhotosShow} icon={GroupIcon}/>,
//******************************************************************
//**These resources need to be dynamically Added based on API Call**
//******************************************************************
// <Resource name="photos/albums/1/" list={PublicPhotosList} icon={StarIcon}/>,
// <Resource name="photos/albums/2/" list={PublicPhotosList} icon={StarIcon}/>,
// <Resource name="photos/albums/3/" list={PublicPhotosList} icon={StarIcon}/>,
// etc.
];
// const fetchResources = permissions =>
// fetch('https://myapi/resources', {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json'
// },
// body: JSON.stringify(permissions),
// })
// .then(response => response.json())
// .then(json => knownResources.filter(resource => json.resources.includes(resource.props.name)));
const fetchResources = () =>
fetch('https://jsonplaceholder.typicode.com/albums/hasphotos/true?$limit=10')
.then(function(response){return response.json()})
.catch(error => console.error('Error:', error))
.then(function(schemas){
var filtered = schemas.data
// console.log(schema.data)
return filtered.map((schema, index)=>{
let name = 'photos/album/'+schema.AlbumId
options[name] = {
id: 'AlbumId'
}
var resource;
//Checks if the album has photos
//if so, create the resource
if(schema.albums.length!==0){
resource = <Resource
name={'photos/albums/'+schema.AlbumId}
list={PublicPhotosList}
options = {{
label:schema.AlbumName
}}/>;
knownResources.push(resource);
console.log(knownResources)
}
return knownResources
})
})
.catch(error => console.error('Error:', error))
const App = () => (
<Admin
// authProvider={authClient(feathersClient, authClientOptions)}
restClient={restClient(feathersClient, options)}
dataProvider={restClient(feathersClient, options)}
customSagas={[realTimeSaga]}
locale="en"
i18nProvider={i18nProvider}
// customRoutes={customRoutes}
history={history}
// theme={theme}
>
//{knownResources}
{fetchResources}
</Admin>
);
export default App;
Hi, and thanks for your question. As explained in the react-admin contributing guide, the right place to ask a "How To" question, get usage advice, or troubleshoot your own code, is StackOverFlow.
This makes your question easy to find by the core team, and the developer community. Unlike Github, StackOverFlow has great SEO, gamification, voting, and reputation. That's why we chose it, and decided to keep GitHub issues only for bugs and feature requests.
So I'm closing this issue, and inviting you to ask your question at:
http://stackoverflow.com/questions/tagged/react-admin
And once you get a response, please continue to hang out on the react-admin channel in StackOverflow. That way, you can help newcomers and share your expertise!
Hi fzaninotto, thanks for responding. I posted here because I was hoping to get the attention of the core team, since I haven't heard back stack overflow.
I have to guess that the use case I described is fairly common. If it's not possible to dynamically declare Resources based on an API call, then that would seem to be a significant restriction.
In any case I'll keep working on a solution and post if I figure it out. Thanks.
I'm attempting to add resources based on an API call. I can add knownResources without issues, I can also add fetchedResources on their own - however I cannot combine the two.
The docs show how you can display resources based on permissions queried from the API, but it doesn't detail how to add resources dynamically if they are not declared:
https://marmelab.com/react-admin/Admin.html#declaring-resources-at-runtime
If the two are combined (as below) the CoreAdminRouter throws an error:
TypeError: child.props is undefined
Any ideas on how to resolve are appreciated! The code is below:
If you consider this a support request, here is the question on stack overflow: https://stackoverflow.com/questions/58065717/adding-fetched-resources-to-knownresources-based-on-api-call