Vue - dynamically registered models? - javascript

Inside a Vue-component, I'm making a list, but the number of entries in the list varies.
So it could be like this:
<form>
<input type="number" value="15" />
<input type="number" value="10" />
<input type="number" value="5" />
<input name="total" :value="summedTotal" /> <!-- (calculated dynamically) -->
</form>
Or like this:
<form>
<input type="number" value="15" />
<input type="number" value="10" />
<input type="number" value="5" />
<input type="number" value="17" />
<input type="number" value="20" />
<input name="total" :value="summedTotal" /> <!-- (calculated dynamically) -->
</form>
If I had a fixed set of input fields, then I would have solved it using v-model. But now the number of 'models' are dynamic.
Can I somehow still use v-model to solve this?
Currently I'm adding an #keypress-event, finding the input ( document.getElementById( '....' ) and finding the value from that. But I need to set a delay for it to work. I could use keyup or some other event-watcher, but it all becomes really hacky, really quick.
The actual code is (an advanced version of) this:
<form>
<input
type="number"
v-for="(entry, index) in list"
name="entry.id"
value="entry.initial_value"
:id="'entry-id__' + entry.id" #keypress="calculateSum()"
/>
<input name="total" :value="summedTotal" /> <!-- (calculated dynamically) -->
</form>

You should be able to use a v-model that will allow your input fields to change the value in the list :
<input
type="number"
v-for="(entry, index) in list"
:key="'input-field-'+entry.id"
name="entry.id"
v-model="entry.initial_value"
:id="'entry-id__' + entry.id"
/>
When a new value is set by the user, it should modify this precise value in your list object.
Then keep your last line as is:
<input name="total" :value="summedTotal" />
with summedTotal being a computed value summing the values of your list.
If you don't want to change your original list, you can make a deep copy first and then use copiedList for your v-model:
data {
copiedList : JSON.parse(JSON.stringify(this.list))
}
Here is a Snippet that works:
new Vue({
el: '#app',
data: {
list: [{
id: 1,
initial_value: 3
},
{
id: 2,
initial_value: 1
},
{
id: 3,
initial_value: 7
},
{
id: 4,
initial_value: 2
},
]
},
computed: {
summedValued() {
return this.list.reduce((acc, c) => {
return acc + parseInt(c.initial_value || 0);
}, 0)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="(entry, index) in list" :key="'input-field-'+entry.id">
ID {{entry.id}}: <input type="number" name="entry.id" v-model="entry.initial_value" :id="'entry-id__' + entry.id" />
</div>
TOTAL :{{summedValued}}
</div>

Related

Vue jS: input auto filled

In my Vue JS code below i have input total price and two inputs paid and percentage, i wanted to do an algorithm that what ever user wrote inside paid input an auto percentage should be filled in percentage input and ofc this percentage is from total price input, also when user write in percentage input the paid should be auto filled and so on.
Is there a way to do this in Vue js?
P.S: I wrote v-model=instpaid and v-model=instprice that posts data to API
<input type="number" v-model="instPrice" class="price-input mt-3" placeholder=" total price" required />
<br />
<input type="number" v-model="instPaid" class="price-input mt-3" placeholder=" paid " required />
<input type="number" class="price-input mt-3" placeholder=" percenatge" required />
Maybe something like following snippet:
new Vue({
el: "#demo",
data() {
return {
instPrice: 0,
instPaid: 0,
pct: 0
}
},
methods: {
calc(pct) {
pct === true ?
this.instPaid = (this.instPrice / 100 * this.pct).toFixed(2)
:
this.pct = (this.instPaid / this.instPrice * 100).toFixed(2)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<input type="number" v-model="instPrice" placeholder=" total price" required />
<br />
<input type="number" v-model="instPaid" placeholder=" paid" #keyup="calc(false)" required />
<input type="number" placeholder=" percenatge" #keyup="calc(true)" v-model="pct" required />
</div>

Vue.js - Dynamically generate v-model name

this is my first use of Vue.js so please bear with me. I have a section in my app where users can dynamically add (up to 5) entries and also remove entries. Each entry consists of four input tags that correspond to product id, description, quantity, and unit price. There is also an "X" icon at the end so that users can choose whether or not to remove that entry row before saving it. So visually, it would look something like this:
1 Tomatoes 40 $2.50 X
2 Pears 50 $1.39 X
3 Celery 12 $1.60 X
I am unsure how to dynamically generate v-model names that correspond to each piece of data that I want to save. In other words, I need four input tags and the X icon for each entry that a user wants to enter. Therefore, I'd want the Vue.js state to look something like:
data: {
numEntries: 2,
entries: [
{
productId: "",
description: "",
qty: "",
price: "",
},
{
productId: "",
description: "",
qty: "",
price: "",
},
// There will be 'n' of these objects depending on how many entries there are.
]
}
And I would like the v-model to be something like "productId1" to refer to entries[0].productId and "productId2" to refer to entries[1].productId, etc. My code is shown below:
HTML
<div id="app">
...
<div v-for="n in numEntries" class="inventory-section">
<input type="text" class="id-input" placeholder="Product Id" v-model="productId" />
<input type="text" class="description-input" placeholder="Description" v-model="description" />
<input type="text" class="qty-input" placeholder="Qty" v-model="qty" />
<input type="text" class="price-input" placeholder="Price" v-model="price" />
<span class="x-sign" v-on:click="removeEntry">X</span>
</div>
...
</div>
Vue JS
var app = new Vue({
el: '#app',
data: {
numEntries: 1,
entries: [
{
productId: "",
description: "",
qty: "",
price: "",
}
]
},
methods: {
addEntry: function () {
if (this.numEntries < 12)
this.numEntries += 1;
},
removeEntry: function () {
if (this.numEntries > 1)
this.numEntries -= 1;
}
}
})
In addition, when clicking the X on a row, how do I determine which row to remove? Currently my removeEntry function is very bare bones.
Any help would be greatly appreciated.
Vue loop code:
<div v-for="(itm,ind) in entries" class="inventory-section">
<input type="text" class="id-input" placeholder="Product Id" v-model="itm.productId" />
<input type="text" class="description-input" placeholder="Description" v-model="itm.description" />
<input type="text" class="qty-input" placeholder="Qty" v-model="itm.qty" />
<input type="text" class="price-input" placeholder="Price" v-model="itm.price" />
<span class="x-sign" #click="removeEntry(ind)">X</span>
</div>
And remove item from array
removeEntry: function (i) {
this.entries.splice(i,1)
}
Instead of using v-for="n in numEntries" use it as v-for="entry in entries".
in this way, "entry" will be your scoped object in that div. and you can use v-model="entry.productId"
you can loop through entries using v-for="(entry, index) in entries" and you can use v-model="entry.productId" and so on
<div id="app">
...
<div v-for="(entry, index) in entries" class="inventory-section">
<input type="text" class="id-input" placeholder="Product Id" v-model="entry.productId" />
<input type="text" class="description-input" placeholder="Description" v-model="entry.description" />
<input type="text" class="qty-input" placeholder="Qty" v-model="entry.qty" />
<input type="text" class="price-input" placeholder="Price" v-model="entry.price" />
<span class="x-sign" v-on:click="removeEntry(index)>X</span>
</div>
...
</div>

How to get html input in JavaScript?

I am using the code below in a html form:
<input type="text" name="cars[]" required>'
Note the use of "cars[]" for the name.
This allows me to have multiple inputs with the same name.
I would like to get the answers from all the inputs in JavaScript.
How can this be done?
I have the following WRONG code for this:
var element = document.getInput("cars[]");
for (i = 0; i < element.length; i++) {
alert(element[i].value);
}
You have to use document.getElementsByName() like this:
var element = document.getElementsByName("cars[]");
for(i=0; i<element.length;i++){
alert(element[i].value);
}
<input type="text" name="cars[]" value="a" required>
<input type="text" name="cars[]" value="b" required>
<input type="text" name="cars[]" value="c" required>
These two things in pure JavaScript net approximately the same result. The first is using the HTML form element to find all of the input elements attached to it. However, the syntax for finding the array called "cars[]" is troublesome and in my opinion a tad annoying. If I was going to do something in pure JavaScript I'd probably prefer the second way, using document.querySelectorAll.
window.addEventListener('load', function() {
var form = document.getElementById('thing');
form.elements['cars[]'].forEach(function(el, i) {
console.log("value is ", el.value)
}); //Form.elements[] array has been available since Chrome 7 or so. It should be available for use in just about any browser available.
var items = document.querySelectorAll('[name="cars[]"]');
items.forEach(function(el, i) {
console.log("Item Value is ", el.value)
});
});
<form id="thing">
<input type="text" name="cars[]" value="1" />
<br />
<input type="text" name="cars[]" value="2" />
<br />
<input type="text" name="cars[]" value="3" />
<br />
<input type="text" name="cars[]" value="4" />
<br />
<input type="submit" value="submit" />
</form>
You write
Note the use of "cars[]" for the name.
This allows me to have multiple inputs with the same name.
In HTML, you can have many inputs in the same form with the same name, regardless of that name having a [] suffix or not. This has always been used for, say, checkboxes. Most server-side libraries will then return the values for those inputs as an array.
An example of gathering all values for inputs with a given name could be the following:
document.querySelector("#b").addEventListener("click", () => {
const values = [];
document.querySelectorAll("input[name='color']").forEach(e => values.push(e.value));
console.log(values); // outputs ["foo", "bar", "baz"] if values unchanged
});
input { display: block; margin: 5px; }
<label>Enter your favorite colors
<input type="text" name="color" value="foo"/>
<input type="text" name="color" value="bar"/>
<input type="text" name="color" value="baz"/>
</label>
<label>
Enter your favorite food
<input type="text" name="food" value="flub"/>
</label>
<button id="b">Click me to output favorite colors</button>
You can give same id to all inputs like
<input type="text" id="inputId" name="cars[]" required>'
In Javascript iterate the element to get the value
var element = document.getElementsByName("cars[]");
for(i=0; i<element.length;i++){
console.log(element[i].value);
}

EasyAutocomplete jquery plugin for live search ,dropdown suggestion box overlapps input fields around it

The problem comes when I search in location, then its dropdown suggestions overlaps below input fields.
home.php
<form>
<label for="contact-name">Contact Name:</label>
<input type="text"/>
<label for="contact-no">Contact No:</label>
<input type="number"/>
<label for="place">Location:</label>
<!--problem area from here-->.
<input type="text" id="locate"name="location" />
<script src="live_search.js"></script>
<label for="size">Size:</label>
<input type="text" />
<label for="price">Price:</label>
<input type="number" />
<label for="rent">Rent/Monthly:</label>
<input type="number"/>
<button type="submit" name="submit-data">Submit</button>
</form>
This script triggers the autocomplete function for searchbox and displays the suggestions from jason file and when it does, it makes a dropdown below input box of location where the problem occurs.
live_search.js
var options = {
url: "location.json",//goto location.json
getValue: "location",//get the value of the object with name=location
list: {
match: {
enabled: true
}
}
};
$("#locate").easyAutocomplete(options);
location.json
[
{"location":"wapda town"},
{"location":"gulberg"},
{"location":"valencia"},
{"location":"gulshan e iqbal"},
{"location":"iqbal avenue"},
{"location":"architect society"},
{"location":"garden town"},
{"location":"defence"},
{"location":"Faisal Garden"},
{"location":"Faisal Town"},
{"location":"Faisalabad"}
]

Change $(this) input field color based on class effecting all classes in div

I have this HTML that occurs multiple times on a page:
<div class="canteen-item">
<div class="col-l">
<h4>Chicken Sandwich</h4>
<p>$<span class="canteen-price">3.50</span></p>
</div>
<div class="col-r">
<div class="qty-days">
<input name="Mon" class="qty-input" value="0" maxlength="2" />
<input name="Tue" class="qty-input" value="0" maxlength="2" />
<input name="Wed" class="qty-input" value="0" maxlength="2" />
<input name="Thu" class="qty-input" value="0" maxlength="2" />
<input name="Fri" class="qty-input" value="0" maxlength="2" />
</div>
</div>
</div>
I have this JQuery to detect when the input field is changed and if the value is greater than 0, change the color to red.
$(".qty-input").change(function(){
var qty = parseInt($(this).val());
if(qty > 0){
$(this).css('color','red');
}
else{
$(this).css('color','black');
}
});
It is behaving very unpredictably. When I change the value of the first input field (Monday), it makes all 5 inputs red. Then sometimes it is changing the colors back to black in completely different rows sets of days. Seems like a simple problem to fix, but having trouble figuring it out.
The problem is that this code:
var qty = $(this).val();
Returns a string. And this code compares that string to a Number
if(qty > 0){
Try changing the first line of code to:
if ($(this).val()) {
var qty = parseInt($(this).val(), 10);
}
And it should start to work more consistently but you will also want to validate that the input is all numbers.
Thanks for all the responses. It prompted me to dig deeper at which point I discovered another piece of code in a different JS file that was trying (incorrectly!) to do the same thing. The code I have above is in fact sound and works perfectly. I apologize for wasting anyone's time here. I didn't realize that my client had a developer who had already attempted to do this (and who also put the code in the wrong file).
Use change event target to get to the element
$(document).ready(function() {
$(".qty-input").change(function(e) {
var target = e.target;
var qty = $(target).val();
if (qty > 0) {
$(target).css('color', 'red');
} else {
$(target).css('color', 'black');
}
alert("value is " + qty)
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="canteen-item">
<div class="col-l">
<h4>Chicken Sandwich</h4>
<p>$<span class="canteen-price">3.50</span>
</p>
</div>
<div class="col-r">
<div class="qty-days">
<input type="text" name="Mon" class="qty-input" value="0" maxlength="2" />
<input type="text" name="Tue" class="qty-input" value="0" maxlength="2" />
<input type="text" name="Wed" class="qty-input" value="0" maxlength="2" />
<input type="text" name="Thu" class="qty-input" value="0" maxlength="2" />
<input type="text" name="Fri" class="qty-input" value="0" maxlength="2" />
</div>
</div>
</div>

Categories

Resources