How to fix NavigationDuplicated error in Internet Explorer? - vue.js

I am developing a "Vue" application that consists of a form to make a purchase.
In all the browsers it makes me the complete cycle without any problem, managing to make the "post" at the end of the form.
On the other hand, when I try to do the flow in Internet Explorer, after filling in the last step of the form, it redirects to the next page but does not load the component, returning the error "Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location: "/devis/resume".
this is my router
import Vue from 'vue'
import Router from 'vue-router'
import Devis from '../components/devis/devis.vue'
import Animal from '../components/devis/animal.vue'
import Create from '../components/devis/create.vue'
import Resume from '../components/devis/resume.vue'
import Service from '../components/devis/service.vue'
import Geo from '../components/extern/geolocalisation.vue'
import Message from '../components/extern/servicenotavailable.vue'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
component: Devis, children: [
{
path: '/',
component: Animal
}
]
},
{
path: '/devis',
component: Devis, children: [
{
path: '/',
component: Animal
},
{
path: 'create',
component: Create
},
{
path: 'resume',
component: Resume
},
{
path: 'service',
component: Service
}
]
},
{
path: '/geo',
component: Geo
},
{
path: '/message',
component: Message
}
],
mode: 'history',
scrollBehavior() {
document.getElementById('app').scrollIntoView();
}
})
and here is the point at which I redirect from create component to the resume component
checkForm() {
if (
this.ownerFormInfo.civility !== "" &&
this.ownerFormInfo.firstName !== "" &&
this.ownerFormInfo.lastName !== "" &&
this.ownerFormInfo.adresse1 !== "" &&
this.ownerFormInfo.city !== "" &&
(this.ownerFormInfo.postalCode === "" ||
(this.ownerFormInfo.postalCode !== "" &&
this.validatePostalCode(this.ownerFormInfo.postalCode))) &&
(this.ownerFormInfo.phone === "" ||
(this.ownerFormInfo.phone !== "" &&
this.validatePhone(this.ownerFormInfo.phone))) &&
(this.ownerFormInfo.email === "" ||
(this.ownerFormInfo.email !== "" &&
this.validateEmail(this.ownerFormInfo.email)))
) {
this.onSubmit();
}
},
onSubmit() {
const formData = {
civility: this.ownerFormInfo.civility,
firstName: this.ownerFormInfo.firstName,
lastName: this.ownerFormInfo.lastName,
adresse1: this.ownerFormInfo.adresse1,
adresse2: this.ownerFormInfo.adresse2,
adresse3: this.ownerFormInfo.adresse3,
city: this.ownerFormInfo.city,
postalCode: this.ownerFormInfo.postalCode,
phone: this.ownerFormInfo.phone.indexOf('0') == 0 ? this.ownerFormInfo.phone.replace('0', '+33') : this.ownerFormInfo.phone,
email: this.ownerFormInfo.email
};
const owner = {
ownerCivility: formData.civility,
ownerLastname: formData.lastName,
ownerFirstname: formData.firstName,
ownerAddressFirstLine: formData.adresse1,
ownerAddressSecondLine: formData.adresse2,
ownerAddressThirdLine: formData.adresse3,
ownerPostalCode: formData.postalCode,
ownerCity: formData.city,
ownerPhone: formData.phone,
ownerEmail: formData.email,
country: "FR"
};
this.$store.dispatch("formOwnerStepInfo", formData);
const token = localStorage.getItem("token");
let config = {
headers: {
Authorization: "Bearer " + token
}
};
globalAxios
.post("/api/fr/estimations", owner, config)
.then(res => {
if (res.data.functional_id) {
this.$store.dispatch("setFunctionalId", res.data.functional_id);
}
})
.catch(error => console.log(error));
this.navigateToResume();
},
navigateToResume() {
this.$store.dispatch("setStep", this.step + 1);
this.$router.push("/devis/resume");
},
How can it be that in the rest of the browsers it works correctly?
What am I doing wrong?
I've been looking for information but I can't find a way to fix the error or reference it as being due to Internet Explorer.
Greetings and thank you all for your time and help in advance

I found several threads, thanks to the help of Yu Zhou in comments, referring to similar problems caused by the vue-router version. All of them suggest using the vue-router below version 3.0.
In my case I first lowered it to 2.8 and there was no difference , but then I lowered it to 2.6 and the problem was solved.

Related

Vue router lazy loading does not work in Vite (Error: Unknown variable dynamic import)

I've built the below code in Vue router and it works perfect in Vue-CLI.
import store from "./../../store/index.js";
function getView(view) {
return () => import(`#/views/settings/${view}.vue`);
}
const routes = [
{
path: "/myProfile",
name: "MyProfile",
component: getView("MyProfile"),
beforeEnter: (to, from, next) => {
document.title = "Profile - " + store.getters.getAppName;
if (store.getters["userStore/authenticated"]) {
next();
} else {
next({ name: "Home" });
}
},
}
]
export default routes;
Now I am replacing Vue-CLI with Vite and it gives the below error.
TypeError: Failed to resolve module specifier '#/views/settings/MyProfile.vue'
When I remove the getView("MyProfile") function and directly use import as below, it works.
const routes = [
{
path: "/myProfile",
name: "MyProfile",
component: () => import('#/views/settings/MyProfile.vue'),
beforeEnter: (to, from, next) => {
document.title = "Profile - " + store.getters.getAppName;
if (store.getters["userStore/authenticated"]) {
next();
} else {
next({ name: "Home" });
}
},
}
]
Can someone please, explain why?
Can someone please, explain why?
This is due to Rollup Limitations. All imports must start relative to the importing file and import should not start with a variable.
So to get the GetView() function working, you have to replace the alias (#/) with relative or absolute path ../views or /src/views :
function getView(view) {
return () => import(`../views/settings/${view}.vue`);
}
Why it is working when you remove the getView() and you write directly the import directive ?
If you set a literal string, the alias is resolved (it end up to a relative or absolute path, respecting rollup requirement).
After trying lots of options, I finally found this solution.
import store from "./../../store/index.js";
async function getView(view) {
const comps = import.meta.glob("../views/**/*.vue");
const match = comps[`../views/${view}.vue`];
//For TS: const match: () => Promise<any> = comps[`../views/${view}.vue`];
return (await match()).default;
}
const routes = [
{
path: "/myProfile",
name: "MyProfile",
component: () => getView("settings/MyProfile"),
beforeEnter: (to, from, next) => {
document.title = "Profile - " + store.getters.getAppName;
if (store.getters["userStore/authenticated"]) {
next();
} else {
next({ name: "Home" });
}
},
}
]
export default routes;
Hope, this will solve the problem. (This works for any route.)
A little bit late but this should be the answer to your question, dynamic import in different bundlers will definitely have different behavior
We have Vite's case covered in the official documentation here:
https://router.vuejs.org/guide/advanced/lazy-loading.html#with-vite
Hope that will help :)

how to extend nuxt router to add new pages?

I'm on Nuxtjs v.2.15.4 and I'm trying a theming method for pages. by this code I can overwrite existing pages by my theme's pages :
// nuxt.config.js
router: {
extendRoutes(routes, resolve) {
if(process.env.THEME === "mainTheme" && process.env.THEME_CUSTOMIZE === "false"){
return
}
routes.map(route => {
const path = resolve(`src/themes/${process.env.THEME}/${route.chunkName}.vue`)
if (fs.existsSync(path)) {
route.component = path
}
if(process.env.THEME_CUSTOMIZE === "true"){
const pathCustom = resolve(`src/themes/customs/${route.chunkName}.vue`)
if (fs.existsSync(pathCustom)) {
route.component = pathCustom
}
}
return route
})
}
},
I know that where I check for existing path , must push to router if it doesn't exist. But what is the code that can do the naming and other thing like nuxt itself?
this is the code provided by nuxt doc to push into router:
router: {
extendRoutes(routes, resolve) {
routes.push({
name: 'custom',
path: '*',
component: resolve(__dirname, 'pages/404.vue')
})
}
}
the component will be resolve(src/themes/${process.env.THEME}/${route.chunkName}.vue) like overwriting code, but what about name and path ?? specially when page is dynamic!!
UPDATE
Ok, I think this approach has a problem. It will check routes and if there is same in theme folder it will overwrite. but won't check the theme's page directory itself for other pages that doesn't exist in main pages directory!! So some how I must check the theme's pages dir and map through theme and overwrite main of add new. SO HOW !??
Ok , I solved it, but it's so messy and ugly!! also increases the build time !!
// nuxt.config.js
// using glob: const glob = require("glob");
router: {
extendRoutes(routes, resolve) {
if(process.env.THEME === "mainTheme" && process.env.THEME_CUSTOMIZE === "false"){
return
}else{
if(process.env.THEME !== "mainTheme"){
let themePages = glob.sync(`src/themes/${process.env.THEME}/pages/**/*.vue`)
routes.map(route => {
const path = resolve(`src/themes/${process.env.THEME}/${route.chunkName}.vue`)
if (fs.existsSync(path)) {
route.component = path
let regexp = new RegExp(process.env.THEME+'/'+route.chunkName+'.vue');
themePages.splice(themePages.findIndex((x)=>{return x.match(regexp)}),1)
}
return route
})
themePages.map((x)=>{
let str = x.split(process.env.THEME+'/')[1]
routes.push({
name: str.replace('pages/','').replace(/\/_|\//gi,'-').replace('.vue',''),
path: str.replace('pages','').replace(/_(\w+)/gi,':$&?').replace(/:_/gi,':').replace('.vue',''),
component: resolve(x),
chunkName: str.replace('.vue','')
})
})
}
if(process.env.THEME_CUSTOMIZE === "true"){
let customPages = glob.sync(`src/themes/customs/pages/**/*.vue`)
routes.map(route => {
if(process.env.THEME_CUSTOMIZE === "true"){
const pathCustom = resolve(`src/themes/customs/${route.chunkName}.vue`)
if (fs.existsSync(pathCustom)) {
route.component = pathCustom
let regexp = new RegExp('customs/'+route.chunkName+'.vue');
customPages.splice(customPages.findIndex((x)=>{return x.match(regexp)}),1)
}
}
return route
})
customPages.map((x)=>{
let str = x.split('customs/')[1]
routes.push({
name: str.replace('pages/','').replace(/\/_|\//gi,'-').replace('.vue',''),
path: str.replace('pages','').replace(/_(\w+)/gi,':$&?').replace(/:_/gi,':').replace('.vue',''),
component: resolve(x),
chunkName: str.replace('.vue','')
})
})
}
}
}
},

Can't load component though URL changed

I have this route which loads a component and makes some validations
{
path: "/sso/:id/:atex/:entityId/:ip",
name: "SSO",
component: () => import("./views/account/sso"),
meta: {
beforeResolve(to, routeFrom, next) {
if (localStorage.getItem('userDetails') || localStorage.getItem('user')) {
next({ path: "/" + to.params.entityId })
}
next();
}
},
}
In the component and if user is valid
this.$router.replace("/" + this.$route.params.entityId);
And here's the route of /
{
path: "/:entityId?",
name: "Companies",
meta: {
authRequired: true,
beforeResolve(routeTo, routeFrom, next) {
next();
},
},
component: () => import("./views/dashboards/CompaniesGrid"),
},
And in the component I search for a table cell that contains the entityId value and click it to naرigate to /dashboard
var len = document.querySelectorAll('td').length;
for (var i=0; i < len; i++){
if ( document.querySelectorAll('td')[i].innerText == (this.$route.params.entityId).toUpperCase()){
document.querySelectorAll('td')[i].setAttribute('id', this.$route.params.entityId);
document.getElementById(this.$route.params.entityId).click();
}
}
The URL changes successfully but it doesn't really navigate. The component of dashboard isn't loaded and when I click it manually I get
Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location: "/dashboard".
How to solve this issue and why did it happen?

TypeError: e is not a function

Good day.
When running my app i get the following error related to my vue-router:
TypeError: e is not a function
however i have nothing ... i simply named "e" in my code.
I have a few before each options but nothing too big besides a few cookies deletions.
I have a few imports of apps and i am trying to use them in my router and they all work. So does the cookies. I did the beforeEach() method a few times to see if the error was there but so far no luck.
i got no idea of what is going on.
EDIT: When trying to figure this i was comenting on my code to see if i could find the error and when i removed most of the beforeEach() section i left on the next() function and a new error showed sayin "t is not a function", so i guess for some reason java script is only recognizing the last letters of my funcions, like t in next() and e in some().
EDIT2: After removing unecessary code that i copied from another project apperently the error happens in my next() function.
here's my router code:
import Vue from "vue";
import Router from "vue-router";
import Dashboard from "#/views/Dashboard.vue";
import Opcoes from "#/views/settings.vue";
import LoginForm from "#/components/component/loginForm.vue";
import store from "./store.js";
import Cookies from "js-cookie";
Vue.use(Router);
let router = new Router({
mode: "history",
base: process.env.BASE_URL,
routes: [
{
path: "/",
name: "loginForm",
component: LoginForm,
meta: {
guest: true
}
},
{
path: "/dashboard",
name: "Dashboard",
component: Dashboard,
meta: {
requiresAuth: true
}
},
{
path: "/opcoes",
name: "Opcoes",
component: Opcoes,
meta: {
requiresAuth: true
}
},
{
path: "/sair",
name: "Sair",
component: LoginForm,
meta: {
requiresAuth: true
}
}
]
});
router.beforeEach((to, from, next) => {
const expirationDate = Cookies.get("expireIn");
const now = new Date().getTime();
if (now >= expirationDate) {
Cookies.remove("expirationDate");
Cookies.remove("token");
Cookies.remove("userId");
store.dispatch('LOGOUT');
} else {
next();
}
});
export default router;
Heres a print of my stack trace:
My Big Fat Guess
The error message points to line 2203 (line 1921 is part of a generic error handler). This line is in the Router push() method
onComplete && onComplete(route);
My guess is, somewhere in your code not shown in your question (perhaps in your LoginForm component), you are calling this.$router.push() with a second argument that is not a function, eg
this.$router.push({ name: 'Dashboard' }, somethingNotAFunction)
Other problems (from previous versions of the question)
Your / route (loginForm) has no params so this...
next({
path: "/",
params: { nextUrl: to.fullPath }
});
is invalid. Did you perhaps mean to send nextUrl as a query parameter. If so, use
next({ name: 'loginForm', query: { nextUrl: to.fullPath } })
You also have
next({ path: "login" });
and
next({ name: "login" });
neither of which exist in your routes. You should only forward the route request to existing routes.
Finally, if you're using Vuex, you should not be directly assigning state values. In strict-mode, this
store.state.isLoggedIn = false
will trigger an error. You should be committing state mutations instead.

Vue.js and Pouch - PouchDB is not a constructor

Am building a simple Vue project to get to grips with simple store (vuex) and then using PouchDB. I am hitting an odd error and am struggling to see
where to go next
const PouchDB = require('pouchdb')
import EntryForm from '#/components/EntryForm.vue'
import DisplayText from '#/components/DisplayText.vue'
export default {
name: 'entryform',
components: {
EntryForm,
DisplayText
},
data() {
return {
db: [],
remote: [],
stepfwd: [],
stepback: [],
newMutation: true
}
},
created() {
//window.db or this.db does it matter ?
this.db = new PouchDB('icecream')
this.remote = 'http://localhost:5984/icecream'
this.db.sync(this.remote, { live: true, retry: true })
//any mutations are put into the stepfwd array and put into the db array
this.$store.subscribe(mutation => {
if (mutation.type !== CLEAR_STATE) {
this.stepfwd.push(mutation)
this.db.push(mutation)
}
if (this.newMutation) {
this.stepback = []
}
})
}
Any helpers much appreciated.
all the branch code can be found here for review
https://gitlab.adamprocter.co.uk/adamprocter/simplevuestore/tree/pouchdb