I'm stuck and could use a nudge in the right direction!
Overview:
I pass a Laravel collection to my Vue.js component ( :collections_prop="{{ $collection }}" ). I'm using a <tr v-for to iterate over the collection in the component. Inside each <tr> is a form with a <select> element.
What I'm trying to accomplish:
When I change an individual <select>, the form should submit and include that particular items order_id to the backend.
What's going wrong:
My table is displayed as expected, and I can see the individual order_id's associated with each <tr>. The form submits, but only for the first item.
Example:
The first collection has an order_id of 10 and a qty of 5. If I select a new qty, the form submits with that order_id and the updated qty. Perfect!
However, if I change any other <select> tag, the order_id and qty of the first row is the only information submitted.
<template>
<div class="container-fluid">
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<table class="table table-sm">
<thead>
<th scope="col">Product</th>
<th scope="col">Quantity</th>
<th scope="col">$</th>
<th scope="col"><i class="fas fa-trash-alt"></i></th>
</thead>
<div v-if="collections.length">
<tr v-for="collection in collections" :key="collection.order_id">
<td>{{ collection.description }}</td>
<td>
<form #submit="updateQty">
<input type="hidden" name="type" :value="'qty'" id="type" />
<select class="form-control" id="qty" #change="updateQty" >
<option :value="collection.qty" >{{ collection.qty }}</option>
<option v-for="(x, index) in 200" :value="x-1" :key="index" >{{ index }}</option>
</select>
</form>
</td>
<td>{{ collection.value }}</td>
<td>{{ collection.order_id }}</td>
</tr>
</div>
</table>
</div>
</div>
</div>
</template>
<script>
export default {
props: ['collections_prop'],
data() {
return {
collections: this.collections_prop,
qty: '',
type: '',
value: '',
order_id: '',
};
},
mounted() {
console.log('DisplayTable.vue mounted successfully');
var type = document.querySelector('#type').value;
},
methods: {
updateQty(e) {
e.preventDefault();
let url = '/update';
/** Uncomment to see variables being posted */
console.log('Order id: ' + order_id.value + ', QTY: ' + qty.value);
axios.post(url, {
qty: qty.value,
type: type.value,
order_id: order_id.value,
})
.then(response => {
this.collections = response.data;
console.log('Form submitted');
})
},
}
}
</script>
What I've tried:
Too many things to post, but highlights are that I've tried switching this
<tr v-for="collection in collections" :key="collections.order_id">
for this
<tr v-for="(collection, index) in collections" :key="index"> , but no luck.
I've tried to add a v-model to the <select> tag as well, and I think this is where I'm going wrong but I can't solve it.
I've tried:
<select id="qty" #change="updateQty" v-model="collection.order_id">, which causes the {{ collection.qty }} to not be displayed inside the <option> tag.
I've read about handling forms and form input bindings, which I'm SURE contains the answer, but I can't wrap my head around it.
Any assistance or even a link to an example would really help me out. Thank you very much in advance!
There are a few issues you'll want to take care of here. First of all, it doesn't seem like the form is really necessary, so I left it out of my example. If you do need it for whatever reason, it won't hurt to add back in.
Your change event on your select isn't passing back any data to the updateQty method, so it doesn't know how to get any of the data you're supposed to send to the API. If you change your select to look like this, the correct order for that row will get passed back to the method:
<select #change="() => change(event, item)" v-model="item.qty">
<option v-for="(x, index) in 200" :value="x" :key="index" >{{x}}</option>
</select>
Also, notice that I removed the first option in your select. That would have caused you to have duplicates - if qty was set to 4 for one of your orders, 4 would show up first in the dropdown and after e (would look like 4,1,2,3,4,etc). By setting v-model to collection.qty (not collection.order_id), the select will always contain the value of collection.qty for that row - if qty is 5, the select will automatically choose 5.
Now, we can set up for change handler to look like this:
updateQty(event, order) {
alert(`New quantity: ${order.qty}`)
var postObject = {
qty: order.qty,
type: 'Wherever this comes from',
order_id: order.order_id,
}
let url = '/update';
console.log(event)
/** Uncomment to see variables being posted */
console.log('Order id: ' + postObject.order_id + ', QTY: ' + postObject.qty);
// Do your post
axios.post(url, postObject)
}
The order parameter will always be the collection item from the row that was changed. Now, every time any of the selects change, your updateQty method can tell exactly which order it was for. collection.qty is also automatically updated, since v-model is 2-way bound.
Here's a JSFiddle showing all of this code working: http://jsfiddle.net/q4cLoz02/3/
Look at this part of your code:
<select class="form-control" id="qty" #change="updateQty" >
<option :value="collection.qty" >{{ collection.qty }}</option>
<option v-for="(x, index) in 200" :value="x-1" :key="index" >{{ index }}</option>
</select>
You iterate this HTML to all of the items in the collection, right? Ok, the user changes the selected value of the select element and it triggers the #chagne event. Now the question is HOW IT SHOULD UNDERSTAND WHAT COLLECTION QTY SHOULD CHANGE?.
Try this:
<select class="form-control" id="qty" #change="() => updateQty(event, collection.id)" >
<option :value="collection.qty" >{{ collection.qty }}</option>
<option v-for="(x, index) in 200" :value="x-1" :key="index" >{{ index }}</option>
</select>
And the updateQty method:
updateQty(e, order_id) {
var newQty = e.target.value;
alert(`${order_id} quantity has changed to ${newQty}`)
// call rest ...
//
}
I created a JSFiddle example here.
This is for building a table that holds data for products: I want the quantity part of the table out and use it as a variable in another form and use it in another function.
{{#viewTableData}}
<tr class="view-product-row">
<td class="product-name" data-product-id="{{ id }}">{{ name }}</td>
<td class="product-maker-number" data-product-id="{{ id }}">{{ makerNumber }}</td>
<td class="product-jan-code" data-product-id="{{ id }}">{{ janCode }}</td>
<td class="product-current-quantity">{{ quantity }}</td>
<td style="text-align: center">
<button type="button" class="btn btn-info edit-current-quantity-button" data-toggle="modal" data-target="#edit-current-quantity-modal"><span class="glyphicon glyphicon-pencil"></span></button>
<button type="button" class="btn btn-success new-movement-button" data-toggle="modal" data-target="#movement-modal"><span class="glyphicon glyphicon-plus"></span></button>
</td>
</tr>
{{/viewTableData}}
{{^viewTableData}}
<tr>
<td colspan="5">
{{#i18n}}inventory.view.no-data{{/i18n}}
</td>
</tr>
{{/viewTableData}}
<script>
$(document).ready(function() {
$('.edit-current-quantity-button').on('click', function() {populateEditCurrentQuantityModal(this)});
$('.new-movement-button').on('click', function() {populateNewMovementModalFromView(this)});
});
</script>
I want to know how to get quantity from that function into this function that is in another html file
function getCurrentQuantity()
{
//find the item and the store and get the quantity
//get data from the database
//Use store id and jan code for the query
//That way both get updated when either is changed
//product-jan-code and store-from
var q = $(".store-from-current-quantity").val(); // this does not work this is the input where the quantity from the other class should go
//update the UI if it is not done auto
fromStoreCurrentQuantity.value = q;
return q;
}
You can save the value in Cookie or localStorage in order to access it from other HTML page.
Check this link: Sharing a variable between multiple html pages
I am returning a list from Controller class.
httpReq.setAttribute("playersList", playersList);
I want size of this list in onchange() method.
$('#teams').on('change', function(){
// code to get the size/count
if(count < 11){
.........
}else{
.........
}
}
here I am displaying that list:
<tr id = "players" style="display:none;">
<td class="tabHead">PLAYER NAMES</td>
<td>
<div class="" id="playerNames" name="playerNames" >
<c:forEach items="${playersList}" var="playersListItem">
${playersListItem.name}<br>
</c:forEach>
</div>
</td>
</tr>
I tried -
var count = playersList.length;
var count = $("#players").length;
but that didn't work.
It seems that each item in your list is some unformatted text followed by a <br> element:
${playersListItem.name}<br>
...all within a particular <div> within a particular <tr>. So to count them just count the <br> elements that are inside the <tr> or <div> using one of the following:
var count = $("#players").find("br").length;
var count = $("#players br").length;
var count = $("#playerNames").find("br").length;
var count = $("#playerNames br").length;
(Note that the second thing you tried, $("#players").length, should always return either 0 or 1, because selecting by element id should always find either 0 or 1 element.)
How about using a tribute selector
$("[id='players'] br").length;
or
$('#playerNames > *').length;
if you change your table structure a little, you can easily find the count. Like here I add class 'playerName' and count it inside the players TR tag
<tr id="players" style="display:none;">
<td class="tabHead">PLAYER NAMES</td>
<td>
<div id="playerNames" name="playerNames" >
<c:forEach items="${playersList}" var="playersListItem">
<div class="playerName">${playersListItem.name}</div>
</c:forEach>
</div>
</td>
</tr>
$('#players .playerName').length
I have an html table and i want to edit the contents of the table based on a button click.
My HTML code:
<form name="myform">
<table id="tblFollow" >
{% for key, value in result.iteritems() %}
<tr>
<td > {{ key }}</td>
<td> <div id="editableText" > {{ value }} </div></td>
</tr>
{% endfor %}
</tbody>
</table>
<h> {{ passvalue }} </h> <br>
<input type="button" onclick="changeContent()" value="Change content">
</form>
and my javascript is
function changeContent(){
var newstate = !editableText.isContentEditable
editableText.contentEditable = newstate
editableText.className = (newstate)
}
but the problem is when i click on the button only the first rown on the table is showing editable. otherthan that all the rows are immutable. Any help will be appreciated
You should use the class instead of id. Id's are meant to be unique.
<div class="editableText" > {{ value }} </div>
Then in your javascript, you need to loop over the selected elements:
function changeContent(){
var editables = document.getElementsByClassName('editableText');
for (var i = 0; i < editables.length; i++) {
var newstate = !editables[i].isContentEditable;
editables[i].contentEditable = newstate;
}
}
HTML:
{% for item in result %}
<tr id="row">
<td><input name="item" type="checkbox" value="{{ item.number }}"></td>
<td contenteditable id="col1">{{ item.foo }}</td>
<td contenteditable id="col4">{{ item.bar }}</td>
</tr>
{% endfor %}
I am using facebox . Where I want to show the single row in the facebox which ever i checked ( checked the checkbox, which is in first <td> ). Jquery is:
$(document).ready(function() {
$('#edit').click(function() {
jQuery.facebox({ div: '#row' })
return false;
});
});
This jquery is giving me the first row only.
You cannot use the same "id" value for more than one element in a page.
You can change that from "id" to "class" and it (might) work. It's hard to tell what exactly you're doing.
<tr class='row'>
<!-- ... -->
</tr>
then
// ...
jQuery.facebox({div: '.row'});
Of course you could just find the <tr> elements directly:
jQuery.facebox({div: 'tr'});