I was learning Vue 3 and get some trouble to use SweetAlert2 in app.js.
everything is ok and worked when i use SweetAlert2 in component Vue but not work in app.js
my goal:
i want to show alert with confirm button when get error response Unauthenticated. from axios interceptors and redirect user to login page
app.js
import {createApp} from 'vue'
require('./bootstrap')
import App from './App.vue'
import axios from 'axios'
import router from './router'
import store from './store'
// SweetAlert2
import VueSweetalert2 from 'vue-sweetalert2';
import 'sweetalert2/dist/sweetalert2.min.css';
axios.interceptors.response.use(function (response) {
return response
}, function (error) {
console.log(error.response.data.message)
if (error.response.data.message === 'Unauthenticated.') {
swal({
title: "Session Expired",
text: "Your session has expired. Would you like to be redirected to the login page?",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "Yes",
closeOnConfirm: false
}).then((result) => {
if (result.value) {
window.location.href = "/login"
}
});
}
return Promise.reject(error)
})
const app = createApp(App)
app.config.globalProperties.$axios = axios;
app.use(router)
app.use(VueSweetalert2)
app.use(store)
app.mount('#app')
it work when i change error response with this, (but not elegant like this for me)
...
axios.interceptors.response.use(function (response) {
return response
}, function (error) {
console.log(error.response.data.message)
if (error.response.data.message === 'Unauthenticated.') {
alert('Session Expired');
window.location.href = "/login"
}
return Promise.reject(error)
})
...
i think it would be good if using sweetalert,
thank youu...
Explanation
I faced the same problem when using Vue 3, and I wanted to use sweetalert2 in my router/index.js to add an alert when a user goes to an unauthorized route.
The same problem will appear if you want to use a sweetalert2 in store/index.js after calling an action fetching data from the backend.
To work around this problem, you must use the native package of sweetalert2, then you can use swal in any .js file.
By the way, I don't want to install any external package, so I found that when you are installing the vue-sweetalert2, the native package will be installed also (because it is a dependency of vue-sweetalert2).
Workaround
All you have to do is:
Keep what you had done in main.js (to use sweetalert2 inside components).
In any .js file where you want to use swal, add this import Swal from 'sweetalert2/dist/sweetalert2', and now you can access and use Swal.fire({}).
Example
I will attach an example of what I want to do (in my case), and how I work around the problem:
My main.js file:
import { createApp } from 'vue';
import App from './App.vue';
import store from './store';
import router from './router';
import VueSweetalert2 from 'vue-sweetalert2';
import 'sweetalert2/dist/sweetalert2.min.css';
const app = createApp(App);
app.use(store);
app.use(router);
app.use(VueSweetalert2);
app.mount('#app');
My router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import Swal from 'sweetalert2/dist/sweetalert2';
import store from '../store/index';
const router = createRouter({
routes: [
// ...
],
});
router.beforeEach((to, from, next) => {
if (to.matched.some((record) => record.meta['requiresAuth']) && store.state.auth.isAuthenticated === false) {
Swal.fire({
toast: true,
position: 'bottom-end',
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
icon: 'error',
title: 'Permission denied',
text: 'You are not authenticated to access this page.'
});
next({
name: 'login',
params: { nextUrl: to.fullPath }
});
}
next();
});
export default router;
i think you need to try withoud condition first,
try only sweet alert without :
axios.interceptors.response.use(function (response) {
return response
}, function (error) {
console.log(error.response.data.message)
if (error.response.data.message === 'Unauthenticated.') {
swal({
title: "Session Expired",
text: "Your session has expired. Would you like to be redirected to the login page?",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "Yes",
closeOnConfirm: false
}).then((result) => {
if (result.value) {
window.location.href = "/login"
}
});
}
return Promise.reject(error)
})
u can try
https://www.npmjs.com/package/vue-sweetalert2
Related
I created a project with Vite, Pinia and Vue-router. Everything works perfectly in development, but when I access the build, only the main path works. All other redirects return 404:
"Failed to load resource: the server responded with a status of 404 ()"
"crbug/1173575, non-JS module files deprecated.
(anonymous) # VM10:6789"
Any idea what could be happening?
*** Main.js ***
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
// Font Awesome
import { library } from '#fortawesome/fontawesome-svg-core'
import { fas } from '#fortawesome/free-solid-svg-icons'
import { far } from '#fortawesome/free-regular-svg-icons'
import { fab } from '#fortawesome/free-brands-svg-icons'
import { FontAwesomeIcon } from '#fortawesome/vue-fontawesome'
//Router
import router from './router'
//Pinia
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
library.add(fas, far, fab);
const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);
createApp(App)
.use(pinia)
.use(router)
.component('fa', FontAwesomeIcon)
.mount('#app')
*** App.vue ***
<script setup>
import { RouterView } from "vue-router";
</script>
<template>
<RouterView />
</template>
*** router/index.js ***
import { createRouter, createWebHistory } from 'vue-router'
import { useAuthStore } from '../stores/AuthStore';
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: "/katriumweb/login",
name: "login",
component: () => import("#/views/Login.vue")
},
{
path: "/katriumweb/playground",
name: "playground",
component: () => import("#/views/Playground.vue")
},
{
path: "/katriumweb/",
name: "home",
component: () => import("#/views/Home.vue"),
meta: {
authRequired: true
}
},
{
path: "/katriumweb/vehicleupdate",
name: "vehicleupdate",
component: () => import("#/views//workflows/VehicleUpdate.vue"),
meta: {
authRequired: true
}
}
],
});
router.beforeEach(async (to, from, next) => {
const authStore = useAuthStore();
let token = authStore.user? authStore.user.TOKEN : false;
const checkToken = await fetch("*******", {
method: "GET",
headers: {
"Token": `${token}`
}
})
if (to.meta.authRequired) {
if (!checkToken.ok || !token) {
localStorage.clear();
next("/katriumweb/login");
} else {
next();
}
} else {
next();
}
})
export default router;
*** vite.config.js ***
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import vue from "#vitejs/plugin-vue";
// https://vitejs.dev/config/
export default defineConfig({
base: "/katriumweb/",
plugins: [vue()],
resolve: {
alias: {
"#": fileURLToPath(new URL("./src", import.meta.url)),
},
},
});
Since the app itself only has an index.html file and everything else is done via javascript, when you navigate to /mypage it tries to grab another html file.
The Vue Router createWebHistory works this way. A simple fix is to use createWebHashHistory, which uses a hash in order to create the routing.
Otherwise, more solutions are available on the documentation (eg. Netlify supports a redirect property to handle this).
The docs: https://router.vuejs.org/guide/essentials/history-mode.html
I am currently trying to start a Vue app which will contain a user login.
For some reason the I have been struggling with getting this router redirect to work.
The implementation is straight from the vueschool page and specifically aimed at the composition API.
What am I missing here?
Every time I run the registration script it registers the user correctly and logs the error that it can't find the 'push' property on of undefined.
My code completion is telling me it's there, the linting works fine and the IDE Webstorm isn't giving any errors.
<script>
import firebase from "firebase/app";
import "firebase/auth";
import { defineComponent, ref } from "vue";
import { useRouter } from "vue-router";
export default defineComponent({
name: "Register",
setup() {
const form = ref({
email: "",
password: "",
error: "",
});
const pressed = () => {
const user = firebase
.auth()
.createUserWithEmailAndPassword(form.value.email, form.value.password);
user
.then((user) => {
console.log(user);
const router = useRouter();
router.push("/about");
})
.catch((e) => console.log(e.message));
};
return {
form,
pressed,
};
},
});
</script>
Hope it is just something simpel
const router = useRouter(); must be declared in the scope of the setup hook not inside any inner scope :
setup(){
const router = useRouter();
const form = ref({
email: "",
password: "",
error: "",
});
const pressed = () => {
const user = firebase
.auth()
.createUserWithEmailAndPassword(form.value.email, form.value.password);
user
.then((user) => {
console.log(user);
router.push("/about");
})
.catch((e) => console.log(e.message));
};
return {
form,
pressed,
};
},
I have a vue component that makes use of the store Vuex. However I get a
TypeError: Cannot read property 'token' of undefined
error. I don't understand why. This is my code:
In main.js:
import Vue from 'vue'
import Vuex from 'vuex';
import App from './App.vue'
import router from './router';
import "./assets/css/tailwind.css";
import '#/assets/css/tailwind.css';
import store from './store';
Vue.config.productionTip = false;
Vue.use(Vuex);
new Vue({
router, store,
render: h => h(App),
}).$mount('#app');
In store/indes.js:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
},
state: {
token: ''
}
})
In GenericForm.vue:
methods: {
execute() {
console.log("GenericForm.vue")
if (this.inputFunction) {
this.inputFunction()
}
this.register()
},
register () {
console.log("register()")
try {
const response = AuthenticationService.register({
email: 'testss',
password: 'frgr'
})
this.$store.dispatch('setToken', response.data.token)
this.$store.dispatch('setUser', response.data.user)
this.$store.router.push({
name: 'songs'
})
} catch (error) {
console.log(error)
/*
this.error = error.response.data.error
*/
}
}
}
the error occurs on this line of code:
this.$store.dispatch
Any help is appreciated.
EDIT:
AuthenticationService.js
import api from './api'
export default {
register (credentials) {
return api().post('register', credentials)
}
}
api.js
import axios from 'axios'
export default() => {
return axios.create({
baseURL: 'http://localhost:8081'
})
};
After adding console.log:
EDIT2:
New method:
register: async () => {
console.log("register()")
const response = AuthenticationService.register({
email: 'testss',
password: 'frgr'
}).then((response) => {
console.log(response)
/* this.$store.dispatch('setToken', response.data.token)
this.$store.dispatch('setUser', response.data.user)*/
this.$store.router.push({
name: '/test'
})
});
}
I get the error on
this.$store.router.push({
name: '/test'
})
line:
The response gets logged alright, though.
There are two problems:
First problem:
This code:
register(credentials) {
return api().post('register', credentials)
}
is returning a Promise, which has no data property. What you want is to access the axios response wrapped in that promise, so you either:
call then on the promise
AuthenticationService.register({...}).then((response) => {
console.log(response.data.token) // 'foo'
});
use async/await inside the Vue component
Second problem
The problem that causes the store to be undefined, is the use of the arrow functions. The register() method shouldn't have an arrow. Once the arrow gets removed there is no error (store is defined, as well as a router):
async register() {
console.log("register()")
const response = AuthenticationService.register({
email: 'testss',
password: 'frgr'
}).then((response) => {
console.log(response)
console.log(this.$store)
this.$router.push({
name: 'ha'
})
});
}
This means that the data property of response is not defined.
Is the AuthenticationService.register method asynchronous?
I'd imagine it is. If so, your code is continuing before the response object has been properly resolved.
Take a second and run console.log(response). You may see an unresolved promise if the method is async.
Otherwise, you may see nothing defined at all if the method does not return anything but instead uses callbacks.
I am new to Vue and I want to rebuild a existing CMS using Vue.
As I was building the authentication system, this error appeared:
WARNING Compiled with 1 warnings 17:16:12
warning in ./src/store/index.js
"export 'default' (imported as 'Vue') was not found in 'vue'
The browser-console is telling me this:
Uncaught TypeError: Cannot read property 'use' of undefined
at eval (index.js:10)
at Module../src/store/index.js (app.js:1337)
at __webpack_require__ (app.js:849)
at fn (app.js:151)
at eval (cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader-v16/dist/index.js?!./src/views/auth/Login.vue?vue&type=script&lang=js:2)
at Module../node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader-v16/dist/index.js?!./src/views/auth/Login.vue?vue&type=script&lang=js (app.js:974)
at __webpack_require__ (app.js:849)
at fn (app.js:151)
at eval (Login.vue?vue&type=script&lang=js:2)
at Module../src/views/auth/Login.vue?vue&type=script&lang=js (app.js:1469)
My main.js file:
import App from './App.vue'
import { createApp } from 'vue'
import router from './router'
createApp(App).use(router).mount('#app')
My store/index.js file:
import Vuex from 'vuex'
import Vue from 'vue'
import axios from 'axios'
Vue.use(Vuex)
axios.defaults.baseURL = 'https://[blablabla]/api'
export const store = new Vuex.Store({
state: {
access_token: window.localStorage.getItem('access_token') || null,
filter: 'all',
todos: []
},
getters: {
access_token: state => {
return state.access_token;
}
},
mutations: {
retreiveToken(state, token) {
state.access_token = token;
}
},
actions: {
authenticate(context, credentials) {
axios.post('/user/authenticate.php', { username: credentials.username, password: credentials.password })
.then(response => {
// const token = response.data.access_token
// localStorage.setItem('access_token', token)
// context.commit('retrieveToken', token)
console.log(response)
})
.catch(error => {
console.log(error)
})
}
}
})
My /views/auth/Login.vue script:
<script>
import { store } from '#/store'
export default {
name: 'Login',
data() {
return{
username: '',
password: ''
}
},
methods: {
login(){
store.dispatch('authenticate', {
username: this.username,
password: this.password
})
}
}
}
</script>
When i remove "Vue.use(Vuex)" the browser errors with:
[vuex] must call Vue.use(Vuex) before creating a store instance
Can someone tell me what is going on here?
Thanks!
The suggestion from vladimir was right.
It seems like I have mixed vue3 with vue2.
After switching to vue2 everything worked perfectly!
I have a Vue SPA that's being served by an ASP Core API. When I run it in development mode, everything works perfectly. But as soon as I deploy it to production (on an Azure App Service), I always get a blank page.
It seems to be specifically the router that can't match the routes, as I can put some arbitrary HTML into my App.vue, and that will render.
If I go into the developer tools, I can see that the index.html and all .js files download successfully and there are no errors in the console. This is true no matter what URL I visit e.g. myapp.com and myapp.com/login, both download everything but nothing displays on screen.
I have seen several posts saying to change the routing mode to hash, but I still get the same result with that.
Please see below my files:
main.ts
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import vuetify from './plugins/vuetify';
import { LOGIN_INITIALISE } from './use-cases/user-auth/AuthModule';
Vue.config.productionTip = false;
store.dispatch(LOGIN_INITIALISE)
.then(() => {
new Vue({
router,
store,
vuetify,
render: (h) => h(App),
}).$mount('#app');
});
App.vue
<template>
<div>
<div>test</div>
<router-view></router-view>
</div>
</template>
<script lang="ts">
/* eslint-disable no-underscore-dangle */
import Vue from 'vue';
import Axios from 'axios';
import { LOGOUT } from './use-cases/user-auth/AuthModule';
import { LOGIN } from './router/route-names';
export default Vue.extend({
name: 'App',
created() {
// configure axios
Axios.defaults.baseURL = '/api';
Axios.interceptors.response.use(undefined, (err) => {
// log user out if token has expired
if (err.response.status === 401 && err.config && !err.config.__isRetryRequest) {
this.$store.dispatch(LOGOUT);
this.$router.push({ name: LOGIN });
}
throw err;
});
},
});
</script>
router/index.ts
import Vue from 'vue';
import {} from 'vuex';
import VueRouter, { RouteConfig } from 'vue-router';
import store from '#/store';
import {
HOME,
LOGIN,
SIGNUP,
USERS,
} from './route-names';
Vue.use(VueRouter);
const routes: Array<RouteConfig> = [
{
path: '/',
name: HOME,
component: () => import('#/views/Home.vue'),
},
{
path: '/login',
name: LOGIN,
component: () => import('#/views/Login.vue'),
},
{
path: '/signup',
name: SIGNUP,
component: () => import('#/views/SignUp.vue'),
},
{
path: '/users',
name: USERS,
component: () => import('#/views/Users.vue'),
beforeEnter: (to, from, next) => {
if (store.getters.userRole === 'Admin') {
next();
} else {
next({ name: HOME });
}
},
},
{
path: '*',
name: '404',
component: {
template: '<span>404 Not Found</span>',
},
},
];
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
});
router.beforeEach((to, from, next) => {
if (store.getters.isAuthenticated) {
next();
} else if (to.name === LOGIN || to.name === SIGNUP) {
next();
} else {
next({ name: LOGIN });
}
});
export default router;
Finally after completely rebuilding my router piece by piece, I found the issue. I found that the problem was in this global route guard:
router.beforeEach((to, from, next) => {
if (store.getters.isAuthenticated) {
next();
} else if (to.name === LOGIN || to.name === SIGNUP) {
next();
} else {
next({ name: LOGIN });
}
});
Specifically, the isAuthenticated getter was throwing an error (silently), so all of the routes were failing before they could render. I wrapped my isAuthenticated logic in a try-catch that returns false if an error is thrown, and now everything works fine.
I still don't understand why this only affects the production build, but hopefully this experience will be useful to others stuck in the same situation.