Navigating to url: site.com/#locallink 'redirects' to site.com, first time entered in the browser - in other words, does not jump to the anchor.
If I simply re-type the url (site.com/#locallink) then it works as expected (jumps to anchor).
I have defined routes and router like so, and history mode as you can see.
let router = new VueRouter({
mode: 'history',
scrollBehavior: function (to, from, savedPosition) {
if (to.hash) {
return { selector: to.hash }
} else {
return { x: 0, y: 0 }
}
},
routes
});
If I have a link on another page to the same anchor, then it works flawlessly. It's only when typed into the browser directly that it does not seem to work - the # part of it get's eaten.
The routes follow this pattern:
export const routes = [
{
path: '/',
name: 'home',
component: require('components/prelogin/landingpage.vue'),
meta: {
title: 'Some title',
metaTags: [
{
name: 'title',
content: '...'
},
{
name: 'description',
content: 'some description here...'
}
]
}
},
...
There are many entries so only showing first.
Any ideas?
Thanks
Hope it will help
scrollBehavior: function (to, from, savedPosition) {
if (to.hash){
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
selector: to.hash,
behavior: 'smooth',
})
}, 500)
})
} else {
return { x: 0, y: 0 }
}
}
Related
In my project, I want to add some Ajax loaded menu items to my CoreUI sidebar in Vue. I already found a working solution, but it's kind of hacky and might have timing issues. Therefore I want to ask you, if there is a proper or at least better solution.
I also found this question from a few days ago, but it doesn't have an answer yet.
// main.js
new Vue({
el: '#app',
router,
icons,
template: '<App/>',
components: {
App
},
data: {
clientConfiguration: null
},
created: async function () {
let svcResult = await this.$http.get('Picking/ViewerSettings');
this.clientConfiguration = svcResult.data;
this.$children[0].$children[0].$children[0].$data.nav[0]._children[0].items =
svcResult.data.map(vc => ({
name: vc.name,
to: 'test/' + vc.name,
icon: 'cil-spreadsheet'
}));
}
})
// _nav.js
export default [
{
_name: 'CSidebarNav',
_children: [
{
_name: 'CSidebarNavDropdown',
name: 'Lists',
to: '/test',
icon: 'cil-list-numbered',
items: []
},
// ...
]
}
]
The _nav.js file is just an example of data structure that can be rendered by CRenderFunction component docs
The idea behind CRenderFunction is that you can render components from the Array/Object.
In your case, you have two options:
generate CRenderFunction object on backend,
generate CRenderFunction object on frontend by computed properties, based on data you got from the backend
Here is the example of the second approach:
in template
<CRenderFunction flat :content-to-render="navItems"/>
in script:
//example array that you receive from backend
const menuItems = [
{
name: 'first item',
to: '/first',
icon: 'cil-user'
},
{
name: 'second item',
to: '/second'
},
{
name: 'third item',
to: '/third'
}
]
export default {
computed: {
navItems () {
return [
{
_name: 'CSidebarNav',
_children: this.sidebarNavChildren
}
]
},
sidebarNavChildren () {
return menuItems.map(menuItem => {
return {
_name: 'CSidebarNavItem',
name: menuItem.name,
to: menuItem.to,
icon: menuItem.icon || 'cil-spreadsheet'
}
})
}
}
}
navItems computed property result:
[{"_name":"CSidebarNav","_children": [
{"_name":"CSidebarNavItem","name":"first item","to":"/first","icon":"cil-user"},
{"_name":"CSidebarNavItem","name":"second item","to":"/second","icon":"cil-spreadsheet"},
{"_name":"CSidebarNavItem","name":"third item","to":"/third","icon":"cil-spreadsheet"}
]
}]
Using the Flexible Gatsby starter (https://github.com/wangonya/flexible-gatsby/), exact versions of Gatsby dependencies are:
"gatsby": "2.15.36",
"gatsby-image": "2.2.27",
"gatsby-plugin-feed": "2.3.15",
"gatsby-plugin-google-analytics": "2.1.20",
"gatsby-plugin-manifest": "2.2.20",
"gatsby-plugin-offline": "3.0.12",
"gatsby-plugin-react-helmet": "3.1.10",
"gatsby-plugin-sass": "2.1.17",
"gatsby-plugin-sharp": "2.2.28",
"gatsby-remark-images": "3.1.25",
"gatsby-remark-prismjs": "3.3.17",
"gatsby-source-filesystem": "2.1.30",
"gatsby-transformer-remark": "2.6.27",
"gatsby-transformer-sharp": "2.2.20",
I can run gatsby develop to get a watch on the files in the folder that refreshes UI changes and such. However, as soon as I save any changes to any of the files in content/blog develop hits the following error:
info added file at /Users/mattsi/dev/me/newsite/gatsby/content/blog/conference-on-javascript/index.md
ERROR #11321 PLUGIN
"gatsby-node.js" threw an error while running the createPages lifecycle:
The "path" argument must be of type string. Received type undefined
GraphQL request:14:17
13 | title
14 | img {
| ^
15 | childImageSharp {
After that, the local server responds with an error page saying TypeError: Cannot read property 'page' of undefined and a stack trace pointing to rootjs:44. If I kill the watch and do gatsby develop again, it works fine. But that feedback loop is obviously much slower.
My Gatsby Config (some details omitted with ...):
module.exports = {
siteMetadata: {
title: `...`,
description: `...`,
author: `...`,
siteUrl: `...`,
social: {
twitter: `...`,
facebook: ``,
github: `...`,
linkedin: `...`,
email: `...`,
},
},
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/content/blog`,
name: `blog`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/content/assets`,
name: `assets`,
},
},
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
{
resolve: `gatsby-remark-images`,
options: {
maxWidth: 970,
},
},
`gatsby-remark-prismjs`,
],
},
},
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
{
resolve: `gatsby-plugin-google-analytics`,
options: {
//trackingId: `ADD YOUR TRACKING ID HERE`,
},
},
`gatsby-plugin-feed`,
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `...`,
short_name: `...`,
start_url: `/`,
background_color: `#663399`,
theme_color: `#663399`,
display: `minimal-ui`,
icon: `./static/gatsby-icon.png`, // This path is relative to the root of the site.
},
},
// `gatsby-plugin-offline`,
`gatsby-plugin-react-helmet`,
`gatsby-plugin-sass`,
],
}
My gatsby-node.js file:
const path = require(`path`)
const { createFilePath } = require(`gatsby-source-filesystem`)
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions
const blogPost = path.resolve(`./src/templates/blog-post.js`)
return graphql(
`
{
allMarkdownRemark(
sort: { fields: [frontmatter___date], order: DESC }
limit: 1000
) {
edges {
node {
fields {
slug
}
frontmatter {
title
img {
childImageSharp {
fluid(maxWidth: 3720) {
aspectRatio
base64
sizes
src
srcSet
}
}
}
}
}
}
}
}
`
).then(result => {
if (result.errors) {
throw result.errors
}
// Create blog posts pages.
const posts = result.data.allMarkdownRemark.edges
posts.forEach((post, index) => {
const previous = index === posts.length - 1 ? null : posts[index + 1].node
const next = index === 0 ? null : posts[index - 1].node
createPage({
path: post.node.fields.slug,
component: blogPost,
context: {
slug: post.node.fields.slug,
previous,
next,
},
})
})
// Create blog post list pages
const postsPerPage = 10
const numPages = Math.ceil(posts.length / postsPerPage)
Array.from({ length: numPages }).forEach((_, i) => {
createPage({
path: i === 0 ? `/` : `/${i + 1}`,
component: path.resolve("./src/templates/blog-list.js"),
context: {
limit: postsPerPage,
skip: i * postsPerPage,
numPages,
currentPage: i + 1,
},
})
})
})
}
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
if (node.internal.type === `MarkdownRemark`) {
const value = createFilePath({ node, getNode })
createNodeField({
name: `slug`,
node,
value,
})
}
}
Looking into the stack trace, it seems as if the post.node.fields.slug field on the modified post from the allMarkdownRemark GraphQL DB is coming back as undefined. But using the built-in GraphQL browser it seems to always be populated. Perhaps it's very briefly unpopulated while refreshing, faster than I can catch, and this causes the watch to crash? Any ideas how I can fix Gatsby's watch functionality?
I have this issue too and I believe it will be fixed by this PR - it was for me at least. Perhaps you could test it out and comment on the PR if it helps you.
Is it possible to know if route has resolvers or not with router.events?
I tried to find it with:
this.router.events.subscribe(e => {
console.log(e);
})
But it seems that there is no information about resolvers in router events. I need this for progress bar. Maybe ActivatedRoute can be useful in this case? But where exactly should i look? activateRoute.snapshot.data is always empty object
I also tried:
private isRouteHaveResolvers() {
let firstChild = this.activatedRoute.firstChild;
while (firstChild && firstChild.firstChild) {
firstChild = firstChild.firstChild;
}
return firstChild && firstChild.routeConfig && !!Object.keys(firstChild.routeConfig.resolve).length;
}
But it doesnt work properly. For example for this case:
{
path: 'edit',
component: EditComponent,
resolve: {
data: resolverData
},
children: [{
path: 'activity/:activityId',
component: ModalComponent,
outlet: 'modal',
}],
}
For this route activity/:activityId it return true
I have a Nuxt.js, statically generated site that has some dynamic pages. I'm using a GraphQL based headless CMS (DatoCMS) to provide the data for these pages, accessed using Apollo (#nuxt/apollo). I have it generating all the routes correctly but when I navigate to these pages from my site nav I'm receiving the following error 3 times:
TypeError: Cannot read property '_seoMetaTags' of undefined
at f.head (cf150f1920d36ab67139.js:1)
at wn.get (008dfc959ff6e6a713a0.js:2)
at wn.evaluate (008dfc959ff6e6a713a0.js:2)
at f.$metaInfo (008dfc959ff6e6a713a0.js:2)
at f.created (008dfc959ff6e6a713a0.js:2)
at Qt (008dfc959ff6e6a713a0.js:2)
at fn (008dfc959ff6e6a713a0.js:2)
at f.t._init (008dfc959ff6e6a713a0.js:2)
at new f (008dfc959ff6e6a713a0.js:2)
at 008dfc959ff6e6a713a0.js:2
This is coming from the head code in my page component so clearly something isn't being generated correctly. I can also see in the Chrome network tab that calls are being made to the GraphQL interface which also tells me the static generation isn't working correctly.
Here's the head() and apollo portions of my page component:
head() {
return {
title: this.blogPost._seoMetaTags.find(element => {
return element.tag === 'title';
}).content,
meta: [
{ hid: 'keywords', keywords: this.blogPost.keywords },
{ hid: 'description', description: this.blogPost._seoMetaTags.find(element => {
return element.tag === 'meta' && element.attributes.name === 'description';
}).attributes.content}
],
script: [
{ src: 'https://cdn.commento.io/js/commento.js', defer: true }
]
}
},
apollo: {
blogPost: {
query: gpl`
query BlogPost($slug: String!) {
blogPost(filter: { slug:{ eq: $slug }}) {
title
titleColor {
hex
}
slug
author
keywords
_seoMetaTags {
tag
attributes
content
}
_firstPublishedAt
banner {
id
url
title
}
content {
... on HeadingRecord {
_modelApiKey
heading
}
... on SubHeadingRecord {
_modelApiKey
subHeading
}
... on TextRecord {
_modelApiKey
content
}
... on CodeRecord {
_modelApiKey
codeBlock
}
... on ImageRecord {
_modelApiKey
image {
id
height
width
url
title
alt
}
}
... on VideoRecord {
_modelApiKey
video {
height
provider
providerUid
thumbnailUrl
title
url
width
}
}
}
}
}
`,
prefetch({ route }) {
return {
slug: route.params.slug
};
},
variables() {
return {
slug: this.$route.params.slug
};
}
And my nuxt.config.js if it helps:
const pkg = require('./package')
const webpack = require('webpack');
import fetch from 'node-fetch';
import { execute, makePromise } from 'apollo-link';
import { createHttpLink } from 'apollo-link-http';
import gql from 'graphql-tag';
module.exports = {
mode: 'universal',
/*
** Headers of the page
*/
head: {
title: pkg.name,
htmlAttrs: {
lang: 'en'
},
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: pkg.description }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
{ rel: 'stylesheet', href: 'https://cdn.jsdelivr.net/gh/tonsky/FiraCode#1.206/distr/fira_code.css' }
]
},
/*
** Customize the progress-bar color
*/
loading: { color: '#fff' },
/*
** Global CSS
*/
css: [
],
/*
** Plugins to load before mounting the App
*/
plugins: [
],
/*
** Nuxt.js modules
*/
modules: [
'#nuxtjs/style-resources',
'#nuxtjs/apollo',
'#nuxtjs/google-analytics'
],
/*
** #nuxtjs/google-analytics settings
*/
googleAnalytics: {
id: 'UA-136517294-1'
},
/*
** #nuxtjs/style-resources settings
*/
styleResources: {
scss: [
'./assets/css/*.scss'
]
},
/*
** Apollo setup for DatoCMS graphql queries
*/
apollo: {
includeNodeModules: true,
clientConfigs: {
default: '#/apollo/default.js'
}
},
/*
** Build configuration
*/
build: {
postcss: {
preset: {
features: {
customProperties: false
}
}
},
/*
** You can extend webpack config here
*/
extend(config, ctx) {
}
},
/*
** Generate configuration
*/
generate: {
routes: function(callback) {
// Get the list of posts
const uri = 'https://graphql.datocms.com';
const link = new createHttpLink({ uri: uri, fetch: fetch });
const operation = {
query: gql`
{
allBlogPosts {
id
slug
keywords
_seoMetaTags {
tag
attributes
content
}
}
}`,
context: {
headers: {
authorization: 'Bearer <my token>'
}
}
};
makePromise(execute(link, operation))
.then(data => {
// Build the routes from the posts
const postRoutes = data.data.allBlogPosts.map(item => {
return { route: `/blog/${item.slug}`, payload: { keywords: item.keywords, seoData: item._seoMetaTags }};
});
// Register the routes
callback(null, postRoutes);
})
.catch(error => console.log(`received error ${error}`));
}
}
}
If you expect all api requests to be bundled into app and not made anymore, thats not how nuxt currently work. It still will do requests to the api`s on client navigation withing app.
There is a plan for making full static mode in nuxt, you can track it here https://github.com/nuxt/rfcs/issues/22
I am trying to write a for loop that builds a dictionary for each object returned in the axios request.
My understanding is that the logic to "do stuff" with the returned object must be contained with axios '.then' block.
Here is my attempt at trying this (coming from a python background, so probably lots of errors here)
var jsonPayload = {}
axios.get('http://localhost:8080/api/tools')
.then(function (response) {
jsonPayload = response.data
console.log(jsonPayload)
const children = [];
jsonPayload.forEach(item => {
const dict = {
name: item.name,
path: item.path,
meta: {
label: item.label,
link: item.link,
},
component: lazyLoading('testitem/basic'),
}
children.push(dict);
});
})
.catch(function (error) {
console.log(error)
})
THIS is what I'm trying to accomplish:
const state = {
items: [
{
name: 'android',
path: '/android',
meta: {
icon: 'fa-tachometer',
link: 'android/index.vue'
},
children: [
{
name: 'jsonResponse_name',
path: 'jsonResponse_path',
meta: {
label: 'jsonResponse_label',
link: 'jsonResponse_link'
},
component: lazyLoading('test')
},
{
name: 'jsonResponse_name',
path: 'jsonResponse_path',
meta: {
label: 'jsonResponse_label',
link: 'jsonResponse_link'
},
component: lazyLoading('test')
},
{
name: 'jsonResponse_name',
path: 'jsonResponse_path',
meta: {
label: 'jsonResponse_label',
link: 'jsonResponse_link'
},
component: lazyLoading('test')
},
]
},
not sure if this is helpful: router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import menuModule from 'vuex-store/modules/menu'
Vue.use(Router)
export default new Router({
mode: 'hash', // Demo is living in GitHub.io, so required!
linkActiveClass: 'is-active',
scrollBehavior: () => ({ y: 0 }),
routes: [
{
name: 'Home',
path: '/',
component: require('../views/Home')
},
{
name: 'Login',
path: '/login',
component: require('../views/auth/Login')
},
...generateRoutesFromMenu(menuModule.state.items),
{
path: '*',
redirect: '/'
}
]
})
// Menu should have 2 levels.
function generateRoutesFromMenu (menu = [], routes = []) {
for (let i = 0, l = menu.length; i < l; i++) {
let item = menu[i]
if (item.path) {
routes.push(item)
}
if (!item.component) {
generateRoutesFromMenu(item.children, routes)
}
}
return routes
}