so I currently have my router paths set up as such:
{
component: List,
name: "account-list",
path: "list/:id",
// alias: "list/:id/edit_item/:item_id",
children: [
{
path: "edit_item/:item_id",
},
{
path: "*",
redirect: "/account/list/:id"
}
]
}
And let's say we have a url like this: http://localhost:8080/#/account/list/5bb17bdec7fb946609ce8bd4/edit_item/5bbc2d12aded99b39c9eadb9
How would I turn this into:
http://localhost:8080/#/account/list/5bb17bdec7fb946609ce8bd4
I am currently using
this.$router.back()
Which generally works well, but if I were to have accessed another item by directly pasting in its url, this.$router.back() would just revisit the previous url.
So is there a surefire way to guarantee that I would remove the child path?
Vue router will maintain current params when navigating so you should be able to navigate to the named parent route.
For example
this.$router.push({ name: 'account-list' })
The current :id param will be re-used.
If you wanted to make it dynamic, you could work your way up the current route's matched array. For example, to go to the current route's named parent
this.$router.push({
name: this.$route.matched[this.$route.matched.length - 2].name
})
This will only work on nested routes of course as the matched length for top-level routes is only 1.
For non-named routes you must construct the full path with all params interpolated into the string. You could do it by getting the destination routes path property and substituting param tokens with those in this.$route.params but that's going to get messy. Eg
// get parent path property
let path = this.$route.matched[this.$route.matched.length - 2].path
let realPath = path.replace(/:\w+/g, param =>
this.$route.params[param.substr(1)])
this.$router.push(realPath)
This won't work if your paths use advanced pattern matching.
You can move your child route up one level, so that it is not a child anymore. That way the id would show up in the this.$router.params object.
[
{
path: 'list/:id',
component: List,
name: "account-list"
},
{
path: 'list/:id/edit_item/:itemid',
component: Form,
name: "account-form"
}
]
You can do a do a $router.replace to replace the current path.
const id = this.$router.params['id'];
this.$router.replace({
name: 'account-form',
params: { id }
})
Store your list id 5bb17bdec7fb946609ce8bd4 in localStorage and get that localStorage in route script file.And add it your redirect path. For ex:
var listId = localStorage.getItem('listId');
// routh obj
{
component: List,
name: "account-list",
path: "list/:id",
// alias: "list/:id/edit_item/:item_id",
children: [
{
path: "edit_item/:item_id",
},
{
path: "*",
redirect: "/account/list/" + listId
}
]
}
get the list's id first before replacing the route.
let currentId = this.$route.params.id
this.$router.replace({
name: 'list',
params: { id: currentId }
})
also, it would be better if you name your sub routes.
Related
I am creating a breadcrumb nav similar to app.box.com with mongo, express and react. The bread crumb on that website doesn't use URI to create the breadcrumb. For example if /home/level1/level2/level3 is the breadcrumb and I click on level2 the request made to server is /folder/{folder_id} instead of /home/level1/level2 and the breadcrumb truncates to /home/level1/level2. To achieve this, how to structure the data in mongodb? And how to handle it in react to create the breadcrumb while making sure that it will work between refresh?
If I create a schema like
{ _id: "asdfasdf", name: "level2", type: "folder", path: "/home/level1/level2" }
and then in react split the path into an array to create a breadcrumb then I won't be able to make /folder/{folder_id} GET requests.
I can ignore the path, create an empty array state and then add path and URL to array. For example after initializing an empty array state, if I click on level1 button then { name: "level1", URL: "/folder/level1-id" } will be added to the array. Then I can use that array to construct breadcrumb. But this won't survive page refresh. Psuedo-code is as follows,
const [pathArr,setPathArr] = useState([]);
// Make initial request to /home
// add { name: "Home", URL: "/folder/0" } to pathArr
// parsed breadcrumb will /home
// display files and folders received
// click on level1 folder button
// Push { name: "level1", URL: "/folder/level1_id" } to pathArr
// parsed breadcrumb will /home/level1
// Do same for level2, pathArr = [ {home obj},{level1 obj}, {level2 obj} ]
// Click on level1 breadcrumb
// pathArr = [ { home object }, { level1 object } ]
}
Any other suggestion on mongodb schema or react nav are appreciated.
I am attempting to create Gatsby pages programmatically using the Gatsby API createPages and data from Firebase. I've set up everything successfully up to the point where Firebase data is accessible via GraphQL and now I want to query specifict data for each of the new pages that were created using id (which are in string format). However, when I create the template component and try to query the data i get this error:
Variable "$clientId" of type "String!" used in position expecting type "StringQueryOperatorInput".
I have looked everywhere for a reference of this StringQueryOperatorInput and can't find any info on it. Google and graphql docs don't seem to mention the term and this is my first time seeing it. After troubleshooting for an hour I got a different error:
If you're e.g. filtering for specific nodes make sure that you choose the correct field (that has the same type "String!") or adjust the context variable to the type "StringQueryOperatorInput".
File: src/templates/Homeowner/Homeowner.js:24:9
However, I still don't know what a StringQueryOperatorInput is or how to fix this.
Below is my code for this component and my gatsby-node.js, and my gatsby-config.js where i use a plugin to source the Firebase data.
I could really use some help on this, I can't seem to find any reference of this StringQueryOperatorInput.
Everything else works fine, I just can't get this query on the Homeowner.js template to work.
gatsby-node.js
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions;
const result = await graphql(`
query {
allClients {
nodes {
firstName
lastName
id
}
}
}
`);
console.log(JSON.stringify(result, null, 4));
result.data.allClients.nodes.forEach(node => {
const slug = `/client/${node.id}`;
createPage({
path: slug,
component: require.resolve(`./src/templates/Homeowner/Homeowner.js`),
context: { clientId: node.id },
});
});
};
src/templates/Homeowner/Homeowner.js
import React from 'react';
import { graphql } from 'gatsby';
import { withFirebase } from '../../components/Firebase';
import { withStyles } from '#material-ui/core/styles';
import Layout from '../../components/layout';
const Homeowner = ({ data }) => {
console.log(data.clients, 'data');
return (
<>
<Layout>
<h1>Home Owner Component</h1>
{/* <h3>{client.firstName}</h3>
<h3>{client.lastName}</h3>
<h3>{client.email}</h3> */}
</Layout>
</>
);
};
export default Homeowner;
export const query = graphql`
query($clientId: String!) {
clients(id: $clientId) {
firstName
lastName
email
}
}
`;
gatsby-config.js
require('dotenv').config({
path: `.env.${process.env.NODE_ENV}`,
});
module.exports = {
siteMetadata: {
title: `SiteTitle`,
siteUrl: `https://www.mysitwe.com`,
description: `YourSite`,
},
plugins: [
`gatsby-plugin-react-helmet`,
`gatsby-plugin-sitemap`,
`gatsby-plugin-styled-components`,
`gatsby-plugin-sharp`,
`gatsby-transformer-sharp`,
{
resolve: `gatsby-source-firebase`,
options: {
credential: require('./firebase-key.json'),
databaseURL: 'https://firebaseurl/',
types: [
{
type: 'Clients',
path: 'clients',
},
{
type: 'Users',
path: 'users',
},
],
},
},
{
resolve: `gatsby-plugin-prefetch-google-fonts`,
options: {
fonts: [
{
family: `Nunito Sans`,
variants: [`400`, `600`, `800`],
},
{
family: `Montserrat`,
variants: [`300`, `400`, `400i`, `500`, `600`],
},
{
family: `Spectral`,
variants: [`400`, `600`, `800`],
},
{
family: `Karla`,
variants: [`400`, `700`],
},
],
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
`gatsby-plugin-offline`,
],
};
THank you in advance if anyone can help me out.
Actually literally right after I posted this question I found the solution. I needed to set up my query like so:
export const query = graphql`
query($clientId: String!) {
clients(id: { eq: $clientId }) {
firstName
lastName
email
}
}
`;
I assume that leaving out the {eq: $clientId} throws that StringQuery error on the GraphQL side. I still do not know what a StringQueryOperatorInput is, however, I have successfully generated the pages with the data from firebase.
StringQueryOperatorInput is the type of the id argument of the clients field. GraphQL includes scalar types like String, ID or Int as well as types that describe more complex data structures like arrays or objects. In this case, StringQueryOperatorInput is an input object type -- it describes objects that can be used as inputs like argument values or variables.
When filtering fields, Gatsby uses an input object like this to enable using a variety of comparison operators to filter the exposed data -- in addition to eq (equals), you can use other operators like ne, regex, in, gt, etc. You can see the full list here. Because not all inputs apply to all scalars (regex makes sense for a String field but lte does not), there's a different input type for each scalar (IntQueryOperatorInput, BooleanQueryOperatorInput, etc.)
Gatsby exposes a GraphiQL endpoint in development. Writing queries using GraphiQL allows you to utilize autocomplete and syntax highlighting so that you can avoid unexpected syntax errors like this. You can also use the "Docs" button to search and browse the entire schema.
I am trying to Navigate to a new page on click of an icon and below is the code
this.prj = e.data.project_number;
this.router.navigateByUrl('/dashboard/ProjectShipment/634');
Instead of this hardcoded query parameter 000634 I have to pass a this.prj in to it. My path is like below
const appRoutes: Routes = [
{
path: 'dB',
data: { title: 'Dashboard' },
children: [
{
path: 'ProjectShipment/:reportProject',
component: ProjectShipmentComponent,
data: { title: 'Project Shipment' },
}
You can use 'router.navigate' instead 'router.navigateByUrl':
this.router.navigate([URL],{ queryParams: { id: this.prj });
Simply use string interpolation
this.router.navigateByUrl(`/dashboard/ProjectShipment/${this.prj}`);
// Set our navigation extras object
// that passes on our global query params and fragment
let navigationExtras: NavigationExtras = {
queryParams: {...},
state: {...}
};
// Redirect the user
this.router.navigateByUrl(redirect, navigationExtras);
NavigationExtras docs
EDIT: https://stackoverflow.com/a/44865817/5011818 this is also worth to look at
this.router.navigate(['/route1'], { variable1: "Value" });
this.router.navigateByUrl('/route1', { variable1: "Value" });
Please none: if your url is urlencoded use navigateByUrl, if your url is not urlencoded use navigate
I have a page, there are three iframes in this page(I have to use iframe) and they will be displayed at the same time. In these iframes, I set specified the url comes from a SPA page. such as:
routes: [
{
path: '/',
name: 'air',
component: () => import('#/views/dashboard/index.vue'),
children: [
{
path: '/top',
name: 'airTop',
component: () => import('#/views/dashboard/top.vue')
},
{
path: '/left',
name: 'airLeft',
component: () => import('#/views/dashboard/left.vue')
},
{
path: '/right',
name: 'airRight',
component: () => import('#/views/dashboard/right.vue')
}
]
}
]
When I change some values in top iframe, I find the left one and the right one will not be changed. I realize that the different iframe will get a new Vue instance, so the value won't be shared.
My question: Is there any way can share the value in different iframe at the same time. Using sington?
I'm new to Vue and have been working on a demo project and I can't seem to understand how routes with query parameters work. I noticed in the documentation that they recommend router.push({ path: 'register', query: { plan: 'private' }}) which would produce /register?plan=private.
Is there a way to do this with nested routes?
I'm trying to achieve this as the URL for the BookAppointment component: /physicians/?appt_id=12345&npi=123456789. If there is a better way to do this I'm open to suggestions. Thanks in advance.
router/index.js
const router = new VueRouter({
routes: [
{ path: '/physicians/', component: PhysicianLanding,
children: [
{
// PhysicianProfile
path: 'profile/:url',
component: PhysicianProfile
},
{
// BookAppointment has 3 different progress steps to get to
// the confirm page
path: '',
query: { appt_id: '12345', npi: '123456789'},
component: BookAppointment
}
]
}
]
})
const router = new VueRouter({
routes: [
{ path: '/physicians/', component: PhysicianLanding,
children: [
{
// PhysicianProfile
path: 'profile/:url',
component: PhysicianProfile
},
{
// BookAppointment has 3 different progress steps to get to
// the confirm page
path: '',
//query: { appt_id: '12345', npi: '123456789'}, // not required here.
component: BookAppointment
}
]
}
]
})
To go to BookAppointment Component with URL as -> /physicians/?appt_id=12345&npi=123456789, you may need to make a button/link in the vue-template with following #click event:
<button
#click="$router.push({ path: '/physicians/', query: {
appt_id: 12345,
npi: 123456789
}})"
>
GO TO: Book Appointment
</button>
OR
<button
#click="$router.push({ path: '/physicians/?appt_id: 12345&npi: 123456789})"
>
GO TO: Book Appointment
</button>
You can change the query values, still, BookAppointment component will be rendered.
Eg. /physicians/?appt_id: 123456&npi: 1234567890 Will also render the BookAppointment Component.
You can use the different query value to fetch different data from the database & render it on the same base template.