Vue shopping cart add to cart not working - api

I cannot see what i have done wrong, i am trying to add my products to my cart but i am not having any luck. How do i add to cart? i can figure out the delete and clear from understanding how to add to cart. i have read through some documentation and managed to get this far but now i am stuck.
i am not sure if i am targeting wrong or i have named something wrong. I used a normal array and it worked alright but i am trying to do it with an api now, does this change the methods?
<section>
<div class ="container" >
<div id="app" >
<div class="row">
<div class="col-md-12" >
<div class="card">
<div class="card-body">
<!-- Cart -->
<table>
<tr>
<th>Product</th>
<th>Price</th>
<th>Quantity</th>
<th>Total</th>
</tr>
<tr v-for="(product, index) in cart">
<td>{{ item.productName }}</td>
<td>{{ item.price }}</td>
<td>{{ item.quantity }}</td>
<td>{{ item.price * item.quantity }} Coins</td>
</tr>
</table>
</div>
</div>
<!-- Shop -->
<div class="row">
<div class="col-md-3" v-for="product in products" :key="product.id" >
<div class="card" >
<div class="card-body">
<div class="product">
<img :src="product.productImage" alt="Product Img">
<h4 class="text-info">{{ product.productName }}</h4>
<h4 class="text-muted">{{ product.price }} Coins</h4>
<p class="text-muted">{{ product.productDescription }}</p>
<input type="number" name="quantity" class="form-control" value="1">
<input type="hidden" name="productName" value="{{productID}}">
<input type="hidden" name="price" value="{{productID.price}}">
<input type="submit" name="add_to_cart" #click="addToCart" class="btn btn-primary btn-block fa-lg gradient-custom-2 mb-3" value="Add to Cart">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<script>
var app = new Vue({
el: '#app',
data: {
products: '',
cart: []
},
methods: {
getproducts: function () {
axios.get('http://localhost:8888/DevsDev2022/productAPI/products')
.then(function (response) {
app.products = response.data;
})
.catch(function (error) {
console.log(error);
});
},
addToCart: function (product) {
var cartItem = this.cart.find(item => item.productName === product.productName);
if (cartItem) {
cartItem.quantity++;
} else {
this.cart.push({
productName: product.productName,
price: product.price,
quantity: 1
});
}
},
removeFromCart: function (product) {
var cartItem = this.cart.find(item => item.productName === product.productName);
if (cartItem.quantity > 1) {
cartItem.quantity--;
} else {
this.cart.splice(this.cart.indexOf(cartItem), 1);
}
},
clearCart: function () {
this.cart = [];
}
},
mounted: function () {
this.getproducts();
}
});
</script>

You are missing your template tag around your template

Please take a look at following snippet:
new Vue({
el: '#app',
data() {
return {
products: [{id: 1, productName: 'aaa', price: 25, productDescription: 'rrrrrrr'}, {id: 2, productName: 'bbb', price: 35, productDescription: 'eeeee'}],
cart: []
}
},
methods: {
getproducts() {
/*axios.get('http://localhost:8888/DevsDev2022/productAPI/products')
.then(function (response) {
app.products = response.data;
})
.catch(function (error) {
console.log(error);
});*/
},
addToCart(product) {
var cartItem = this.cart.find(item => item.productName === product.productName);
if (cartItem) {
cartItem.quantity++;
} else {
this.cart.push({
productName: product.productName,
price: product.price,
quantity: 1
});
}
},
removeFromCart(product) {
var cartItem = this.cart.find(item => item.productName === product.productName);
if (cartItem.quantity > 1) {
cartItem.quantity--;
} else {
this.cart.splice(this.cart.indexOf(cartItem), 1);
}
},
clearCart() {
this.cart = [];
}
},
mounted: function () {
this.getproducts();
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<section>
<div class ="container" >
<div class="row">
<div class="col-md-12" >
<div class="card">
<div class="card-body">
<!-- Cart -->
<table>
<tr>
<th>Product</th>
<th>Price</th>
<th>Quantity</th>
<th>Total</th>
</tr>
<tr v-for="(product, index) in cart">
<td>{{ product.productName }}</td>
<td>{{ product.price }}</td>
<td>{{ product.quantity }}</td>
<td>{{ product.price * product.quantity }} Coins</td>
</tr>
</table>
</div>
</div>
<!-- Shop -->
<div class="row">
<div class="col-md-3" v-for="product in products" :key="product.id" >
<div class="card" >
<div class="card-body">
<div class="product">
<img :src="product.productImage" alt="Product Img">
<h4 class="text-info">{{ product.productName }}</h4>
<h4 class="text-muted">{{ product.price }} Coins</h4>
<p class="text-muted">{{ product.productDescription }}</p>
<input type="number" name="quantity" class="form-control" value="1">
<input type="hidden" name="productName" :value="product.name">
<input type="hidden" name="price" :value="product.price">
<input type="submit" name="add_to_cart" #click="addToCart(product)" class="btn btn-primary btn-block fa-lg gradient-custom-2 mb-3" value="Add to Cart">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</div>

Related

ERROR 422 when update data inside modal with axios.put [laravel + vuejs 3]

I am using Laravel + VueJS 3 to build a small project,
I use axios.put method for update details for single user in a table row via a modal, but I have problems when I click on submit button of a form inside a modal with axios.put, even I filled all data for all inputs but It still said the errors below, can you guys show me how can I fix this please?
Thanks!
ERROR
My backend:
public function updateUser(Request $req, User $user)
{
$req->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email,' . $user->id,
'password' => 'same:confirmPassword|max:64',
'roles' => 'required',
]);
$input = $req->all();
if (!empty($input['password'])) {
$input['password'] = Hash::make($input['password']);
} else {
$input = Arr::except($input, 'password');
}
$user->update($input);
$user->syncRoles($input['roles']);
return $this->sendResponse($user, 'Updated!');
}
My JS Code:
import axios from "axios";
let API_URL = "http://localhost:8000";
export default {
name: "manageUsers",
components: {},
data() {
return {
users: [],
userInfo: {
id: 0,
name: "",
username: "",
phone: "",
email: "",
password: "",
},
};
},
methods: {
refreshUsers() {
axios.get(`${API_URL}/api/users/allusers`).then((res) => {
this.users = res.data.data;
});
},
getUserInfo(user) {
axios
.get(`${API_URL}/api/users/show/` + user.id)
.then((res) => {
this.userInfo.id = res.data.data.id;
this.userInfo.name = res.data.data.name;
this.userInfo.email = res.data.data.email;
this.userInfo.username = res.data.data.username;
this.userInfo.phone = res.data.data.phone;
})
.catch((error) => {
console.log("ERRRR:: ", error.response.data);
});
},
updateUser() {
axios
.put(`${API_URL}/api/users/update/${this.userInfo.id}`)
.then((res) => {
this.refreshUsers();
alert(res.data);
})
.catch((error) => {
console.log("ERRRR:: ", error.response.data);
});
},
},
mounted() {
this.refreshUsers();
},
};
My VueJS template code:
<template>
<table class="table table-striped" id="datatable">
<tbody>
<tr v-for="(user, id) in users" :key="user.id">
<td>{{ user.id }}</td>
<td>{{ user.name }}</td>
<td>{{ user.email }}</td>
<td>{{ user.username }}</td>
<td class="text-right">
<button
class="btn btn-link btn-warning btn-icon btn-sm"
data-toggle="modal" data-target="#userEditModal"
#click="getUserInfo(user)">
<i class="tim-icons icon-pencil"></i>
</button>
</td>
</tr>
</tbody>
</table>
<!-- EDIT USER MODAL -->
<div class="modal modal-black fade" id="userEditModal" tabindex="-1" role="dialog"
aria-labelledby="userEditModal" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="userEditModal">
Edit user <strong class="text-primary">{{ userInfo.username }}</strong>
</h4>
<button type="button" class="close"
data-dismiss="modal" aria-hidden="true">
<i class="tim-icons icon-simple-remove"></i>
</button>
</div>
<form class="form-horizontal">
<div class="modal-body">
<div class="d-flex flex-row">
<label class="col-md-3 col-form-label">Username</label>
<div class="col-md-9">
<div class="form-group">
<input type="text" class="form-control" name="username"
v-model="userInfo.username" />
</div>
</div>
</div>
<div class="d-flex flex-row">
<label class="col-md-3 col-form-label">Name</label>
<div class="col-md-9">
<div class="form-group">
<input type="text" class="form-control" name="name"
v-model="userInfo.name" />
</div>
</div>
</div>
<div class="d-flex flex-row">
<label class="col-md-3 col-form-label">Email</label>
<div class="col-md-9">
<div class="form-group">
<input type="email" name="email" class="form-control"
v-model="userInfo.email" />
</div>
</div>
</div>
<div class="d-flex flex-row">
<label class="col-md-3 col-form-label">Roles</label>
<div class="col-md-9">
<div class="form-group">
<input type="roles" name="roles" class="form-control"
v-model="userInfo.roles" />
</div>
</div>
</div>
</div>
<div class="modal-footer d-flex flex-row">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button type="submit" class="btn btn-primary" data-dismiss="modal"
#click="updateUser()">
Save changes
</button>
</div>
</form>
</div>
</div>
</div>
<!-- END EDIT USER MODAL -->
</template>```
I think you're not passing any parameters to your put call. axios docs
example:
axios.put('https://httpbin.org/put', { hello: 'world' });
When an issue like this arises you can always check your network tab in your browser. to see what data is send to your server.

Using same .vue component twice in same parent component - how to differentiate

I want to use the same component twice from a parent component; all that was stopping me was the use of an ID for a dropdown in the subcomponents! So I currently have duplicated the subcomponent.
My parent component:
<template>
<div id="compare-page">
<div class="row">
<div class="col-md-12">
<div class="row campaign-overview">
<div class="col-md-4">
<h2>{{ campaign.name }}</h2>
<strong>Published</strong>
<strong>Starts: {{ campaign.start_date }} - Ends: {{ campaign.end_date }}</strong>
</div>
<div class="col-md-4 text-right">
<select name="daterange" id="" #change="onChangeDaterange($event)">
<option v-for="(daterange, index) in dateranges" v-bind:key="daterange.index" :value="index" :data-start="daterange.start" :data-end="daterange.end" :selected="daterange.optionSelected == 1">{{ index }}</option>
</select>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<left-device ref="leftDevice"></left-device>
</div>
<div class="col-md-6">
<right-device ref="rightDevice"></right-device>
</div>
</div>
</div>
</template>
<script>
import left from './compared_device_component_left.vue';
import right from './compared_device_component_right.vue';
export default {
components: {
'left-device': left,
'right-device': right,
},
mounted() {
this.fetchCampaignData().then(result => {
});
},
data() {
return {
campaign_id: this.$route.params.campaign_id,
campaign: [],
dateranges: [],
leftDevice: '',
rightDevice: ''
}
},
methods: {
fetchCampaignData() {
return this.$http.get('/api/portal/campaign/' + this.campaign_id + '/campaign?' + this.axiosParams)
.then(function(data){
return data.json();
}).then(function(data){
this.campaign = data.campaign;
this.dateranges = data.dateranges;
});
},
onChangeDaterange(event) {
this.$router.push('?range=' + event.target.value);
this.$refs.leftDevice.onChangeDaterange(event);
this.$refs.rightDevice.onChangeDaterange(event);
},
},
computed: {
axiosParams() {
const params = new URLSearchParams();
if(this.$route.query.range) params.append('range', this.$route.query.range);
return params;
}
},
}
</script>
<style lang="scss">
</style>
One of my subcomponents
<template>
<div>
<div class="row device-overview">
<div class="col-md-4">
<select name="devices" id="deviceLeft" #change="onChangeDevice($event)">
<option v-for="(device, index) in devices" v-bind:key="device.index" :value="index" :data-device_id="device.device_id" :data-address="device.address" :selected="device.optionSelected == 1">{{ device.device_id }} | {{ device.address }}</option>
</select>
</div>
</div>
<div class="row totals">
<div class="col-md-4 card">
<div class="card-body">
<h5 class="card-title">Total Interactions</h5>
<p class="card-text">{{ total_interactions }}</p>
</div>
</div>
<div class="col-md-4 card">
<div class="card-body">
<h5 class="card-title">Average Interactions Per Day</h5>
<p class="card-text">{{ average_daily_interactions }}</p>
</div>
</div>
<div class="col-md-4 card">
<div class="card-body">
<h5 class="card-title">Total Average Dwell Time</h5>
<p class="card-text">{{ average_dwell_time }}s</p>
</div>
</div>
</div>
<div class="row interactions">
<div class="col-md-12">
<h5>Total Interactions Per Product</h5>
<table class="table table-condensed table-hover">
<tbody>
<tr>
<td class="">Tag</td>
<td class="">Mapped Product</td>
<td class="">Lifts</td>
</tr>
<tr v-for="interaction in table_product_interactions">
<td class="">{{ interaction.tag }}</td>
<td class="">{{ interaction.mapping }}</td>
<td>{{ interaction.tag_count }}</td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-12">
<h5>Total Interactions Per Day</h5>
<div class="chart" ref="chartdaily"></div>
</div>
</div>
<div class="row interactions">
<div class="col-md-8">
<h5>Total Interactions Per Hour</h5>
<div class="chart" ref="charthourly"></div>
</div>
</div>
</div>
</template>
<script>
import * as am4core from "#amcharts/amcharts4/core";
import * as am4charts from "#amcharts/amcharts4/charts";
import am4themes_animated from "#amcharts/amcharts4/themes/animated";
am4core.useTheme(am4themes_animated);
export default {
mounted() {
this.fetchData(null).then(result => {
this.chartTotalPerDay();
this.chartTotalPerHour();
});
},
data() {
return {
campaign_id: this.$route.params.campaign_id,
campaign: [],
dateranges: [],
device: [],
devices: [],
total_interactions: '',
average_daily_interactions: '',
average_dwell_time: '',
interaction_type: '',
chart_daily_interactions: [],
chart_hourly_interactions: [],
table_product_interactions: []
}
},
methods: {
fetchData(deviceID) {
// Use JS to get by ID!
var device = document.getElementById("deviceLeft");
// ... call to API
},
chartTotalPerDay() {
// ...
},
chartTotalPerHour() {
// ...
},
onChangeDaterange(event) {
// Use JS to get by ID!
var device = document.getElementById("deviceLeft");
// st cookie
document.cookie = "deviceLeft="+device.value;
this.fetchData(device.value).then(result => {
this.chartTotalPerDay();
this.chartTotalPerHour();
});
},
onChangeDevice(event) {
// st cookie
document.cookie = "deviceLeft="+event.target.value;
this.fetchData(event.target.value).then(result => {
this.chartTotalPerDay();
this.chartTotalPerHour();
});
}
},
created() {
},
computed: {
axiosParams() {
const params = new URLSearchParams();
if(this.$route.query.range) params.append('range', this.$route.query.range);
return params;
}
},
filters: {
},
directives: {
},
}
</script>
<style lang="scss">
.interactions {
h5 {
text-align: center;
}
}
.chart {
min-height: 550px;
}
</style>
I am currently using
var device = document.getElementById("deviceLeft");
...in my duplicated left/right subcomponents (this is 'left' and I also have 'right').
Should I use a 'ref' for my devices dropdown, so that each instance of the subcomponent is looking at the devices dropdown relative to that instance? Currently if I merge these into one the devices dropdown ID is the same for both instances and therefore I get incorrect ID in one of the instances!
Any helpful pointers would be much appreciated.
Thanks,
K...

I do not commit and the state is updated in Vuex

I have a bit frustrating problem, result that I have a select / option where I choose an item and then a modal is opened and just by clicking on Add / update to table, it just commits to the state "itemstabla", but result that when I give it to edit item in the table and the model is opened and I change, for example, quantity to another digit, the state "itemstabla" is updated without executing the commit, it should only be done when clicking on the modal button.
My store:
let store = {
state: {
token: localStorage.getItem('access_token') || null,
items: [],
itemstabla: [],
monedas: [],
impuestos: [],
venta: [],
estadotienda: '',
},
getters: {
loggedIn(state) {
return state.token !== null
},
},
mutations: {
EliminarItemTabla(state, item) {
var index = state.itemstabla.findIndex(c => c.id == item);
state.itemstabla.splice(index, 1);
},
retrieveToken(state, token) {
state.token = token
},
setmonedas(state, monedas) {
state.monedas = monedas
},
setventa(state, venta) {
state.venta = venta
},
setitemstabla(state, items) {
let found = state.itemstabla.find(item => item.id == items.id);
if(found) {
if(items.accion=='agregar') {
found.cantidad = parseInt(found.cantidad) + parseInt(items.cantidad)
}
else {
found.cantidad = parseInt(items.cantidad)
}
}
else {
state.itemstabla.push(items)
}
},
actualizaritemstabla(state) {
state.itemstabla.forEach(function (item) {
if ((state.venta.moneda_id == 'S/' && item.moneda == 'S/') || (state.venta.moneda_id == '$' && item.moneda == '$')) {
item.precio = parseFloat(item.precio).toFixed(2)
}
else if(state.venta.moneda_id == '$' && item.moneda == 'S/') {
item.moneda = '$'
item.precio = parseFloat(parseFloat(item.precio) / parseFloat(state.venta.tipocambio)).toFixed(2)
}
else if(state.venta.moneda_id == 'S/' && item.moneda == '$') {
item.moneda = 'S/'
item.precio = parseFloat(parseFloat(item.precio) * parseFloat(state.venta.tipocambio)).toFixed(2)
}
});
},
setimpuestos(state, impuestos) {
state.impuestos = impuestos
},
setmonedaid(state, moneda_id) {
state.venta.moneda_id = moneda_id
},
settipocambio(state, tipocambio) {
state.venta.tipocambio = tipocambio
},
destroyToken(state) {
state.token = null
}
},
actions: {
retrieveToken(context, credentials) {
return new Promise((resolve, reject) => {
axios.post('/api/login', {
username: credentials.username,
password: credentials.password,
})
.then(response => {
const token = response.data.access_token
localStorage.setItem('access_token', token)
context.commit('retrieveToken', token)
resolve(response)
})
.catch(error => {
reject(error)
})
})
},
destroyToken(context) {
if (context.getters.loggedIn){
return new Promise((resolve, reject) => {
axios.post('/api/logout', '', {
headers: { Authorization: "Bearer " + context.state.token }
})
.then(response => {
localStorage.removeItem('access_token')
context.commit('destroyToken')
resolve(response)
})
.catch(error => {
localStorage.removeItem('access_token')
context.commit('destroyToken')
reject(error)
})
})
}
}
}
}
export default store
My file Vue:
<template>
<div>
<!-- MODAL PARA EDITAR ITEM -->
<div class="modal fade" id="editarItem" tabindex="-1" role="dialog" aria-labelledby="editarItem" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Editar ítem</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="form-group row">
<label for="cantidadEdit" class="col-sm-4 col-form-label col-form-label-sm font-weight-bold">Cantidad</label>
<div class="col-sm-8">
<div class="input-group">
<input v-model="item.cantidad" type="number" class="form-control text-center font-weight-bold h2" min="1" tabindex="1" onfocus="this.select();">
</div>
</div>
</div>
<div class="form-group row">
<label for="itemEdit" class="col-sm-4 col-form-label col-form-label-sm">Stock</label>
<div class="col-sm-8">
<input type="text" class="form-control text-center font-weight-bold h2" v-model="item.stock" disabled>
</div>
</div>
<div class="form-group row">
<label for="precioEdit" class="col-sm-4 col-form-label col-form-label-sm">Precio unitario<small class="text-muted" id="porcentajefinalprecio">+ {{item.primer_margen}}%</small></label>
<div class="col-sm-8">
<input v-model="item.precio" type="text" class="form-control font-weight-bold" tabindex="2" onfocus="this.select();">
</div>
</div>
<div class="form-group row">
<label for="" class="col-sm-4 col-form-label col-form-label-sm">Tipo de impuesto</label>
<div class="col-sm-8">
<select v-model="item.impuesto" class="imp custom-select" id="imp">
<option v-for="imp in impuestos" v-bind:key="imp.id" v-bind:value="imp.id">{{ imp.nombre }}</option>
</select>
</div>
</div>
<div class="form-group row">
<label for="precioTotalEdit" class="col-sm-4 col-form-label col-form-label-sm">Subtotal <small id="simboloparatodos" class="text-muted">{{item.moneda_id}}</small></label>
<div class="col-sm-8">
<input type="text" v-model="subtotal" class="form-control form-control-sm" id="precioTotalEdit" onfocus="this.select();" readonly>
</div>
</div>
<div class="form-group row">
<label for="precioigvEdit" class="col-sm-4 col-form-label col-form-label-sm">I.G.V. </label>
<div class="col-sm-8">
<input type="text" v-model="igv" class="form-control form-control-sm" id="precioigvEdit" readonly>
</div>
</div>
<div class="form-group row">
<label for="descuentoEdit" class="col-sm-4 col-form-label col-form-label-sm">Descuento</label>
<div class="col-sm-8">
<input v-model="item.descuento" type="text" class="form-control form-control-sm" id="descuentoEdit" data-toggle="popover" data-placement="top" data-html="true" data-content="Para montos. Ej: 10<br>Para porcentajes agrega %. Ej: 10%" data-trigger="hover" tabindex="4" onfocus="this.select();">
</div>
</div>
<div class="form-group row">
<label for="precioSubtotalEdit" class="col-sm-4 col-form-label col-form-label-sm">Total <small id="simboloparatodos" class="text-muted">{{ moneda_id }}</small></label>
<div class="col-sm-8">
<input v-model="total" type="text" class="form-control font-weight-bold" id="precioSubtotalEdit" value="0" tabindex="5" onfocus="this.select();">
</div>
</div>
<div class="form-group row">
<label for="precio20Edit" class="col-sm-4 col-form-label col-form-label-sm">Precio <small class="text-muted" id="porcentajeinicial">+ {{item.primer_margen}}%</small></label>
<div class="col-sm-8">
<div id="margeninicialx">{{ item.masprimermargen }}</div>
</div>
</div>
<div class="form-group row">
<label for="precio35Edit" class="col-sm-4 col-form-label col-form-label-sm">Precio <small class="text-muted" id="porcentajefinal">+ {{item.segundo_margen}}%</small></label>
<div class="col-sm-8">
<div id="margenfinalx"> {{ item.massegundomargen }}</div>
</div>
</div>
<div class="form-group row">
<label for="itemEdit" class="col-sm-4 col-form-label col-form-label-sm">Item</label>
<div class="col-sm-8">
<small id="marcaEdit">{{ item.marca }}</small> {{ item.nombre }}<br><span class="text-muted small" title="códigos" id="codigoedit" v-for="cod in codigos" v-bind:key="cod.id">{{ cod.nombre_codigo }}-{{ cod.pivot.nombre }}<br></span>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">Cancelar</button>
<button type="button" class="btn btn-sm btn-primary" tabindex="5" #click="anadiritem">Añadir</button>
</div>
</div>
</div>
</div>
<!-- FIN DE MODAL PARA EDITAR ITEM -->
<!-- SECCION SELECCIONAR ITEM Y AGREGAR A LA TABLA -->
<div class="">
<div class="input-group input-group-sm mb-3">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-search"></i></span>
</div>
<div class="prefetch">
<input type="text" id="item" class="form-control typeahead" placeholder="Buscar item (Ctrl+.)" v-model.trim="q" #keyup.enter="buscaritem">
</div>
<div class="input-group-append">
<button class="btn btn-outline-secondary" id="button-addon2" disabled></button>
</div>
</div>
</div>
<table class="table table-striped table-hover table-sm table-responsive-md text-nowrap mt-3" id="detailFactura">
<thead>
<tr>
<th>Ítem</th>
<th class="text-right">Cnt.</th>
<th class="text-right">Costo U.</th>
<th></th>
<th class="text-right text-nowrap">
SubTotal
</th>
<th class="text-right text-nowrap">
I.G.V
</th>
<th class="text-right text-nowrap"><span class="text-muted">
Total
<div id="monedaText"></div>
</span></th>
</tr>
</thead>
<tbody>
<tr v-for="itemtabla in itemstabla" v-bind:key="itemtabla.id">
<td class="overflow-hidden" style="max-width: 299px; text-overflow: ellipsis">{{ item.nombre }} <small class="text-muted">({{ itemtabla.marca }})</small> </td>
<td class="text-right"><small class="text-muted mr-1" title="Unidades">{{ itemtabla.unidad }}</small>{{ itemtabla.cantidad }}</td>
<td class="text-right">{{ itemtabla.precio }}</td>
<td class="text-right">
<i class="fas fa-pencil-alt mr-2"></i>
<i class="far fa-trash-alt"></i>
</td>
<td class="text-right">{{ preciosegunmoneda(itemtabla.precio, itemtabla.moneda, itemtabla.cantidad, itemtabla.impuesto, itemtabla.descuento).subtotal }}</td>
<td class="text-right">{{ preciosegunmoneda(itemtabla.precio, itemtabla.moneda, itemtabla.cantidad, itemtabla.impuesto, itemtabla.descuento).igv }}</td>
<td class="text-right">{{ preciosegunmoneda(itemtabla.precio, itemtabla.moneda, itemtabla.cantidad, itemtabla.impuesto, itemtabla.descuento).total }}</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="2" class="text-right" id="cantidadItems">{{ itemstabla.length }} </td>
<td class="small font-weight-bolder">ítem(s)</td>
</tr>
</tfoot>
</table>
<!-- FIN DE SECCION SELECCIONAR ITEM Y AGREGAR A LA TABLA -->
</div>
</template>
<script>
import {
required,
minLength,
maxLength,
between
} from 'vuelidate/lib/validators'
import Bloodhound from 'corejs-typeahead/dist/bloodhound';
import typeahead from 'corejs-typeahead/dist/typeahead.jquery';
export default {
name: 'tabla-item',
props: {
tienda: Number,
},
data() {
return {
resource: 'venta',
error: false,
submitStatus: null,
isLoading: false,
fullPage: true,
q: '',
suggestions: null,
item: {},
}
},
created() {
},
mounted() {
let contextoVue = this
// Cargar los datos del typeahead en items
this.suggestions = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('title'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
identify: function (item) {
return item.id;
},
remote: {
url: '/item/records/' + this.tienda + '/' + '%QUERY',
wildcard: '%QUERY'
}
});
let inputEl = $('.prefetch input');
inputEl.typeahead({
minLength: 1,
highlight: true,
}, {
name: 'suggestions',
source: this.suggestions,
limit: 20,
display: 'label',
templates: {
suggestion: (data) => {
let codigos = data.codigos
let nuevoscodigos = ""
codigos.forEach(function (valor, indice, array) {
nuevoscodigos = nuevoscodigos + valor.pivot.nombre + ','
});
let nuevoprecio = ((parseFloat(contextoVue.preciosegunmoneda(data.precio, data.moneda,'1',data.impuesto_id).precio) * parseFloat(data.primer_margen) / 100) + parseFloat(contextoVue.preciosegunmoneda(data.precio, data.moneda,'1',data.impuesto_id).precio)).toFixed(2)
return `<div class="ss-suggestion">
<div class="codigos">
${data.nombre_marca} <span title="Código global"> - ${nuevoscodigos}</span>
<span title="Código de barras"></span>
</div>
<div class="searchproducto" style="text-transform: capitalize;">
<strong>${data.nombre}</strong>
</div>
<div class="d-flex mt-1"><div class="searchprice text-primary">${contextoVue.moneda_id}
<span id="pricechange">${nuevoprecio}</span></div>
<div class="searchstock flex-grow-1 text-danger"><b>Stock</b>:
<b style="color: red;">${data.stock}</b><b></b></div></div></div>`;
}
}
});
// Cuando se hace click en un item
$('.prefetch input').bind('typeahead:selected', function (evt, suggestion) {
$('#editarItem').modal('show')
let preciosegunmoneda = ((parseFloat(contextoVue.preciosegunmoneda(suggestion.precio, suggestion.moneda, '1', suggestion.impuesto_id).precio) * parseFloat(suggestion.primer_margen) / 100) + parseFloat(contextoVue.preciosegunmoneda(suggestion.precio, suggestion.moneda, '1', suggestion.impuesto_id).precio)).toFixed(2)
let massegundomargen = ((parseFloat(contextoVue.preciosegunmoneda(suggestion.precio, suggestion.moneda, '1', suggestion.impuesto_id).precio) * parseFloat(suggestion.segundo_margen) / 100) + parseFloat(contextoVue.preciosegunmoneda(suggestion.precio, suggestion.moneda, '1', suggestion.impuesto_id).precio)).toFixed(2)
contextoVue.item = {
id: suggestion.id,
stock: suggestion.stock,
nombre: suggestion.nombre,
precio: preciosegunmoneda,
marca: suggestion.nombre_marca,
impuesto: suggestion.impuesto_id,
primer_margen: suggestion.primer_margen,
segundo_margen: suggestion.segundo_margen,
masprimermargen: preciosegunmoneda,
massegundomargen: massegundomargen,
codigos: suggestion.codigos,
cantidad: '1',
descuento: '0',
moneda: contextoVue.moneda_id,
unidad: suggestion.nombre_unidad,
}
});
// Fin typeahead items
},
updated() {
},
computed: {
total() {
return this.item.precio * this.item.cantidad - this.item.descuento
},
igv() {
if(this.item.impuesto=="1") {
return (parseFloat(this.total) * 18/100).toFixed(2)
}
else {
return 0
}
},
subtotal() {
return (parseFloat(this.total) - this.igv).toFixed(2)
},
tipocambio: {
get() {
return this.$store.state.venta.tipocambio
},
set(value) {
this.$store.commit('settipocambio', value)
}
},
moneda_id: {
get() {
return this.$store.state.venta.moneda_id
},
set(value) {
this.$store.commit('setmonedaid', value)
}
},
itemstabla: {
get() {
return this.$store.state.itemstabla
},
},
impuestos: {
get() {
return this.$store.state.impuestos
},
},
},
watch: {
moneda_id: function (val) {
//this.$store.commit('actualizaritemstabla')
},
},
methods: {
submit() {},
preciosegunmoneda(precio, moneda, cantidad, impuesto, descuento) {
let total,nuevoprecio,subtotal,igv = 0
if ((this.moneda_id == 'S/' && moneda == 'S/') || (this.moneda_id == '$' && moneda == '$')) {
nuevoprecio = parseFloat(precio).toFixed(2)
total = parseFloat((parseFloat(precio) * cantidad) - descuento).toFixed(2)
igv = parseFloat((parseFloat(total) * (impuesto=='1' ? 18/100 : 0))).toFixed(2)
subtotal = parseFloat(total - igv).toFixed(2)
return {precio: nuevoprecio, total: total, igv: igv, subtotal: subtotal }
}
else if (this.moneda_id == 'S/' && moneda == '$') {
nuevoprecio = parseFloat(precio * this.tipocambio).toFixed(2)
total = parseFloat((parseFloat(precio * this.tipocambio) * cantidad) - descuento).toFixed(2)
igv = parseFloat((parseFloat(total) * (impuesto=='1' ? 18/100 : 0))).toFixed(2)
subtotal = parseFloat(total - igv).toFixed(2)
return {precio: nuevoprecio, total: total, igv: igv, subtotal: subtotal }
}
else if (this.moneda_id == '$' && moneda == 'S/') {
nuevoprecio = parseFloat(precio / this.tipocambio).toFixed(2)
total = parseFloat((parseFloat(precio / this.tipocambio) * cantidad) - descuento).toFixed(2)
igv = parseFloat((parseFloat(total) * (impuesto=='1' ? 18/100 : 0))).toFixed(2)
subtotal = parseFloat(total - igv).toFixed(2)
return {precio: nuevoprecio, total: total, igv: igv, subtotal: subtotal }
}
},
deleteitem(i) {
this.$store.commit('EliminarItemTabla', i);
},
editaritem(item) {
$('#editarItem').modal('show')
this.item = item
},
anadiritem(event) {
$('#editarItem').modal('hide')
this.$store.commit('setitemstabla', this.item )
},
},
validations: {
form: {
nombre_codigo: {
required,
},
}
}
}
</script>
With the use of editaritem like you do, I think you're actually passing the item itself, so it gets modified as it's a reference.
editaritem(item) {
$('#editarItem').modal('show')
this.item = { ...item } // or some way to copy the object
}
And after you finish edit, perform the actual update of the edited object.

v-model is not working on dynamic radio buttons, vue js

var vue = new Vue({
el: '#app',
data: function (){
return {
categories: null,
foodItems: null,
selectedCategoryId: null
}
},
mounted: function() {
axios
.get('#Url.Action("GetCategories", "Home", new { area="Canteen" })')
.then(response => (this.categories = response.data))
}
});
<span>selected: {{ selectedCategoryId }}</span>
<div class="box box-default">
<div class="box-header with-border">
<div class="text-center text-uppercase"><b>Select</b></div>
</div>
<div class="box-body">
<div class="btn-group-vertical btn-block btn-group-toggle" data-toggle="buttons">
<label v-for="(category, index) in categories" class="btn btn-default active">
<input :id="'option-' + category.id" :value="category.id" type="radio" name="categories" autocomplete="off" v-model="selectedCategoryId" />{{ category.name }}
</label>
</div>
</div>
</div>
Here is working example
var vue = new Vue({
el: '#app',
data: function (){
return {
categories: null,
foodItems: null,
selectedCategoryId: null,
isdata:false
}
},
mounted: function() {
console.log("mounted");
var vm = this;
setTimeout(function(){
vm.categories = [
{id:1,name:'test1'},
{id:2,name:'test2'},
{id:3,name:'test3'}
];
vm.isdata = true;
}, 2000);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<span>selected: {{ selectedCategoryId }}</span>
<div class="box box-default">
<div class="box-header with-border">
<div v-show="!isdata">Loading....</div>
<div v-show="isdata" class="text-center text-uppercase"><b>Select</b></div>
</div>
<div class="box-body">
<div class="btn-group-vertical btn-block btn-group-toggle" data-toggle="buttons">
<label v-for="(category, index) in categories" class="btn btn-default active">
<input :id="'option-' + category.id" :value="category.id" type="radio" name="categories" autocomplete="off" v-model="selectedCategoryId" />{{ category.name }}
</label>
</div>
</div>
</div>
</div>

VueJs select binding is not working

I have a categories component that looks like this:
<template>
<div>
<select v-model="categories">
<option v-for="category in categories" v-bind:value="category\.id">
{{category.name}}
</option>
</select>
</div>
</template>
<script>
export default {
data(){
return{
categories: []
}
},
created(){
this.showCategories();
},
methods: {
showCategories(){
axios.get('/app/categories').then(response => {
this.categories = response.data.categories;
});
}
}
}
</script>
I import this component inside my posts componen because I want to be able to choose a category when adding a new post, however, the categories for some reason do not show.
If it helps, my posts component looks like this:
<template>
<div class="container">
<button type="button" class="btn btn-info btn-lg" data-toggle="modal" data-target="#myModal">Add Post</button>
<div class="form-group">
<input type="text" v-model="search" class="form-control" id="search">
</div>
<categories></categories>
<table class="table">
<thead class="thead-dark">
<tr>
<th>ID</th>
<th>Title</th>
<th>Body</th>
<th>Owner</th>
<th>Category</th>
<th>Created At</th>
<th>Updated At</th>
</tr>
</thead>
<tbody>
<tr v-for="post in filteredPosts">
<td>{{ post.id }}</td>
<td>{{ post.title }}</td>
<td>{{ post.body | snippet }}</td>
<td>{{ post.user.name }}</td>
<td>{{ post.category.name }}</td>
<td>{{ post.created_at }}</td>
<td>{{ post.updated_at }}</td>
<td><button class="btn btn-primary">Edit</button></td>
<td><button class="btn btn-danger">Delete</button></td>
</tr>
</tbody>
</table>
<div class="modal fade" id="myModal" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Modal Header</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label>Title</label>
<input type="text" v-model="post.title" class="form-control">
</div>
<div class="form-group">
<label>Body</label>
<textarea v-model="post.body" class="form-control"></textarea>
</div>
</div>
<div class="modal-footer">
<button #click.prevent="addPost" type="button" class="btn btn-primary" data-dismiss="modal">Submit</button>
<button type="button" class="btn btn-danger" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data(){
return{
posts: [],
post: {
title: "",
body: ""
},
search: ""
//categories: []
}
},
created(){
this.showPosts();
//this.showCategories();
},
methods: {
/*showCategories(){
axios.get('/app/categories').then(response => {
this.categories = response.data.categories;
});
},*/
showPosts(){
axios.get('/app/posts').then(response => {
this.posts = response.data.posts;
});
},
addPost(){
axios.post('/app/posts', {
title: this.post.title,
body: this.post.body,
})
.then(response => {
this.showPosts();
//console.log('Added');
})
.catch(function (error) {
console.log(error);
});
}
},
computed: {
filteredPosts: function(){
return this.posts.filter((post) => {
return post.title.match(this.search);
});
}
}
}
</script>
OBS: If I use an li tag like this inside the categories component I manage to see all the categories:
<li v-for="category in categories">{{category.name}}</li>
How can I show my categories inside the posts component using the select binding?
In your Select element you are binding v-model to array categories instead bind another variable selectedCategory in v-model like this
<select v-model="selectedCategory">
<option v-for="category in categories" v-bind:value="category.id">
{{category.name}}
</option>
</select>
<script>
export default {
data(){
return{
selectedCategory:null,
categories: []
}
},
created(){
this.showCategories();
},
methods: {
showCategories(){
axios.get('/app/categories').then(response => {
this.categories = response.data.categories;
});
}
}
}
</script>