I'm new to Vue.js and building an app with header / footer (showing on certain pages) and in the footer I have a shopping cart.
Basically on some pages of the app I can add items to the cart, and with the icon in the footer I can acess to the list of items, and delete them if I want to.
My cart showing as a dialog full screen, above my app.
The problem is, if I empty my cart, I want to reload the component behind my shopping cart before closing it (because the step is not the same...), and I don't know how to do it, actually i'm reloading the page if I close the cart while he's empty....
This is my footer part (with the cart) :
var footer = Vue.component("iteck-footer", {
template: `<div>
<v-footer fixed height="auto" color="teal" dark>
<v-layout class="pl-2 pr-2" justify-center row wrap>
<v-dialog fullscreen v-model="dialog" transition="dialog-bottom-transition">
<v-toolbar fixed dense dark color="teal">
<v-spacer></v-spacer>
<v-toolbar-title>Panier</v-toolbar-title>
<v-spacer></v-spacer>
<v-toolbar-items>
<v-btn icon dark #click="dialog = false">
<v-icon>close</v-icon>
</v-btn>
</v-toolbar-items>
</v-toolbar>
<div class="content-with-header-footer">
<div v-if="articles.length > 0">
<div v-for="article in articles" :key="article.LIG">
<v-checkbox class="inputs-panier pa-0 ma-0 " v-model="article.selected">
<template slot="label">
<div>{{article.DESIG}} | <b>Qté.</b> : {{quantite(article.QTESAI)}}</div>
<div>{{article.CLE}} {{article.CODBAR}}</div>
</template>
</v-checkbox>
</div>
</div>
<div class="text-xs-center mt-4" v-else>
<h2 class="red--text">Panier vide</h2>
</div>
</div>
<v-footer fixed height="auto" color="teal" dark>
<v-btn #click="deleteLignesPanier()" class="mx-0" icon>
<v-icon>delete</v-icon>
</v-btn>
<v-spacer></v-spacer>
<v-btn #click="validerPanier()" class="mx-0" icon>
<i class="material-icons">check</i>
</v-btn>
</v-footer>
</v-dialog>
<v-btn style="position:relative;" #click="openMenu()" class="mx-0" icon>
<i class="material-icons">shopping_basket</i>
<span id="nb_articles">
{{articles.length}}
</span>
</v-btn>
<v-spacer></v-spacer>
<v-btn #click="validerPanier()" class="mx-0" icon>
<i class="material-icons">check</i>
</v-btn>
<v-dialog v-model="modal" max-width="290">
<v-card>
<v-card-text>
{{modalMessage}}
</v-card-text>
<v-card-actions>
<v-btn color="green darken-1" flat="flat" #click="modal = false; modalMessage = ''">
OK
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-layout>
</v-footer>
</div>`,
props: ["menu"],
data() {
return {
modal : false,
modalMessage : "",
entete: null,
articles: [],
dialog: false
}
},
mounted() {
this.getPanier()
},
watch: {
// whenever question changes, this function will run
dialog: function (newValue, oldValue) {
if(newValue === false && this.articles.length === 0)
location.reload();
}
},
methods: {
async openMenu() {
this.articles = [];
this.entete = null;
if(this.dialog === false) {
//Récuperation du panier en cours.
this.getPanier();
}
this.dialog = true;
},
async deleteLignesPanier() {
let lignes = "";
for (let i=0; i < this.articles.length; i++ ) {
if(this.articles[i].selected === true) {
if(lignes === "")
lignes = lignes + this.articles[i].LIGNE;
else
lignes = lignes + "," + this.articles[i].LIGNE;
}
}
if(lignes !== "") {
//On envoie la requête au serveur.
let data = await wspda.deleteLignesPanier(this.menu,lignes);
if(data == 'true')
{
console.log('OUI');
console.log('length',this.articles.length);
console.log('articles',this.articles);
for (let i = this.articles.length -1; i >= 0; i-- ) {
if(this.articles[i].selected === true) {
this.articles.splice(i,1);
}
}
}
else
{
console.log(data);
}
}
},
async validerPanier() {
if(this.articles.length > 0) {
let data = await wspda.validerPanier(this.menu,"","False");
this.modal = true;
this.modalMessage = data;
this.articles = [];
}
},
async getPanier() {
let data = await wspda.getPanier(this.menu);
if(data.ProDataSet && data.ProDataSet.PANIERENT && data.ProDataSet.PANIERLIG) {
if(Array.isArray(data.ProDataSet.PANIERLIG)) {
this.articles = data.ProDataSet.PANIERLIG;
} else {
this.articles.push(data.ProDataSet.PANIERLIG);
}
this.entete = data.ProDataSet.PANIERENT;
for (let i=0; i<this.articles; i++ ) {
this.articles[i].selected = false;
}
}
},
quantite(qtesai) {
return (qtesai % 1) === 0 ? Math.round(qtesai) : qtesai;
}
}
});
As you can see, in my watcher, on the closing of the cart, i may reload the page... But there is a way, when the cart is empty (deleting items), reload the current component behind my dialog ?? can't find a proper way to do it.
And my current component running behind (just for an example) :
var spaHome = Vue.component("Home", {
template: `<div>
<v-container fill-height>
<v-layout>
<v-flex>
<v-list>
<v-list-tile class="menu-home"
v-for="(item,index) in menus" :key="index" #click="$router.push(item.path)" v-if="item.value">
<!--<v-list-tile-action>
<v-icon>{{ item.icon }}</v-icon>
</v-list-tile-action>-->
<v-list-tile-content class="teal darken-3 white--text">
<v-list-tile-title class="text-xs-center">{{ item.label }}</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list>
</v-flex>
</v-layout>
</v-container>
</div>`,
props: ["title"],
$_veeValidate: {
validator: "new"
},
data() {
return {
menus: conf.Menus,
}
},
methods: {
}
});
By the way, I'm not using node.js etc... Because I can't run the app on a node server, so I can't use "import" , "export"...
Related
I create vuex with addNews method Inside of it and pass two arguments, title and body of item. But after calling that method inside my component it only prints my first argument title in HTML. Also i try to console.log body and i get data
This is my method in vuex
async addNews({ commit }, title, body) {
const response = await axios.post(
`https://jsonplaceholder.typicode.com/posts`,
{ title: title, body: body }
);
commit("addNews", response.data);
},
And here is component where I call it
<template>
<div class="text-center">
<v-dialog v-model="dialog" width="500">
<template v-slot:activator="{ on, attrs }">
<v-btn class="mb-5" fab dark color="primary" v-bind="attrs" v-on="on">
<v-icon dark> mdi-plus </v-icon>
</v-btn>
</template>
<v-card>
<v-card-title class="text-h5 blue lighten-2">
ADD NEW POST
</v-card-title>
<v-text-field v-model="title" required></v-text-field>
<v-text-field v-model="body" required></v-text-field>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="primary"
class="mr-4"
#click="
onSubmit();
dialog = false;
"
>
Do It
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</template>
<script>
import { mapActions } from "vuex";
export default {
name: "AddNews",
data() {
return {
title: "",
body: "",
dialog: false,
};
},
methods: {
...mapActions(["addNews"]),
onSubmit() {
this.addNews(this.title, this.body);
this.title = "";
this.body = "";
},
},
};
</script>
Try passing an object with arguments to your action:
async addNews({ commit }, { title, body }) {
const response = await axios.post(
`https://jsonplaceholder.typicode.com/posts`,
{ title, body }
);
commit("addNews", response.data);
},
I have a role permission implementation where by i have resource which is an array that contains items that the user may be given access to. again i have checks which are the permissions for the said resource.
I Want to dynamically assign a role that will have these resources along with the permissions chosen by the user.
i have tried the following implementation but the submitted result does not submit an array of permissions (checks) chosen, it only submits the last item in the checkbox.
What am i missing here
The template is
<template v-slot:activator="{ on }">
<v-btn
class="mx-2"
data-toggle="tooltip"
data-placement="left"
title="Edit Permissions"
fab
dark
small
color="#666"
v-on="on"
#click="getItem()"
>
<v-icon dark>mdi-access-point</v-icon>
</v-btn>
</template>
<v-form v-model="valid" #submit.prevent="onSubmit">
<v-container>
<v-row>
<v-col cols="12" sm="12" md="12" class="alternate-card">
<h4 class="text-muted text-center">
Role : {{ payload.role }}
</h4>
</v-col>
<blockquote class="col-md-12">
<h4 class=" text-center">Permissions</h4>
</blockquote>
<hr />
<v-col
cols="12"
sm="12"
md="12"
v-for="(perm, indexe) in result"
:key="indexe"
>
<h5 class="text-center text-muted">{{ indexe }}</h5>
<v-row class="alternate-card">
<v-col
cols="12"
sm="3"
md="3"
v-for="(item, index) in checks"
:key="index"
>
{{item}}
<span>
<v-checkbox
v-model="result[indexe]"
:label="item"
:value="item"
></v-checkbox>
</span>
</v-col>
</v-row>
</v-col>
</v-row>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="blue darken-1" text #click="dialog = false"
>Close</v-btn
>
<v-btn type="submit" :disabled="!valid" color="blue darken-1" text
>Save</v-btn
>
</v-card-actions>
</v-container>
</v-form>
The script is
export default {
props: ["form"],
data() {
return {
valid: false,
load: false,
payload: {},
result: {},
checks: {
create: "create",
edit: "edit",
delete: "delete",
show: "show",
},
};
},
methods: {
...mapActions(["editRole"]),
onSubmit() {
this.load = true;
console.log(this.result)
this.payload.permission = {}
this.payload.permission = this.result
// console.log(this.payload)
if (this.editRole(this.payload)) {
setTimeout(() => (this.load = false), 1000);
setTimeout(() => (this.dialog = false), 1300);
}
},
getItem() {
this.payload = {
id: 22462662,
role: "Admin",
permission :
{
package : ['create', 'edit', 'delete', 'show'],
category : ['create', 'edit', 'delete', 'show'],
product : ['create', 'edit', 'delete', 'show'],
},
},
let resource = ['package', 'users', 'category', 'product', 'assets', 'readers']
let keys = Object.keys(this.payload.permission);
for (var i = 0; i < resource.length; i++) {
for (var j = 0; j < Object.keys(this.payload.permission).length; j++) {
//search through the obj and return corresponding items and assign to result Obj
if (keys[j] === resource[i]) {
this.result[resource[i]] = this.payload.permission[keys[j]];
}
}
}
//now remove all keys that are in obj from resource
let included = resource.filter(function(item) {
return !keys.includes(item);
});
//now push these into result
for (var h = 0; h < included.length; h++) {
this.result[included[h]] = [];
}
},
},
};
so at the end of the day result Obj will look something like
{ "package": [ "create", "edit", "delete", "show" ], "category": [ "create", "edit", "delete", "show" ], "product": [ "create", "edit", "delete", "show" ], "assets": [], "users": [], "readers": [] }
I am using Vuex, but for this problem i have removed most references to it.
Thanks #IVOGELOV i figured it out, though it is not as neat, but will have to do for now, i changed the
<v-checkbox v-model="result[indexe][index]" :label="item" :value="item" ></v-checkbox>
and
`checks: { 0: "create", 1: "edit", 2: "delete", "show",},`
and that did it, i got the array of checkboxes, i don't know why it worked, but it did. we'll improve my structure going forward but this will do for now.
I wanted to know if it is possible to move rows up & down?
I was using a checkbox feature, & the CRUD data table from the documetation.
I couldn't really find any examples in the documentation.
My v-data-table currently looks like this
<v-data-table
v-model="selected"
:headers="headers"
:items="rows"
:search="search"
disable-pagination
hide-default-footer
show-select
class="elevation-1" >
<template v-slot:item="props">
<tr>
<td>
<v-checkbox
v-model="props.selected"
:disabled="!props.selected && selected.length != 0"
:indeterminate="!props.selected && selected.length != 0"
></v-checkbox>
</td>
<td v-for="(prop, key) in props.item" :key="key" #click="onClickItem(key, props.item[key])">
{{props.item[key]}}</td>
<td>
<v-icon small class="mr-2" #click="editItem(props.item)">
mdi-pencil
</v-icon>
<v-icon small #click="deleteItem(props.item, getItemAtIndex(navItem))">
mdi-delete
</v-icon>
</td>
</tr>
</template>
<template> <!-- A dialog box for editing content-->
</template>
</v-data-table>
You can take a look at this example. The example has up and down arrow which you will click and it will update the items array. Note that you must you use Vue.$set to make the update to the items array reactive.
The example is done using vue-composition api and typescript
https://gist.github.com/JeremyWalters/457ea585bab678b3bafeb3ee16e96401
<template>
<v-data-table :headers="headers" :items="items">
<template v-slot:item.actionUp="{item}">
<v-btn color="success" icon #click="moveUp(item.id)">
<v-icon>mdi-arrow-up</v-icon>
</v-btn>
</template>
<template v-slot:item.actionDown="{item}">
<v-btn color="warning" icon #click="moveDown(item.id)">
<v-icon>mdi-arrow-down</v-icon>
</v-btn>
</template>
</v-data-table>
</template>
<script lang="ts">
import {
defineComponent,
SetupContext,
ref,
onMounted,
Ref
} from "#vue/composition-api";
export default defineComponent({
setup(props: any, context: SetupContext) {
const items: Ref<any[]> = ref([]);
const headers = [
{ text: "Test Value", value: "testValue" },
{ text: "", value: "actionUp" },
{ text: "", value: "actionDown" }
];
// Create data example
onMounted(() => {
for (let i = 0; i < 20; i++) {
items.value.push({ id: i, testValue: "testValue " + i });
}
});
// Move items up in the array
function moveUp(id: number) {
const index = items.value.findIndex(e => e.id == id);
if (index > 0) {
const el = items.value[index];
context.root.$set(items.value, index, items.value[index - 1]);
context.root.$set(items.value, index - 1, el);
}
}
// Move items down in the array
function moveDown(id: number) {
const index = items.value.findIndex(e => e.id == id);
debugger;
if (index !== -1 && index < items.value.length - 1) {
const el = items.value[index];
context.root.$set(items.value, index, items.value[index + 1]);
context.root.$set(items.value, index + 1, el);
}
}
return {
moveUp,
moveDown,
headers,
items
};
}
});
</script>
I am new to Vue and trying to make a blog project.
In above image when i click on reply button a dialog box opens and i submit a reply to the comment.
But the problem here is that After submitting the form and on dialog=false the new submitted reply doesn't show in the list.
my code is
<v-btn
#click="handleReply(comment.id)"
>Reply</v-btn>
<v-dialog v-model="dialog" max-width="400">
<v-card>
<v-card-title>
<span class="headline">{{ formTitle }}</span>
</v-card-title>
<v-card-text>
<v-form ref="replyForm" v-model="isFormValid" lazy-validation>
<v-text-field v-model="editedReply.reply" label="reply" required></v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="primary" text #click="close">Cancel</v-btn>
<v-btn
color="primary"
#click.prevent="handleSubmit"
:disabled="!isFormValid || isProcessing"
:loading="isProcessing"
>Save</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
and
handleReply(id) {
this.dialog = true;
this.editedReply.comment_id = id;
},
handleSubmit() {
this.isProcessing = true;
axios
.post(`/replies`, { reply: this.editedReply })
.then(res => {
this.isProcessing = false;
const newEntry = res.data.reply;
this.replies.push(newEntry);
this.dialog = false;
},
Here this.editedReply presents the state of all params which are
editedReply: {
reply: null,
comment_id: null,
name: JSON.parse(localStorage.getItem("user")).name,
email: JSON.parse(localStorage.getItem("user")).email
}
we are getting comment id from handleReply method.
thanks:)
I am using VueJS and Vuetify to create a modal that can accept some strings in the text field. Now what i want to do is to push the input string inside an array on click. So let's say if i input something and click create the resultant array is ['inputValue1'] but if i add another value by separating with a comma, the resultant array should be ['inputValue1', 'inputValue2'] instead i am getting it as ['inputValue1', 'inputValue1' 'inputValue2']. So the new value should be pushed to the new index instead of adding it with the last value.
Here is a demo
new Vue({
el: "#app",
data() {
return {
dialog: false,
inputValue: "",
stringArray: []
};
},
methods: {
createArray() {
if (this.inputValue !== "") {
this.stringArray.push(this.inputValue);
console.log(this.stringArray);
}
},
closeDialog() {
this.dialog = false;
this.inputValue = "";
this.stringArray = [];
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.js"></script>
<div id="app">
<v-app id="inspire">
<v-layout justify-center>
<v-flex>
<v-btn color="primary" #click="dialog=!dialog"> Click Me </v-btn>
</v-flex>
</v-layout>
<v-dialog v-model="dialog" width=350>
<v-card>
<v-card-title primary-title>
Create Array
</v-card-title>
<v-card-text>
<span class="title">How to create Array of Strings </span>
<v-layout justify-center>
<v-flex xs11>
<v-text-field v-model="inputValue"></v-text-field>
</v-flex>
</v-layout>
</v-card-text>
<v-card-actions class="mt-5">
<v-spacer></v-spacer>
<v-btn #click="closeDialog">CLOSE</v-btn>
<v-btn #click="createArray" :disabled="this.inputValue === ''" color="primary">CREATE</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-app>
</div>
Also on Cancel how can i set the input value and the array to an empty string and an empty array respectively. Thank You. I asked it yesterday but had to delete since i wasn't able to figure out the exact issue.
Your `createArray' method is not attached to any click event. Other than that the code is correct. :)
You should clear the inputValue after the value is pushed to the array like this:
methods: {
createArray() {
if (this.inputValue !== "") {
this.stringArray.push(this.inputValue);
this.inputValue = '';
console.log(this.stringArray);
} else {
console.log('The inputValue is empty')
}
},
closeDialog() {
this.dialog = false;
this.inputValue = "";
this.stringArray = []
}
}
});