I am trying to change result value between true/false by other values. I want set result to true, if all other values are not empty.
I think it looks like good, but result property returns true all time. So i can not hide result <p> tag.
<script src="https://unpkg.com/vue#3.2.37/dist/vue.global.prod.js"></script>
<div id="app">
<label>
Name :
<input type="text" v-model="name" />
</label>
<label>
Size :
<input type="text" v-model="size" />
</label>
<label>
Quantity :
<input type="text" v-model="quantity" />
</label>
<p v-if="result">Summary: {{ name }} - {{ size }} - {{ quantity }}</p>
</div>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
name: '',
size: '',
quantity: '',
result: this.name !== '' && this.size !== '' && this.quantity !== '',
};
},
}).mount('#app');
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: left;
color: #2c3e50;
margin-top: 60px;
}
label {
display: block;
margin: 0 0 10px;
}
input {
display: block;
}
</style>
In this case you should defing result as a computed property :
createApp({
data() {
return {
name: '',
size: '',
quantity: '',
};
},
computed:{
result(){
return this.name !== '' && this.size !== '' && this.quantity !== ''
}
}
}).mount('#app');
I am trying to add multiple product in the cart. I am using vuejs and django rest framework. My problem is: When I add a product into the cart it added successfully But when I add another product it doesnt add. It adds the same product again and again.
For example:
I have three products named "A" and "B" and "C". I added "A". Then i try to add "C" in the cart. But it stills adds "A" in the cart. I cleared the session and tried again still add the "A" product if I try to add "C" product first. It always add "A" product.
Here is my store/index.js:
import { createStore } from 'vuex'
export default createStore({
state: {
cart: {
items: []
},
isAuthenticated: false,
token: '',
isLoading: false,
},
mutations: {
initializeStore(state){
if(localStorage.getItem('cart')){
state.cart = JSON.parse(localStorage.getItem('cart'))
}
else{
localStorage.setItem('cart', JSON.stringify(state.cart))
}
},
addToCart(state, item) {
let exists = state.cart.items.filter(i => i.product.id === item.product.id)
if (exists.length){
exists[0].quantity = parseInt(exists[0].quantity) + parseInt(item.quantity)
}
else{
state.cart.items.push(item)
}
localStorage.setItem('cart', JSON.stringify(state.cart))
}
},
actions: {
},
modules: {
}
})
Here is my add to cart page and code:
<template>
<br />
<div class="col">
<div class="col1">
<img v-bind:src="product.get_image" alt="">
</div>
<div class="col2">
<div class="product__title">
<p>PRODUCT TITLE</p>
<h2>{{ product.name }}</h2>
<small>{{ product.short_description }}</small>
</div>
<div class="product__price">
<p>Price: $ {{ product.price }}</p>
</div>
<div class="product__button">
<input type="hidden" v-model="quantity" min="1">
<button type="submit" class="button__primary" #click="addToCart">Add To Cart</button>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
import {toast} from 'bulma-toast'
export default {
name: "ProductDetail",
data () {
return {
product: {},
quantity: 1
}
},
mounted() {
this.getProduct()
},
methods: {
getProduct() {
const categorySlug = this.$route.params.category_slug
const productSlug = this.$route.params.product_slug
axios.get(`/api/product-details/${categorySlug}/${productSlug}/`)
.then(response => {
this.product = response.data
})
.catch(error => {
console.log(error)
})
},
addToCart() {
if(isNaN(this.quantity) || this.quantity < 1){
this.quantity = 1
}
const item = {
product: this.product,
quantity: this.quantity
}
this.$store.commit("addToCart", item)
toast({
message: "Product has been added to cart" + item.product.name,
type: "is-success",
pauseOnHover: true,
duration: 2000,
position: "bottom-right",
dismissible: true,
})
}
}
}
</script>
<style scoped>
.col {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 5rem;
height: 50vh;
padding: 60px;
}
.col1 {
height: 520px;
width: 100%;
}
.col1 img{
object-fit: fill;
height: 520px;
width: 100%;
}
.col2 {
display: grid;
grid-auto-rows: 1fr 1fr 1fr 1fr;
background: #fff;
padding: 12px;
}
.product__button button{
height: 40px;
width: 100%;
border: none;
background: #007bc4;
color: #fff;
border-radius: 3px;
}
.product__price p {
color: #007bc4;
font-size: 18px;
}
</style>
Here is the cartitem component:
<template>
<tr class="is-fullwidth">
<td>{{ item.product.name }}</td>
<td>$ {{ item.product.price }}</td>
<td>
<button #click="increment(item)" class="plusButton">+</button>
{{ item.quantity }}
<button #click="decrement(item)" class="minusButton">-</button>
</td>
<td>{{ getTotal(item).toFixed(2) }}</td>
<td><button class="delete"></button></td>
</tr>
</template>
<script>
export default {
name: "Cartitem",
props: {
initialItem: Object
},
data() {
return {
item: this.initialItem
}
},
methods: {
getTotal(item) {
return item.quantity * item.product.price
},
increment(item){
item.quantity += 1
this.updateCart()
},
decrement(item) {
item.quantity -= 1
if(item.quantity === 0){
this.$emit('removeFromCart', item)
}
this.updateCart()
},
updateCart() {
localStorage.setItem('cart', JSON.stringify(this.$store.state.cart))
},
removeFromCart(item) {
this.$emit('removeFromCart', item)
this.updateCart()
}
}
}
</script>
<style scoped>
.plusButton{
border: none;
background: #fff;
font-size: 19px;
}
.minusButton{
border: none;
background: #fff;
font-size: 19px;
}
</style>
I am new in vue js. I am trying to build this projetc so that i can learn. But this issue is eating my brain. I tried to use find function in sotre/index.js. It solved my problem though but if i clear the cookies and try to add product it gives me error.
is there any solution for me?
Thanks in advance.
I had set up a disable system if my form fields are not filled in and I want to move it to a custom component but the problem is that it doesn't work anymore, I think I have targeted the problem but I don't see how to solve it. I guess because it doesn't find my this.email, this.password etc. If you can help me please
<template>
<button
class="btn"
:class="{ 'btn--disabled': !validatedFields }"
:disabled="!validatedFields"
>
<slot></slot>
</button>
</template>
<script>
export default {
props: ["disabled"],
computed: {
validatedFields() {
if (this.signup) {
if (this.email != "" && this.password != "") {
return true;
} else {
return false;
}
} else {
if (this.email != "" && this.password != "") {
return true;
} else {
return false;
}
}
},
},
};
</script>
<style lang="scss" scoped>
#import "../scss/main.scss";
.btn {
width: 100%;
margin: 1rem 0;
background: $secondary;
color: #ffff;
border: none;
padding: 1rem 2rem;
}
.btn--disabled {
color: red;
}
</style>
<template>
<section>
<div class="form">
<transition name="test" mode="out-in">
<form key="login" v-if="login" #submit.prevent="login">
<h1>Connexion</h1>
<custom-input
icon="fa-at"
name="email"
type="email"
placeholder="email#gmail.com"
#updated="updatedEmail"
/>
<custom-input
icon="fa-lock"
name="password"
type="password"
placeholder="Mot de passe"
#updated="updatedPassword"
/>
<custom-btn>Connexion</custom-btn>
<p #click="login = !login">Déjà un compte ?</p>
</form>
<form
action=""
key="signup"
v-else
novalidate
#submit.prevent="createAccount"
>
<h1>Inscription</h1>
<custom-input
icon="fa-at"
name="email"
type="email"
placeholder="email#gmail.com"
#updated="updatedEmail"
/>
<custom-input
icon="fa-lock"
name="password"
type="password"
placeholder="Mot de passe"
#updated="updatedPassword"
/>
<custom-input
icon="fa-lock"
name="RepeatPassword"
type="password"
placeholder="Répéter votre mot de passe"
#updated="updatedPassword"
/>
<custom-input
icon="fa-user"
name="name"
type="text"
placeholder="John"
#updated="updatedName"
/>
<custom-file />
<custom-btn>Inscription</custom-btn>
<p #click="login = !login">Pas de compte?</p>
</form>
</transition>
</div>
</section>
</template>
<script>
// import signup from "../assets/signup.jpg";
// import connex from "../assets/connex.jpg";
import CustomInput from "./Input.vue";
import CustomBtn from "./Button.vue";
import CustomFile from "./FileInput.vue";
export default {
components: {
CustomInput,
CustomBtn,
CustomFile,
},
data() {
return {
login: true,
file: null,
};
},
methods: {
onFileChanges(event) {
let files = event.target.files || event.dataTransfer.files;
if (!files.length) return;
this.file = files[0];
},
updatedEmail(email) {
this.email = email;
},
updatedPassword(password) {
this.password = password;
},
updatedName(name) {
this.name = name;
},
},
};
</script>
<style lang="scss" scoped>
#import "../scss/main.scss";
section {
padding: 2rem;
.form {
background: #ffff;
box-shadow: 0px 15px 16.83px 0.17px rgb(0 0 0 / 5%);
border-radius: 10px;
padding: 2rem;
h1 {
text-align: center;
font-size: 1.8rem;
margin-bottom: 1rem;
color: $secondary;
}
p {
text-align: center;
margin-top: 1rem;
}
}
.test-enter-active,
.test-leave-active {
transition: opacity 0.5s;
}
.test-enter,
.test-leave-active {
opacity: 0;
}
}
</style>
Assign filename to input field on upload and then show success message working fine,but when i try to delete file and upload again it's not working!
new Vue({
el: "#app",
data() {
return {
form: {
message: '',
fileurl: ''
},
loading: false
}
},
methods: {
uploadImage(event) {
this.form.fileurl = 'uploaded!'
},
deleteFile(furl) {
this.form.fileurl = ''
}
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
span {
color: red;
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
<div id="app">
<h3>
File Upload / remove Demo
</h3>
<hr />
<div class="custom-file attach_file" v-show="!form.fileurl">
<input type="file" id="file" name="file" #change="uploadImage($event)">
<input type="text" v-model="form.fileurl">
</div>
<p v-if="form.fileurl"> {{ form.fileurl }} <span #click="deleteFile(form.fileurl)">Delete</span></p>
</div>
I am not getting any console error as well.
This is what i have tried so far.
Can you guys please have a look at this!
The problem is that #change is not trigger when you choose the same file. The simplest solution is reset value of input when you click delete
this.$refs.fileToUpload.value = '';
new Vue({
el: "#app",
data() {
return {
form: {
message: '',
fileurl: ''
},
loading: false
}
},
methods: {
uploadImage(event) {
this.form.fileurl = 'uploaded!'
},
deleteFile(furl) {
this.form.fileurl = ''
this.$refs.fileToUpload.value = '';
}
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
span {
color: red;
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
<div id="app">
<h3>
File Upload / remove Demo
</h3>
<hr />
<div class="custom-file attach_file" v-show="!form.fileurl">
<input type="file" id="file" name="file" class="custom-file-input" #change="uploadImage($event)" ref="fileToUpload">
<input type="text" v-model="form.fileurl">
</div>
<p v-if="form.fileurl"> {{ form.fileurl }} <span #click="deleteFile(form.fileurl)">Delete</span></p>
</div>
You need to clear you input field first.
Update your upload method with this.
uploadImage(event) {
this.form.fileurl = 'uploaded!'
this.success = false
this.$nextTick(() => {
this.success = true
})
Have a look at this working demo
https://jsfiddle.net/asimshahzad/8c9pcfys/
I'm using Vuejs and dataTable for one of my project. I make an Ajax call and push data into an array. After that I use v-for to loop the data in the <tr> tag. Most of the time it doesn't work. The table loads as soon as the page has finished loading.. it takes a bit of time to receive the ajax data. Here is the output. It says no data available in the table
So the serch option doesn't work properly. I thought to use a setTimeout function (which was a bad idea) to load the table after a bit of time. What would be the proper way to do it? Sharing the code :
new Vue({
el: '#app',
data: {
entries: [],
},
methods:{
getData(){
var route = '/admin/temporary-enrolled-students';
this.$http.get(route).then((response)=>{
for(var i = 0; i< response.data.length;i++)
{
this.entries.push({
scId: response.data[i].id,
name: response.data[i].user.name,
phone: response.data[i].user.phone,
email: response.data[i].user.email,
courseId: response.data[i].course.id,
courseName: response.data[i].course.course_title,
expiryDate: response.data[i].expiry_date,
shares: response.data[i].number_of_shares,
expired: (response.data[i].expired == 1),
enrollDate: response.data[i].created_at
})
}
})
},
},
mounted(){
this.getData();
},
});
//data table
$(function () {
setTimeout(()=> {
$("#temp-enroll").DataTable({
"paging": true,
"ordering": false,
"info": true,
"autoWidth": false
});
},1000);
});
in blade:
Ok I tried this and working exactly what I have wanted. Thanks everyone for supporting.
new Vue({
el: '#app',
data: {
entries: [],
},
methods:{
getData(){
var route = '/admin/temporary-enrolled-students';
this.$http.get(route).then((response)=>{
for(var i = 0; i< response.data.length;i++)
{
this.entries.push({
scId: response.data[i].id,
name: response.data[i].user.name,
............................
......................
enrollDate: response.data[i].created_at
})
}
}).then(()=>{
$("#temp-enroll").DataTable({
"paging": true,
"ordering": false,
"info": true,
"autoWidth": false
});
});
},
},
mounted(){
this.getData();
},
});
I think someone mentioned that a computed property is the way to go, and that is what I would recommend as well.
The reason why is that as soon as your template makes a reference to the computed property, this triggers your ajax call. The page will then render any other available elements, and when your ajax call returns, it will then render the data it received. No special action in code is required.
Anyway, here is what it would look like...
In your html, as an example...
<table>
<tr v-for="item in serverData">
<td>{{item.name}}</td>
<td>{{item.someOtherValue}}</td>
</tr>
</table>
export default {
name: 'pets',
data () {
return {
}
},
computed: {
serverData: function() {
// ajax call using axios - returns a json array []
axios.get("http://localhost:8080/getSomeData")
.success(function(data) {
return data;
};
}
}
}
Notice the return in the success promise returned from the ajax call - there is no need to store the data to another variable (and you should definitely not have to loop through it like the noob coder example above shows. Do that on the server, return an array ready to render - if it isn't your web service, then write your own that calls the original and do the data manipulation there).
The parts of your template that reference the computed value will render after the data arrives - there is no need to watch it.
Hope this helps!
Vue is the bomb!
<template>
<div class="panel panel-default tablecontainer">
<div class="panel-heading">ChartBookin Import</div>
<br>
<div class='col-md-12'>
<div class='col-md-3'></div>
<div class='col-md-3'>
<div class="panel panel-default">
<div class="panel-body">
<commitChart :width="150"
:height="150"></commitChart>
</div>
</div>
</div>
<div class='col-md-3'>
<div class="panel panel-default">
<div class="panel-body">
<InboxMessage :width="150"
:height="150"></InboxMessage>
</div>
</div>
</div>
</div>
<div class="panel-body">
<div class='col-md-3'>
<label> by Account </label>
<select v-model="teamId" class="form-control" rows="3">
<option VALUE="" disabled> CHOISIR UN TEAM</option>
<option v-for="option in options" v-bind:value="option.id">{{option.name}}</option>
</select>
</div>
<div class='col-md-3'>
<label> by Date</label>
<div class="form-group">
<input type="text" class="form-control" name="daterange"
value="01/01/2017-01/31/2017"/>
</div>
</div>
<div class='col-md-5'></div>
<div class='col-md-1'>
<label>Records</label>
<div class="form-group">
<select v-model="elementsPerPage" class="form-control">
<option v-for="option in filtre" v-bind:value="option">
{{ option }}
</option>
</select>
</div>
</div>
<div id="sixthTable">
<table class="table-bordered table-striped table-bordered table-hover">
<thead>
<tr>
<th v-for=" (key,value) in rows[0]" v-on:click="sortTable(value)">{{value}}
<div class="arrow" v-if="value == sortColumn"
v-bind:class="[ascending ? 'arrow_up' : 'arrow_down']"></div>
</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-if=" rows.length > 0" v-for="row in rows">
<td v-for="(key, value) in row">{{ key }}</td>
<td>
<a :href="'/stat_booking_import/' + row.Id">
<span class="glyphicon glyphicon-eye-open"></span>
</a>
</td>
</tr>
<tr v-else> No Result Founded</tr>
</tbody>
</table>
<div class="pagination">
<div id="paginatebutton">
«
<a class="" v-for="i in num_pages()"
v-bind:class="[i == currentPage ? 'active' : '']"
v-on:click="change_page(i)">{{i}}
</a>
»
</div>
<div class="col-md-12" id="paginatetexte">
<p v-if="pages > (elementsPerPage*currentPage) ">
Showing 1 to {{elementsPerPage * currentPage }} of {{ pages }} records
</p>
<p v-else>
Showing 1 to {{pages}} of {{ pages }} records
</p>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import Vue from 'vue';
import axios from 'axios';
import CommitChart from './Mail';
import InboxMessage from './Inbox';
export default {
components: {
CommitChart,
InboxMessage
},
data() {
return {
filtre: [10, 25, 50, 100],
option: 0,
options: [],
currentPage: 1,
elementsPerPage: 10,
pages: 0,
ascending: false,
sortColumn: '',
startdate: null,
enddate: null,
options: [],
teamId: null,
columns: [],
messages: [],
date: 0,
rows: {},
}
},
created() {
this.getData();
this.getTeams();
this.getMailInbox();
},
mounted() {
let vm = this;
$(document).ready(function () {
$('input[name="daterange"]').daterangepicker({
ranges: {
'Today': [moment(), moment()],
'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
'Last 7 Days': [moment().subtract(6, 'days'), moment()],
'This Month': [moment().startOf('month'), moment().endOf('month')]
},
locale: {
format: 'YYYY-MM-DD'
},
});
$('.applyBtn').click(function () {
vm.startdate = $("input[name=daterangepicker_start]").val();
vm.enddate = $("input[name=daterangepicker_end]").val();
vm.getData();
});
$('input[name="daterange"]').on('apply.daterangepicker', function (ev, picker) {
vm.startdate = $("input[name=daterangepicker_start]").val();
vm.enddate = $("input[name=daterangepicker_end]").val();
vm.getData();
});
});
},
watch: {
date: function () {
this.getData();
},
teamId: function () {
this.getData();
},
elementsPerPage: function () {
this.getData();
}
},
methods: {
getData() {
axios.get(`/admin/stat_booking_import.json/` + this.startdate + `/` + this.teamId + `/` + this.enddate + `/` + this.elementsPerPage + `?page=` + this.currentPage)
.then(response => {
this.rows = response.data.elements.data;
this.columns = Object.keys(this.rows[0]);
this.pages = response.data.elements.total_element;
})
.catch(e => {
this.errors.push(e)
})
},
getTeams() {
axios.get('/admin/team.json')
.then(response => {
this.options = response.data.data;
this.errors = [];
})
.catch(e => {
e.message = "aucun resultat trouvé essayer de choisir une autre date";
this.errors.push(e)
})
},
getMailInbox() {
axios.get(`/mailstorage.json`)
.then(response => {
this.messages = response.data.data;
console.log(this.messages);
})
.catch(e => {
this.errors.push(e)
});
},
sortTable(col) {
if (this.sortColumn === col) {
this.ascending = !this.ascending;
} else {
this.ascending = true;
this.sortColumn = col;
}
var ascending = this.ascending;
this.rows.sort(function (a, b) {
if (a[col] > b[col]) {
return ascending ? 1 : -1
} else if (a[col] < b[col]) {
return ascending ? -1 : 1
}
return 0;
})
},
num_pages() {
return Math.ceil(this.pages / this.elementsPerPage);
},
get_rows() {
var start = (this.currentPage - 1) * this.elementsPerPage;
var end = start + this.elementsPerPage;
return this.rows.slice(start, end);
},
change_page(page) {
this.currentPage = page;
this.getData();
}
},
}
</script>
<style type="text/css">
table {
width: 100%;
}
table td {
text-align: center;
}
table td {
text-align: center;
padding: 8px;
}
table td:last-child {
border-right: none;
}
.pagination {
display: inline-block;
}
.pagination a {
color: #3097D1;
float: left;
padding: 8px 16px;
text-decoration: none;
transition: background-color .3s;
border: 1px solid #ddd;
}
.pagination a.active {
background-color: #3097D1;
color: white;
border: 1px solid #3097D1;
}
.arrow_down {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB8AAAAaCAYAAABPY4eKAAAAAXNSR0IArs4c6QAAAvlJREFUSA29Vk1PGlEUHQaiiewslpUJiyYs2yb9AyRuJGm7c0VJoFXSX9A0sSZN04ULF12YEBQDhMCuSZOm1FhTiLY2Rky0QPlQBLRUsICoIN/0PCsGyox26NC3eTNn3r3n3TvnvvsE1PkwGo3yUqkkEQqFgw2Mz7lWqwng7ztN06mxsTEv8U0Aam5u7r5EInkplUol/f391wAJCc7nEAgE9Uwmkzo4OPiJMa1Wq6cFs7Ozt0H6RqlUDmJXfPIx+qrX69Ti4mIyHA5r6Wq1egND+j+IyW6QAUoul18XiUTDNHaSyGazKcZtdgk8wqhUKh9o/OMvsVgsfHJy0iWqVrcQNRUMBnd6enqc9MjISAmRP3e73T9al3XnbWNjIw2+KY1Gc3imsNHR0YV4PP5+d3e32h3K316TySQFoX2WyWR2glzIO5fLTSD6IElLNwbqnFpbWyO/96lCoai0cZjN5kfYQAYi5H34fL6cxWIZbya9iJyAhULBHAqFVlMpfsV/fHxMeb3er+Vy+VUzeduzwWC45XA4dlD/vEXvdDrj8DvURsYEWK3WF4FA4JQP9mg0WrHZbEYmnpa0NxYgPVObm5teiLABdTQT8a6vrwdRWhOcHMzMzCiXlpb2/yV6qDttMpkeshEzRk4Wo/bfoe4X9vb2amzGl+HoXNT29vZqsVi0sK1jJScG+Xx+HGkL4Tew2TPi5zUdQQt9otPpuBk3e0TaHmMDh1zS7/f780S0zX6Yni+NnBj09fUZUfvudDrNZN+GkQbl8Xi8RLRtHzsB9Hr9nfn5+SjSeWUCXC7XPq5kw53wsNogjZNohYXL2EljstvtrAL70/mVaW8Y4OidRO1/gwgbUMvcqGmcDc9aPvD1gnTeQ+0nmaInokRj0nHh+uvIiVOtVvt2a2vLv7Ky0tL3cRTXIcpPAwMDpq6R4/JXE4vFQ5FI5CN+QTaRSFCYc8vLy1l0rge4ARe5kJ/d27kYkLXoy2Jo4C7K8CZOsEBvb+9rlUp1xNXPL7v3IDwxvPD6AAAAAElFTkSuQmCC')
}
.arrow_up {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAaCAYAAACgoey0AAAAAXNSR0IArs4c6QAAAwpJREFUSA21Vt1PUmEYP4dvkQ8JFMwtBRocWAkDbiqXrUWXzU1rrTt0bdVqXbb1tbW16C9IBUSmm27cODdneoXjputa6069qwuW6IIBIdLvdaF4OAcOiGeDc87zPs/vd57P96WpFq7p6enbGo1mjKZpeTabjU1MTCRagGnOZHFxcXxtbe1XKpUq7+zslJeXl//Mz8+Hy+Uy3RxSE9qTk5M3otFooVQqgef4Wl9f343FYoEmoISrxuNxFX5f9vb2jhn/PxUKhfLS0tIPfFifUESRUMV8Pv/M6XReRm5rTGQyGeXxeGxYe1ezeBpBOBx2rKysbO7v79d4Wy3Y2Nj4GQqFbgnhaugxwiuGJx99Pp9FLBbXxYTXvTqd7v3MzIy6riIWGxJnMpl7AwMD14xGYyMsSq1WUyQdUqn0eSPlusQIsbGrq+vl4OCgvhFQZd1utyv1en0gEolcqsi47nWJlUrlG5fLZVcoFFy2nDKSDpIWlUoVTCQSEk4lCHmJMZ2GTCbTiMVikfIZ88l7enoos9l8dXt7+z6fDicxSJUokqDX6xXcl2wCROoc0vQCWL3sNfLOSdzR0fHY4XC4tVotl40gmVwup9xuN4OQv+UyqCFGH9rg7SOGYVRcBs3IEG4J0nVnamrqOtvuBDGGgQg9+wHFcVEi4a0LNkbdd6TrPKo8ODc311mteIIYjT/a398/jK+s1jnVM0kXoufCFvq0GuiIGEVgQIhfoygM1QrteEa9dAL7ITiYCt4RMabOK5AyKKzKWtvupLcRciu8D5J0EuDDPyT/Snd39yh6VtY2NhYQSR9G79Ds7OxdskRjEyAufvb7/cPoO5Z6e1+xtVKrq6vfcFzyi/A3ZrPZ3GdNSlwgo5ekE4X2RIQGf2C1WlufFE0GBeGWYQ8YERWLxQtnUVB830MKLZfL9RHir8lkssCn2G751tZWEWe03zTKm15YWPiEiXXTYDB0Ig/t7yd8PRws4EicwWHxO4jHD8/C5HiTTqd1BwcHFozKU89origB+y/kmzgYpgOBQP4fGmUiZmJ+WNgAAAAASUVORK5CYII=')
}
.arrow {
float: right;
width: 12px;
height: 15px;
background-repeat: no-repeat;
background-size: contain;
background-position-y: bottom;
}
.number {
display: inline-block;
padding: 4px 10px;
margin: 0px 5px;
cursor: pointer;
}
.number:hover,
.number.active {
background-color: #3097D1;
border-color: #3097D1;
}
#paginatetexte {
padding-top: 6%;
import Vue from 'vue'
new Vue({
el: '#statistique',
render: h => h(require('./StatBookingImport.vue'))
});
<style type="text/css">
table {
width: 100%;
}
table td {
text-align: center;
}
table td {
text-align: center;
padding: 8px;
}
table td:last-child {
border-right: none;
}
.pagination {
display: inline-block;
}
.pagination a {
color: #3097D1;
float: left;
padding: 8px 16px;
text-decoration: none;
transition: background-color .3s;
border: 1px solid #ddd;
}
.pagination a.active {
background-color: #3097D1;
color: white;
border: 1px solid #3097D1;
}
.arrow_down {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB8AAAAaCAYAAABPY4eKAAAAAXNSR0IArs4c6QAAAvlJREFUSA29Vk1PGlEUHQaiiewslpUJiyYs2yb9AyRuJGm7c0VJoFXSX9A0sSZN04ULF12YEBQDhMCuSZOm1FhTiLY2Rky0QPlQBLRUsICoIN/0PCsGyox26NC3eTNn3r3n3TvnvvsE1PkwGo3yUqkkEQqFgw2Mz7lWqwng7ztN06mxsTEv8U0Aam5u7r5EInkplUol/f391wAJCc7nEAgE9Uwmkzo4OPiJMa1Wq6cFs7Ozt0H6RqlUDmJXfPIx+qrX69Ti4mIyHA5r6Wq1egND+j+IyW6QAUoul18XiUTDNHaSyGazKcZtdgk8wqhUKh9o/OMvsVgsfHJy0iWqVrcQNRUMBnd6enqc9MjISAmRP3e73T9al3XnbWNjIw2+KY1Gc3imsNHR0YV4PP5+d3e32h3K316TySQFoX2WyWR2glzIO5fLTSD6IElLNwbqnFpbWyO/96lCoai0cZjN5kfYQAYi5H34fL6cxWIZbya9iJyAhULBHAqFVlMpfsV/fHxMeb3er+Vy+VUzeduzwWC45XA4dlD/vEXvdDrj8DvURsYEWK3WF4FA4JQP9mg0WrHZbEYmnpa0NxYgPVObm5teiLABdTQT8a6vrwdRWhOcHMzMzCiXlpb2/yV6qDttMpkeshEzRk4Wo/bfoe4X9vb2amzGl+HoXNT29vZqsVi0sK1jJScG+Xx+HGkL4Tew2TPi5zUdQQt9otPpuBk3e0TaHmMDh1zS7/f780S0zX6Yni+NnBj09fUZUfvudDrNZN+GkQbl8Xi8RLRtHzsB9Hr9nfn5+SjSeWUCXC7XPq5kw53wsNogjZNohYXL2EljstvtrAL70/mVaW8Y4OidRO1/gwgbUMvcqGmcDc9aPvD1gnTeQ+0nmaInokRj0nHh+uvIiVOtVvt2a2vLv7Ky0tL3cRTXIcpPAwMDpq6R4/JXE4vFQ5FI5CN+QTaRSFCYc8vLy1l0rge4ARe5kJ/d27kYkLXoy2Jo4C7K8CZOsEBvb+9rlUp1xNXPL7v3IDwxvPD6AAAAAElFTkSuQmCC')
}
.arrow_up {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAaCAYAAACgoey0AAAAAXNSR0IArs4c6QAAAwpJREFUSA21Vt1PUmEYP4dvkQ8JFMwtBRocWAkDbiqXrUWXzU1rrTt0bdVqXbb1tbW16C9IBUSmm27cODdneoXjputa6069qwuW6IIBIdLvdaF4OAcOiGeDc87zPs/vd57P96WpFq7p6enbGo1mjKZpeTabjU1MTCRagGnOZHFxcXxtbe1XKpUq7+zslJeXl//Mz8+Hy+Uy3RxSE9qTk5M3otFooVQqgef4Wl9f343FYoEmoISrxuNxFX5f9vb2jhn/PxUKhfLS0tIPfFifUESRUMV8Pv/M6XReRm5rTGQyGeXxeGxYe1ezeBpBOBx2rKysbO7v79d4Wy3Y2Nj4GQqFbgnhaugxwiuGJx99Pp9FLBbXxYTXvTqd7v3MzIy6riIWGxJnMpl7AwMD14xGYyMsSq1WUyQdUqn0eSPlusQIsbGrq+vl4OCgvhFQZd1utyv1en0gEolcqsi47nWJlUrlG5fLZVcoFFy2nDKSDpIWlUoVTCQSEk4lCHmJMZ2GTCbTiMVikfIZ88l7enoos9l8dXt7+z6fDicxSJUokqDX6xXcl2wCROoc0vQCWL3sNfLOSdzR0fHY4XC4tVotl40gmVwup9xuN4OQv+UyqCFGH9rg7SOGYVRcBs3IEG4J0nVnamrqOtvuBDGGgQg9+wHFcVEi4a0LNkbdd6TrPKo8ODc311mteIIYjT/a398/jK+s1jnVM0kXoufCFvq0GuiIGEVgQIhfoygM1QrteEa9dAL7ITiYCt4RMabOK5AyKKzKWtvupLcRciu8D5J0EuDDPyT/Snd39yh6VtY2NhYQSR9G79Ds7OxdskRjEyAufvb7/cPoO5Z6e1+xtVKrq6vfcFzyi/A3ZrPZ3GdNSlwgo5ekE4X2RIQGf2C1WlufFE0GBeGWYQ8YERWLxQtnUVB830MKLZfL9RHir8lkssCn2G751tZWEWe03zTKm15YWPiEiXXTYDB0Ig/t7yd8PRws4EicwWHxO4jHD8/C5HiTTqd1BwcHFozKU89origB+y/kmzgYpgOBQP4fGmUiZmJ+WNgAAAAASUVORK5CYII=')
}
.arrow {
float: right;
width: 12px;
height: 15px;
background-repeat: no-repeat;
background-size: contain;
background-position-y: bottom;
}
.number {
display: inline-block;
padding: 4px 10px;
margin: 0px 5px;
cursor: pointer;
}
.number:hover,
.number.active {
background-color: #3097D1;
border-color: #3097D1;
}
#paginatetexte {
padding-top: 6%;
}
#paginatebutton {
border-radius: 1px;
}
.tablecontainer {
margin-right: 2%;
margin-left: 2%;
}
.mailinbox {
margin-left: 1%;
}
</style>
<template>
<div class="panel panel-default tablecontainer">
<div class="panel-heading">ChartBookin Import</div>
<br>
<div class='col-md-12'>
<div class='col-md-3'></div>
<div class='col-md-3'>
<div class="panel panel-default">
<div class="panel-body">
<commitChart :width="150"
:height="150"></commitChart>
</div>
</div>
</div>
<div class='col-md-3'>
<div class="panel panel-default">
<div class="panel-body">
<InboxMessage :width="150"
:height="150"></InboxMessage>
</div>
</div>
</div>
</div>
<div class="panel-body">
<div class='col-md-3'>
<label> by Account </label>
<select v-model="teamId" class="form-control" rows="3">
<option VALUE="" disabled> CHOISIR UN TEAM</option>
<option v-for="option in options" v-bind:value="option.id">{{option.name}}</option>
</select>
</div>
<div class='col-md-3'>
<label> by Date</label>
<div class="form-group">
<input type="text" class="form-control" name="daterange"
value="01/01/2017-01/31/2017"/>
</div>
</div>
<div class='col-md-5'></div>
<div class='col-md-1'>
<label>Records</label>
<div class="form-group">
<select v-model="elementsPerPage" class="form-control">
<option v-for="option in filtre" v-bind:value="option">
{{ option }}
</option>
</select>
</div>
</div>
<div id="sixthTable">
<table class="table-bordered table-striped table-bordered table-hover">
<thead>
<tr>
<th v-for=" (key,value) in rows[0]" v-on:click="sortTable(value)">{{value}}
<div class="arrow" v-if="value == sortColumn"
v-bind:class="[ascending ? 'arrow_up' : 'arrow_down']"></div>
</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-if=" rows.length > 0" v-for="row in rows">
<td v-for="(key, value) in row">{{ key }}</td>
<td>
<a :href="'/stat_booking_import/' + row.Id">
<span class="glyphicon glyphicon-eye-open"></span>
</a>
</td>
</tr>
<tr v-else> No Result Founded</tr>
</tbody>
</table>
<div class="pagination">
<div id="paginatebutton">
«
<a class="" v-for="i in num_pages()"
v-bind:class="[i == currentPage ? 'active' : '']"
v-on:click="change_page(i)">{{i}}
</a>
»
</div>
<div class="col-md-12" id="paginatetexte">
<p v-if="pages > (elementsPerPage*currentPage) ">
Showing 1 to {{elementsPerPage * currentPage }} of {{ pages }} records
</p>
<p v-else>
Showing 1 to {{pages}} of {{ pages }} records
</p>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import Vue from 'vue';
import axios from 'axios';
import CommitChart from './Mail';
import InboxMessage from './Inbox';
export default {
components: {
CommitChart,
InboxMessage
},
data() {
return {
filtre: [10, 25, 50, 100],
option: 0,
options: [],
currentPage: 1,
elementsPerPage: 10,
pages: 0,
ascending: false,
sortColumn: '',
startdate: null,
enddate: null,
options: [],
teamId: null,
columns: [],
messages: [],
date: 0,
rows: {},
}
},
created() {
this.getData();
this.getTeams();
this.getMailInbox();
},
mounted() {
let vm = this;
$(document).ready(function () {
$('input[name="daterange"]').daterangepicker({
ranges: {
'Today': [moment(), moment()],
'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
'Last 7 Days': [moment().subtract(6, 'days'), moment()],
'This Month': [moment().startOf('month'), moment().endOf('month')]
},
locale: {
format: 'YYYY-MM-DD'
},
});
$('.applyBtn').click(function () {
vm.startdate = $("input[name=daterangepicker_start]").val();
vm.enddate = $("input[name=daterangepicker_end]").val();
vm.getData();
});
$('input[name="daterange"]').on('apply.daterangepicker', function (ev, picker) {
vm.startdate = $("input[name=daterangepicker_start]").val();
vm.enddate = $("input[name=daterangepicker_end]").val();
vm.getData();
});
});
},
watch: {
date: function () {
this.getData();
},
teamId: function () {
this.getData();
},
elementsPerPage: function () {
this.getData();
}
},
methods: {
getData() {
axios.get(`/admin/stat_booking_import.json/` + this.startdate + `/` + this.teamId + `/` + this.enddate + `/` + this.elementsPerPage + `?page=` + this.currentPage)
.then(response => {
this.rows = response.data.elements.data;
this.columns = Object.keys(this.rows[0]);
this.pages = response.data.elements.total_element;
})
.catch(e => {
this.errors.push(e)
})
},
getTeams() {
axios.get('/admin/team.json')
.then(response => {
this.options = response.data.data;
this.errors = [];
})
.catch(e => {
e.message = "aucun resultat trouvé essayer de choisir une autre date";
this.errors.push(e)
})
},
getMailInbox() {
axios.get(`/mailstorage.json`)
.then(response => {
this.messages = response.data.data;
console.log(this.messages);
})
.catch(e => {
this.errors.push(e)
});
},
sortTable(col) {
if (this.sortColumn === col) {
this.ascending = !this.ascending;
} else {
this.ascending = true;
this.sortColumn = col;
}
var ascending = this.ascending;
this.rows.sort(function (a, b) {
if (a[col] > b[col]) {
return ascending ? 1 : -1
} else if (a[col] < b[col]) {
return ascending ? -1 : 1
}
return 0;
})
},
num_pages() {
return Math.ceil(this.pages / this.elementsPerPage);
},
get_rows() {
var start = (this.currentPage - 1) * this.elementsPerPage;
var end = start + this.elementsPerPage;
return this.rows.slice(start, end);
},
change_page(page) {
this.currentPage = page;
this.getData();
}
},
}
</script>
}
#paginatebutton {
border-radius: 1px;
}
.tablecontainer {
margin-right: 2%;
margin-left: 2%;
}
.mailinbox {
margin-left: 1%;
}
</style>
You could try watch property https://v2.vuejs.org/v2/guide/computed.html#Watchers. From the doc:
While computed properties are more appropriate in most cases, there
are times when a custom watcher is necessary. That’s why Vue provides
a more generic way to react to data changes through the watch option.
This is most useful when you want to perform asynchronous or expensive
operations in response to changing data.