So I'm trying to essentially have two lists on one screen, I have a wizard and in this step I'm linking entities, such as adding users to a profile
I used Use <List /> on React-Admin dashboard as a starting point, and then gave the entities different names, but still don't know how to do this. Basically the modal shouldn't be tied to the url, just a list of users that can be added to the profile, and then behind this modal is the list of users in that profile
initPropsLinkDeviceList = {
basePath: "/profiles/create/link-devices",
hasCreate: false,
hasEdit: false,
hasList: true,
hasShow: false,
history: {},
location: { pathname: "/profiles/create/link-devices", search: "", hash: "", state: undefined },
match: { path: "/profiles/create/link-devices", url: "/profiles/create/link-devices", isExact: true, params: {} },
options: {},
unlinked: "true",
permissions: null,
resource: "profile-users-unlinked",
listactions: null,
profileId: null,
}
In customRoutes:
<Route exact path="/profiles/create/:id/:step" component={ProfileWizard} />,
In App:
<Admin>
<Resource name="profile-devices" />
<Resource name="profile-devices-unlinked" />
ProfileDevices.js
componentDidMount() {
var initProps = {
basePath: `/profiles/create/${this.props.match.params.id}/link-devices`,
hasCreate: false,
hasEdit: false,
hasList: true,
hasShow: false,
history: {},
location: { pathname: `/profiles/create/${this.props.match.params.id}/link-devices`, search: "", hash: "", state: undefined },
match: { path: `/profiles/create/${this.props.match.params.id}/link-devices`, url: `/profiles/create/${this.props.match.params.id}/link-devices`, isExact: true, params: {} },
options: {},
unlinked: "true",
permissions: null,
resource: "profile-devices",
profileId: this.props.match.params.id,
listactions: <ProfileDevicesListActions profileId={this.props.match.params.id} />
}
this.setState({ 'initProps': initProps })
}
render() {
const {
initProps
} = this.state;
if (!initProps) {
return false;
}
return (
<DevicesList {...initProps} {...this.props} />
);
}
DevicesList:
<List {...this.props}
perPage={10}
filters={<DeviceSearchFilter />}
actions={this.props.listactions}
bulkActionButtons={<DeviceBulkActions />} filterDefaultValues={
{
id: 1,
unlinked: this.props.unlinked,
profileId: this.props.profileId
}}>
Then I have the same initProps in LinkAction(the modal dialog)
In my dataprovider I've mapped both resources to the same api, so one just adds a filter to show all vs show specific to profileId
The two resources seem to be clashing even though they are different resources in redux, assuming this is due to the url routing, essentially I suppose I need the in the modal to not be tied to the url.
Thanks
Just to add I realise I could probably achieve this by manually just calling dataProvider and handling them separately such as the demo dashboard, but wanted to get the 'magic' benefits of filter,paginiation etc.
The two resources seem to be clashing even though they are different resources in redux, assuming this is due to the url routing, essentially I suppose I need the in the modal to not be tied to the url.
You're right about that. The List component is indeed tightly coupled to the url so having two of them inside the same page is not supported (see https://github.com/marmelab/react-admin/issues/2903).
We don't have an answer for those cases yet and you'll have to implement your own List component for now.
Related
I recently deployed our Docusaurus site for the first time and I am running into a weird issue with routing.
Every page in the /docs folder will briefly render the 404.html page when hitting the page directly. However, if I click around in sidebar the pages render properly.
This only happens in the /docs folder. If I click on the home page link I do not see the 404.
I cannot replicate this issue locally. I have tried both yarn start and yarn build/serve and in both cases the app works fine. I do not see any 404s, console errors, etc. The response payload of the 404 is the OOTB Docusaurus page, I have not done any customization to it or how its handled.
Attached is a gif showing the behavior and a screen shot showing that the browser is seeing a hard 404 in my non-localhost environment.
And here's my config file:
// #ts-check
// Note: type annotations allow type checking and IDEs autocompletion
const lightCodeTheme = require('prism-react-renderer/themes/github');
const darkCodeTheme = require('prism-react-renderer/themes/dracula');
/** #type {import('#docusaurus/types').Config} */
const config = {
title: 'Guidebook',
tagline: 'Engineering Information',
url: 'https://guidebook.our-internal-domain.tools/',
baseUrl: '/',
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'throw',
favicon: 'img/favicon.png',
organizationName: 'Guidebook',
projectName: 'Guidebook',
presets: [
[
'classic',
/** #type {import('#docusaurus/preset-classic').Options} */
({
docs: {
sidebarPath: require.resolve('./sidebars.js'),
editUrl: 'https://git.our-internal-domain.com/tech-standards/tech-guidebook'
},
blog: false,
theme: {
customCss: require.resolve('./src/css/custom.css')
}
// debug: true
})
]
],
themeConfig: {
navbar: {
title: 'Home',
logo: {
alt: 'Home',
src: 'img/TechnologyGuidebook-Icon_Red_Small.svg'
},
items: [
{
type: 'doc',
docId: 'intro',
position: 'left',
label: 'Guidebook'
},
{
href: 'https://git.our-internal-domain.com/tech-standards/tech-guidebook',
label: 'GitHub',
position: 'right'
}
]
},
footer: {
style: 'dark',
links: [
{
title: 'Community',
items: [
{
label: 'Stack Overflow',
href: 'https://stackoverflow.com/questions/tagged/docusaurus'
}
]
},
{
title: 'More',
items: [
{
label: 'GitHub',
href: 'https://github.com/facebook/docusaurus'
}
]
}
],
copyright: `Copyright © ${new Date().getFullYear()} Guidebook V2, Inc. Built with Docusaurus.`
},
prism: {
theme: lightCodeTheme,
darkTheme: darkCodeTheme
}
}
};
module.exports = config;
I figured it out. It wasn't a Docusaurus problem. The problem was a configuration issue in our CloudFront infrastructure.
I am using Vercel to deploy a Docusaurus V2 website and was running into the same issue with redirects.
Fixed this issue by enabling cleanUrls inside my vercel.json config.
I have a vuetify table. Right now, I call API for all records and load all records into my table. I might not see the performance differences now because it's less than 1000. When I have 10,000,000 this might not work anymore. I need to only query for the first 10 on page loads, and my BE API already supports that. Then, I will make calls to API to get the next/previous 10 only when the user clicked on the pagination buttons.
data() {
return {
headers: [
{
text: 'Name',
align: 'start',
sortable: false,
value: 'name',
width: '20%'
},
{ text: 'Link Count', value: 'count', width: '10%' },
{ text: 'URL', value: 'details', width: '50%' },
{ text: 'Actions', value: 'id', width: '20%' }
],
items: []
}
},
and I set this.items to the response from API below :
axios.defaults.headers['Content-Type'] = 'application/json'
axios
.post(window.MTS_URL, vc_url_group)
.then((response) => {
this.items = response.data.groups
})
Can someone please get me started?
It's highly depends on your backend implementation, but there are some common points:
You should define v-data-table this way:
<v-data-table
:headers="headers"
:items="desserts"
:items-per-page="10"
:server-items-length="totalDesserts"
:options.sync="options"
></v-data-table>
So you need to operate with three variables:
desserts as a [1..10] rows on your current page,
totalDesserts as a total amount of rows (10,000,000 in your case)
options as a synchronize point of your pagination
These variables comes from an example of official docs.
After that, in order to track user click on pagination buttons, you need to define a deep watcher (it should be deep in order to react to changes in nested props):
watch: {
options: {
handler() {
this.getDessertsFromApi();
},
deep: true
},
},
And then - your API call method:
methods: {
async getDessertsFromApi() {
this.loading = true;
const { sortBy, sortDesc, page, itemsPerPage } = this.options;
// Your axios call should be placed instead
await this.simulateApiCall({
size: itemsPerPage,
page: page - 1,
})
.then((response) => {
this.desserts = response.data.content;
this.totalDesserts = response.data.totalElements;
})
.finally(() => {
this.loading = false;
});
},
}
Test this at CodePen with simulated API calls.
When I navigate to my dynamic components trough navigation bar, vue-meta title, content, and schema are displayed correctly, but when I refresh the page or click on the external link I get a value of undefined.
i have stored title content and schema in the json file.
metaInfo() {
return {
title: `${this.seoTitle}`,
meta: [
{name: "robots", content: "index,follow"},
{
name: 'description',
content: `${this.seoContent}`
}
],
link: [
{rel: 'favicon', href: 'logo.ico'}
],
script: [{
type: 'application/ld+json',
json: this.markups
}]
}
},
data() {
return {
seoTitle: this.$route.params.title,
seoContent: this.$route.params.content,
markups:this.$route.params.markup,
}
}
<div class="landing-group-tours box" v-for="tour in boatTours" :key="tour.id">
<router-link
:to="{name: 'details', params:{id: tour.id, title: tour.seoTitle, content: tour.seoContent, markup:tour.markup}}">
</div>
<script>
import tours from '#/data/privateToursData.json'
export default{
data(){
return{
boatTours: tours
{
}
}
</script>
You should store the router parameters in the router itself or in the URL, not the link. What you do is passing objects internally when you click the link, but as you noticed, when you click the browser refresh button these params are gone.
What happens is that Vue will load the app and router, identify what components are responsible for rendering the route and pass the detected parameters from your router to the components. Hence losing any additional data you had in your link before.
Try to keep only the dynamic params in your router and load the rest in the component, based on app logic. I.e. Assuming your route looks like /details/:id, you should initialize the SEO params in your details component.
Typically these come from the backend and for faster access I would transform the array to literal object and access the record by key. I.e. transform the array from:
[
{ "id": 1008; "title": "title1", "content": "....", ... },
{ "id": 1009, "title": "..."... }
]
to
{
"1008": { title: "title1", content: "....", ... },
"1009": { .... }
}
and then store it in VueX (https://vuex.vuejs.org/guide/getters.html)
getters: {
// ...
getBoatTour: (state) => (id) => {
return state.boatTours[id] || { title: 'Not found', content: '......' }
}
}
data() {
const SEOdata = store.getters.getBoatTour(this.$route.params.id);
return {
seoTitle: SEOdata.title,
seoContent: SEOdata.content,
markups: SEOdata.markup,
}
}
I am trying to generate dynamic data table through Vuetify ,in vuejs but dont see any example in vuetify official documentation,does anyone mind sharing an example
By "dynamic" I'm guessing you mean data loads asynchronously from an API. The Vuetify docs have numerous examples of data tables including one that simulates requesting data from an API. A very basic implementation looks something like (note: this example uses the random user generator API:
<template>
<v-data-table
:headers="headers"
:items="people"
item-key="login.uuid"
:loading="loading"
:options.sync="options"
:server-items-length="totalPeople"
#pagination="updatePage"
#update:options="customSort"
></v-data-table>
</template>
<script>
import axios from 'axios'
export default {
data: () => ({
apiURL: 'https://randomuser.me/api/',
headers: [
{ text: 'Name', value: 'name', align: 'start' },
{ text: 'Country', value: 'country' },
{ text: 'DOB (Age)', value: 'dob' },
{ text: 'Contacts', value: 'contacts' },
],
loading: false,
options: {
page: 1,
itemsPerPage: 10,
sortBy: ['name'],
sortDesc: [true],
},
people: [],
}),
mounted () {
this.getPeople()
},
methods: {
async getPeople (page = 1, results = 10, seed = 'example') {
this.loading = true
const params = { params: { page, results, seed } }
try {
this.people = (await axios.get(this.apiURL, params)).data.results
this.loading = false
} catch (error) {
console.log(error)
this.loading = false
}
},
updatePage (pagination) {
const { itemsPerPage: results, page } = pagination
this.pagination = pagination
this.getPeople({ page, results })
},
customSort (options) {
// The Random User API does NOT support sorting, but if it did, you
// would need to make an API call that returned a sorted
// list of results based on the sort parameter(s)
console.log(options)
},
},
}
</script>
For a more complex example that uses more of Vuetify's features, check out this codepen.
I would like to passe an Id from my component to another that is not related as parent or child.
I'm on a profile page and by clicking on a button it brings me to a message page.
The way I do to go to another page :
this.$router.push({ name: `messages_new` });
On my message component I should receive the ID of the contact in this props :
props: {
sendTo: {
type: Object,
default: () => ({
to: []
}),
description: 'Pre fill the send field with this receivers formatted {contact, type}'
}
},
I tried this way as try exemple to see if datas are passing, from contact page component to the message component :
data(){
sendTo: {
to: [{
contact: {
email: 'exemple#9online.fr',
first_name: 'exemple',
last_name: 'exemple',
_id: '12'
},
type: 'contacts'
}]
}
}
`this.$router.push({ name: `message_new`, params: { sendTo: this.sendTo} });`
But it's not working, is there something wrong in what I do, am I forgetting something or is it just totally the wrong way ?
[EDIT]
My route is set like this :
{
name: 'profile',
path: '/profile/:id',
component: Profile,
props: (route) => ({ id: route.params.id || null }),
}
My props is already set with the id of the contact
Just add props: true to your route in your router.js like this:
{ path: '/Profile', name: 'Profile', component: load('ProfileComponent'), props: true}