Why generated build in production makes browser crash - vue.js

I just want to update Vue X store when I click on add button called "Ajouter" but my browser crashes and I should open it again and again.
I already use store in my project and I'm not able to reproduce this issue with another state
I got this issue in production and not in development
I'm using this dependencies :
"core-js": "^3.8.3",
"vue": "^3.2.13",
"vue-class-component": "^8.0.0-0",
"vue-router": "^4.0.3",
"vuex": "^4.0.0"
State
export default {
selectedFoods: [],
currentFood: {},
nutrients: {
energy: 0,
protein: 0,
lipid: 0,
carbohydrate: 0
},
activeFilters: {
energy: false,
protein: false,
lipid: false,
carbohydrate: false
}
}
I would like to update selectedFoods
Mutation
SET_FOOD_QUANTITY (state: OrganizeMealState, param: SelectedFood) {
const selectedFoodsLength = Object.values(state.selectedFoods).length
if (selectedFoodsLength > 0) {
for (let index = 0; index < selectedFoodsLength; index++) {
const food = state.selectedFoods[index]
if (food.food.name === param.food.name) {
state.selectedFoods[index].quantity = param.quantity
return
}
}
}
// ===> crash here
state.selectedFoods.push({
food: param.food,
quantity: param.quantity
})
}
I can't push data into selectedFoods because browser crash
Action
setFoodQuantity ({ commit }: { commit: Commit }, param: SelectedFood) {
commit('SET_FOOD_QUANTITY', param)
},
Component
<template>
<div class="modal fade" id="modal-quantity" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="modal-portion-label" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-quantity-label">Quantité (g)</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" #click="cleanCurrentFood()"></button>
</div>
<div class="modal-body">
<form>
<div class="mb-1">
<input type="number" class="form-control" v-model="quantity">
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" #click="cleanCurrentFood()">Fermer</button>
<button type="button" class="btn btn-danger">Réinitialiser</button>
<button type="button" class="btn btn-primary" #click="addQuantity()">Ajouter</button>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { Options, Vue } from 'vue-class-component'
import { mapActions, mapGetters } from 'vuex'
import { Food } from '../../domain/food'
import { SelectedFood, Nutrients } from '../../domain/store/OrganizeMealState'
#Options({
computed: {
...mapGetters({
currentFood: 'OrganizeMeal/currentFood',
selectedFoods: 'OrganizeMeal/selectedFoods',
nutrients: 'OrganizeMeal/nutrients'
})
},
methods: {
...mapActions({
setFoodQuantity: 'OrganizeMeal/setFoodQuantity',
cleanCurrentFood: 'OrganizeMeal/cleanCurrentFood'
}),
addQuantity () {
this.setFoodQuantity({
food: this.currentFood,
quantity: this.quantity
})
}
}
})
export default class AddFoodQuantityModal extends Vue {
currentFood!: Food
selectedFoods!: SelectedFood[]
nutrients!: Nutrients
quantity = 0
}
</script>
Here is my modal
If you need to see more code, I share you github project here : https://github.com/wyllisMonteiro/diet-helper
Use devtools result
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
const app = createApp(App).use(store).use(router).mount('#app')
// eslint-disable-next-line
// #ts-ignore: Unreachable code error
app.config.performance = true
npm run build
Use this extension to serve : https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb
and got this

Related

Trying to access the store in a main page and I'm getting the error

Main.vue:
<template>
<div>
<div class="home_page_header">
<h1>My Recipe</h1>
<button #click="toggleOpen">Add New Recipe</button>
</div>
<div v-for="recipe in $store.state.recipes" :key="recipe.Recipe_Name">
<h1 >{{recipe.Recipe_Name}}</h1>
<p>{{recipe.Ingredients}}</p>
<router-link :to="`/recipe/${recipe.Recipe_Name}`">
<button>View Recipe</button>
</router-link>
<router-view/>
</div>
<div>
<h1></h1>
<p></p>
</div>
<div class="popUp" v-show="openUp">
<div>
<label for="receipe_name">Recipe Name</label>
<input type="text" id="receipe_name" v-model="values.receipeName"/>
</div>
<div>
<label for="ingredients_name">Ingredients</label>
<input type="text" id="ingredients_name" v-model="values.ingredientsName" v-for="i in values.ingredientsRows" :key="i"/>
<button #click="addrows" >Add Ingredients</button>
</div>
<div><button #click="onSubmit">Submit</button></div>
<div><button #click="toggleClose">Close</button></div>
</div>
</div>
</template>
<script>
import store from '#/store/index.js'
export default {
data() {
return {
values:{
receipeName:'',
ingredientsName:'',
ingredientsRows:1
},
values_final:{
receipeName:'',
ingredientsName:'',
ingredientsRows:1
},
openUp : false
}
},
methods: {
toggleOpen(){
this.openUp = true
},
toggleClose(){
this.openUp = false
},
onSubmit(){
if(this.values.receipeName || this.values.ingredientsName == ''){
alert('enter the full details')
}
},
addrows(){
this.values.ingredientsRows++;
},
},
computed: this.$store.commit('Add_Recipes',{...values_final})
}
</script>
store:
import { createStore } from 'vuex'
export default createStore({
state: {
recipes:[
{
Recipe_Name: 'curd',
Ingredients:'xxxxxx'
}
]
},
mutations: {
Add_Recipes (state,recipe) {
state.recipes.push(recipe)
}
},
Error : app.js:340 Uncaught TypeError: Cannot read properties of undefined (reading '$store')...
I'm trying to create a recipe app by using option API, I have one main page. In that main page that contains one title and add recipe button to add the details. And another one is a popup to enter the recipe details. so here after entering all the details that should show in a main page. I'm trying to access the store in a main page but iam getting the above error.
I guess you need to move the import statement of your store to your main.js file (not your Main.vue). And add app.use(store) after you created the app there with const app = createApp(…).

Open/Close a modal using Vue3 composition API doesn't work as expected

I want to build a simple open/close Modal, using Vue3 composition API,
but it doesn't work.
If I use v-if (as in the code below) the modal doesn't open, if I use v-show the modal opens but the close button doesn't work.
As an addition, add a eventListener for ESC key, and then remove it on unMounted.
App.vue
<div class="min-h-screen flex items-center justify-center">
<button #click="isModalOpen = true" type="button" class="btn btn-blue">Open Modal</button>
</div>
<announcement-modal
v-if="isModalOpen"
#click="isModalOpen = true"
v-model:isOpen="isModalOpen">
</announcement-modal>
</div>
</template>
<script>
import { ref } from "vue";
import AnnouncementModal from "./components/AnnouncementModal";
export default {
components: {
AnnouncementModal,
},
setup() {
const isModalOpen = ref(false);
return {
isModalOpen,
}
},
}
</script>
Announcement.vue
<div class="text-center">
<button #click="closeModal" type="button" class="btn btn-blue">
Dismiss
</button>
</div>
</div>
</div>
</template>
<script>
import { onUnmounted } from "vue"
export default {
props: ["isOpen"],
setup(props, context) {
onUnmounted(function () {
console.log("after unmounted")
});
function closeModal() {
context.emit("update:is-open", false);
}
return {
closeModal
}
}
}
The #click="isModalOpen = true" is immediately opening it every time you click to close the modal.
Remove this event handler and it should work:
const app = Vue.createApp({
setup() {
const isModalOpen = Vue.ref(false);
return {
isModalOpen
}
},
});
app.component('announcement-modal', {
template: `<div class="text-center">
<button #click="closeModal" type="button" class="btn btn-blue">
Dismiss
</button>
</div>`,
setup(props, context) {
Vue.onUnmounted(function() {
console.log("after unmounted")
});
function closeModal() {
context.emit("update:is-open", false);
}
return {
closeModal
}
}
})
app.mount('#app')
<script src="https://unpkg.com/vue#next"></script>
<div id="app">
<div class="min-h-screen flex items-center justify-center">
<button #click="isModalOpen = true" type="button" class="btn btn-blue">Open Modal</button>
</div>
<announcement-modal v-if="isModalOpen" v-model:is-open="isModalOpen"></announcement-modal>
</div>
Also, as #Dan said, the v-model:isOpen="isModalOpen" shouldn't be camelCase.

Error When clicking 'Print' button using 'Vue HTML to Paper'

I have a vue app and I'm trying to implement the 'Vue HTML to Paper'.
I have followed all the instructions on https://randomcodetips.com/vue-html-to-paper/ but when i click my 'Print' button I get the following error.
Main.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './App.vue';
import { routes } from './routes';
import { store } from './store/store';
import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap-vue/dist/bootstrap-vue.css';
import VueHtmlToPaper from 'vue-html-to-paper';
const router = new VueRouter({
// Loads page always at the top
scrollBehavior() {
$('.tooltip, .popover').tooltip('hide');
return { x: 0, y: 0 };
},
routes,
});
const options = {
name: '_blank',
specs: [
'fullscreen=yes',
'titlebar=yes',
'scrollbars=yes'
],
styles: [
'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css',
'https://unpkg.com/kidlat-css/css/kidlat.css'
]
}
Vue.use(VueRouter, VueHtmlToPaper, options);
...
Component
<template>
<div>
<loader v-if="loading" />
<div v-else class="form-group row d-flex justify-content-center">
<div class="col-10">
<div id="printMe" class="card">
<div class="card-header">
<div class="row d-flex align-items-center">
<div class="col">
Order details for: <span class="text-info">{{ 'PACK' + productOrder.id }}</span>
</div>
<div class="col d-flex justify-content-end">
<button class="btn btn-info" #click="print">Print</button>
......
<script>
export default {
data() {
return {
...
output: null
....
methods: {
print () {
// Pass the element id here
this.$htmlToPaper('printMe');
},
...
You can't register multiple plugins in one Vue.use.
Try replacing the line
Vue.use(VueRouter, VueHtmlToPaper, options);
With
Vue.use(VueRouter);
Vue.use(VueHtmlToPaper, options)

Vuex State data is not persisting?

I'm working on admin panel in vuejs and using vuex for state management.
store/module/home/home.js:
import instance from "../../../services/Http";
const state = {
usersCount: 0,
customersCount: 0,
chefsCount: 0,
driversCount: 0,
Users: [],
};
const getters = {
Userscount: state => state.usersCount,
Customerscount: state => state.customersCount,
Chefscount: state => state.chefsCount,
Driverscount: state => state.driversCount,
users: state => state.Users,
};
const actions = {
getStats({commit})
{
instance.get('admin/stats').then(res => commit('setStats', res.data));
},
getUsers({commit})
{
instance.get('admin/users').then(res => commit('setUsers', res.data));
}
};
const mutations = {
setStats:(state, data) => {
state.usersCount = data.usersCount;
state.customersCount = data.customersCount;
state.chefsCount = data.chefsCount;
state.driversCount = data.driversCount;
},
setUsers:(state, data) => { state.Users = data.users}
};
export default {
state,
getters,
actions,
mutations
}
and then i'm calling getStats and getUsers actions in two different components in created method of respective components.
The issue is that getStats and setStats is executed but it does not set the data, but getUsers and setUsers is working as expected.
src/components/layouts/Widgets.vue:
<template>
<!-- Widgets -->
<div class="row">
<div class="col-lg-3 col-md-6">
<div class="card">
<div class="card-body">
<div class="stat-widget-five">
<div class="stat-icon dib flat-color-1">
<!-- <i class="pe-7s-cash"></i>-->
<i class="pe-7s-users"></i>
</div>
<div class="stat-content">
<div class="text-left dib">
<div class="stat-text"><span class="count">{{ Userscount }}</span></div>
<div class="stat-heading">Total Users</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6">
<div class="card">
<div class="card-body">
<div class="stat-widget-five">
<div class="stat-icon dib flat-color-2">
<!-- <i class="pe-7s-cart"></i>-->
<i class="pe-7s-users"></i>
</div>
<div class="stat-content">
<div class="text-left dib">
<div class="stat-text"><span class="count">{{ Chefscount }}</span></div>
<div class="stat-heading">Total Chefs</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6">
<div class="card">
<div class="card-body">
<div class="stat-widget-five">
<div class="stat-icon dib flat-color-8">
<!-- <i class="pe-7s-browser"></i>-->
<i class="pe-7s-users"></i>
</div>
<div class="stat-content">
<div class="text-left dib">
<div class="stat-text"><span class="count">{{ Customerscount }}</span></div>
<div class="stat-heading">Total Customers</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6">
<div class="card">
<div class="card-body">
<div class="stat-widget-five">
<div class="stat-icon dib flat-color-4">
<i class="pe-7s-users"></i>
</div>
<div class="stat-content">
<div class="text-left dib">
<div class="stat-text"><span class="count">{{ Driverscount }}</span></div>
<div class="stat-heading">Total Drivers</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- /Widgets -->
</template>
<script>
import {mapActions,mapGetters} from 'vuex';
export default {
name: "Widgets",
created() {
this.getStats();
},
computed: mapGetters(['Userscount','Customerscount','Chefscount','Driverscount']),
methods:{
...mapActions(['getStats'])
},
}
</script>
i'have also attached images showing of vue js dev tools for vuex that data is stored in state but it is not being displayed.
edit-1:
setStats-after console.log
{usersCount: 12, customersCount: 4, chefsCount: 7, driversCount: 0, postsCount: 22}chefsCount: 7customersCount: 4driversCount: 0postsCount: 22usersCount: 12__proto__: Object
Edit-2:
vuex binding widgets components
Edit-3:
Store/index.js:
import Vue from 'vue'
import Vuex from 'vuex'
import auth from "./modules/auth/auth";
import home from "./modules/home/home";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules: {
auth,
home
}
});
sr/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false;
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!store.getters.isLoggedIn)
{
next({
name: 'login',
})
}
else
{
next();
}
}
else if(to.matched.some(record => record.meta.Visitor)) {
if (store.getters.isLoggedIn)
{
next({
name: 'home',
})
}
else
{
next();
}
}
else
{
next()
}
});
new Vue({
store,
router,
render: h => h(App)
}).$mount('#app');
src/components/layout/Main.vue:
<template>
<div class="Main">
<SideBar/>
<div id="right-panel" class="right-panel">
<Header/>
<!-- Content -->
<div class="content">
<div class="animated fadeIn">
<Widgets/>
<div class="clearfix"></div>
<Users/>
<div class="clearfix"></div>
<Footer/>
</div>
</div>
</template>
<script>
import SideBar from "./SideBar";
import Header from "./Header";
import Footer from "./Footer";
import Widgets from "./Widgets";
import Users from "../users/Users";
export default {
name: "Main",
components: {Users, Widgets, Footer, Header, SideBar}
}
</script>
<style scoped>
#weatherWidget .currentDesc {
color: #ffffff!important;
}
.traffic-chart {
min-height: 335px;
}
#flotPie1 {
height: 150px;
}
#flotPie1 td {
padding:3px;
}
#flotPie1 table {
top: 20px!important;
right: -10px!important;
}
.chart-container {
display: table;
min-width: 270px ;
text-align: left;
padding-top: 10px;
padding-bottom: 10px;
}
#flotLine5 {
height: 105px;
}
#flotBarChart {
height: 150px;
}
#cellPaiChart{
height: 160px;
}
</style>
Any help will be appreciated.
Thanks.
you forgot to add "..." before the 'mapGetters', "...mapGetters"
I think your problem would be solved by implementing the strict-mode in Vuex, by the way, it's turned off by default.
take a look here: https://vuex.vuejs.org/guide/strict.html
Have you tried using mapState instead of mapGetters? As your values are just being updated, but your getters aren't computed values, they just map to your state.
Instead of:
<script>
import {mapActions,mapGetters} from 'vuex';
export default {
name: "Widgets",
created() {
this.getStats();
},
computed: mapGetters(['Userscount','Customerscount','Chefscount','Driverscount']),
methods:{
...mapActions(['getStats'])
},
}
</script>
Maybe try:
<script>
import {mapActions,mapGetters} from 'vuex';
export default {
name: "Widgets",
created() {
this.getStats();
},
computed: mapState({
Userscount: state => state.home.Userscount,
Customerscount: state => state.home.Customerscount,
Chefscount: state => state.home.Chefscount,
Driverscount: state => state.home.Drivers.count
}),
methods:{
...mapActions(['getStats'])
},
}
</script>

VueJS display dynamic modal component

I have posts and replys s.t. replies belong to posts via the attribute reply.posts_id.
I am attempting to show the reply form as a modal for the user to enter a reply. However, I want to create a generic Modal component that I can use everywhere with content that is specified in another component built for a specific context.
Reply to post is the first place I woul like this to work.
Currently, the Vuex correctly returns Modal visible:true when the reply button is clicked, but the modal does not render and I get the error message showing that the Modal component is not found:
Unknown custom element: <ModalReplyForm> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
I am using vuex to manage the visibility of the modal. Here are the relevant files:
store.js:
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
...
Vue.use(Vuex)
export default new Vuex.Store({
state: {
status: '',
...
modalVisible: false,
modalComponent: null
},
mutations: {
...
showModal(state, componentName) {
console.log('showing the modal')
state.modalVisible = true;
state.modalComponent = componentName;
},
hideModal(state) {
console.log('hiding the modal')
state.modalVisible = false;
}
},
actions: {
...
}
},
getters: {
isAuthenticated: state => !!state.user,
authStatus: state => state.status,
user: state => state.user,
token: state => state.token,
posts: state => {
return state.posts;
}
...
}
})
App.vue
<template>
<div id="app">
<app-modal></app-modal>
<NavigationBar />
<div class="container mt-20">
<router-view />
</div>
<vue-snotify></vue-snotify>
</div>
</template>
<script>
import AppModal from '#/components/global/AppModal';
import NavigationBar from '#/components/layout/NavigationBar'
export default {
name: "App",
components: {
AppModal,
NavigationBar
}
};
</script>
<style>
body {
background-color: #f7f7f7;
}
.is-danger {
color: #9f3a38;
}
</style>
Post.vue (houses the button to call the reply modal):
<template>
<div class="row ui dividing header news">
<!-- Label -->
<div class="m-1 col-md-2 ui image justify-content-center align-self-center">
<img v-if="post.avatar_url" :src="post.avatar_url" class="mini rounded"/>
<v-gravatar v-else :email="post.email" class="mini thumbnail rounded image rounded-circle z-depth-1-half"/>
</div>
<!-- Excerpt -->
<div class="col-md-9 excerpt">
...
<!-- Feed footer -->
<div class="feed-footer row">
<div class="small"> {{ post.created_at | timeAgo }}</div>
<button type="button" flat color="green" #click="showModal('ModalReplyForm')">
<i class="fa fa-reply" ></i>
...
<div v-show="postOwner(post)" class="">
<button type="button" flat color="grey" #click="deletePost(post.id)">
<i class="fa fa-trash " ></i>
</button>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapMutations } from 'vuex';
import PostsService from '../../services/PostsService'
import RepliesService from '../../services/RepliesService'
import Replies from '#/components/Reply/Replies'
import ReplyForm from '#/components/Reply/ReplyForm'
export default {
name: "Post",
props: {
post: {
type: Object,
required: true
}
},
components: {
Replies,
ReplyForm
},
computed: {
me() {
return this.$store.getters.user
}
},
methods: {
...mapMutations(['showModal']),
...
}
};
</script>
AppModal.vue - generic Modal component
<template>
<div class="c-appModal">
<div class="c-appModal__overlay" v-if="visible"></div>
<div class="c-appModal__content" v-if="visible" #click.self="hideModal"></div>
<div class="c-appModal__innerContent">
<component :is="component"></component>
</div>
</div>
</template>
<script>
import Vue from 'vue';
import { mapState, mapMutations } from 'vuex';
export default {
name: 'AppModal',
data() {
return {
component: null
}
},
computed: {
...mapState({
visible: 'modalVisible',
modalComponent: 'modalComponent'
}),
},
methods: {
...mapMutations(['hideModal'])
},
watch: {
modalComponent(componentName) {
if (!componentName) return;
Vue.component(componentName, () => import(`#/components/modals/${componentName}`));
this.component = componentName;
}
},
created() {
const escapeHandler = (e) => {
if (e.key === 'Escape' && this.visible) {
this.hideModal();
}
};
document.addEventListener('keydown', escapeHandler);
this.$once('hook:destroyed', () => {
document.removeEventListener('keydown', escapeHandler);
});
},
};
</script>
ModalReplyForm - specific reply modal content
<template>
<div>
<div class="c-modalReply">
<div>
<label for="reply">Your comment</label>
<div class="field">
<textarea name="reply" v-model="reply" rows="2" placeholder="Compose reply"></textarea>
</div>
</div>
<button class="c-modalReply__cancel" #click="hideModal">Cancel</button>
<button class="c-modalReply__post" :disabled="!isFormValid" #click="createReply">Reply</button>
</div>
</div>
</template>
<script>
import RepliesService from '#/services/RepliesService'
import { mapMutations } from 'vuex';
export default {
name: "ModalReplyForm",
// props: {
// post: {
// type: Object,
// required: true
// }
// },
data() {
return {
reply: ""
};
},
computed: {
isFormValid() {
return !!this.reply;
},
currentGroup() {
return this.$store.getters.currentPost;
}
},
methods: {
...mapMutations([
'hideModal'
]),
async createReply () {
let result = await RepliesService.addReply({
reply: {
body: this.reply,
postId: this.post.id
}
});
this.$emit("reply-created");
this.hideModal();
}
}
};
</script>
Unknown custom element: - did you register the
component correctly? For recursive components, make sure to provide
the "name" option.
This message says that you never imported/defined ModalReplyForm, which you have not.
In my own generic modal, I ended up having to import all the components that might appear within the modal itself.
If you add a:
import ModalReportForm from ...
and a:
components: {
ModalReplyForm
}
to AppModal.vue, the modal should then do what you expect.