How to calculate result from dynamic fields - vuejs2

I am trying to calculate a difference between dynamic fields and then add all of the differences. I am using date fields as I need to record the difference between each group of dates and then result would be total number of years. I am providing an example as below
<div id="app">
<form action="">
<div class="group" v-for="(group,id) in groups" :key="id">
<input type="text" v-model="group.from">
<input type="text" v-model="group.till">
<button #click="removeGroup(id)">Remove</button>
</div>
</form>
<button #click="addGroup">add</button>
<h2>Results</h2>
{{ result }}
<pre>{{ $data }}</pre>
So, the idea is that I should be able to calculate the difference between "from" field and "till" field in the groups array but at the same time result should reflect the sum of all differences. I tried with watch but in actual form there are a lot of fields and I might be over thinking. would appreciate some help. here is the vue code
var vm = new Vue({
data: {
groups: [
{
from: '',
till: ''
}
],
},
computed: {
result() {
return 0
}
},
methods: {
addGroup: function () {
var additional = {
from: '',
till: ''
}
this.groups.push(additional)
},
removeGroup: function (id) {
var index = this.groups[id]
this.groups.splice(index, 1)
},
}
}).$mount('#app')

Just use a computed property. Because of groups reactivity any reference to this.groups would trigger an update:
import moment from 'moment'
...
// assuming your date is a string
computed: {
result() {
return this.groups.reduce((group, total) => {
return total + moment(group.from).diff(group.till, 'years')
}, 0)
}
},
Update
Now that I know you're working with dates, I'd suggest a library like moment or fecha. Here's how to calculate differences with moment

Related

Get name model in vue js with help id input or name

Can i get model name if i now id input?
For examle
<input v-model="data.name" id="name_db">
I have in db value for data.name
Before vue i did this:
valuesFromDb.forEach(data=>{
if(data.fromdb==name_db)
$("#name_db").val(data.fromdb)
}
...
But it can't work with vueJS
I know i can do this:
data.name = data.fromdb
But i have many data in db and before vue i put data with help forloop.
Model and id have different names ​​and it will take a long time to manually iterate through all the data
Now i want get model name and put value to it
Somethinks like this:
var modelName = $("#name_db").getModelNameVue();
modelName=data.fromdb
If i do this, in input value change but in data dont
data(){
return{
mainPdf:{
left: 5,
bottom:5,
top:5,
right:5
}
}
}
<input v-model="mainPdf.left" id="left_margin">
<input v-model="mainPdf.bottom" id="bot_margin">
<input v-model="mainPdf.isMargin" id="right_margin">
<input v-model="mainPdf.isMargin" id="up_margin">
getFromdb(){
api.getFromdb(e=>{ // string=e
var string = "left_margin=0&bot_margin=1&right_margin=2&up_margin=3"
var rPlus = /\+/g;
$.each( string.split( "&" ), function( index, field ) {
$.each( string.split( "&" ), function( index, field ) {
var current = field.split( "=" );
if( current[ 1 ] && current[ 0 ]) {
var name = decodeURIComponent(current[0].replace(rPlus, "%20"));
var value = decodeURIComponent(current[1].replace(rPlus, "%20"));
$("#"+ name).val(value);
}
});
})
})
I can't dynamic-binding because i can't change name of properties in mainPdf, because i have entity with same fields(left,bottom,top,right) in my backend
==========i found solution
i used dispatchEvent
$("#" + NAME).prop("checked", true);
$("#"+ NAME")[0].dispatchEvent(new Event('change')); //or input
Using Vue.js and dynamic programming techniques, it's a piece of cake.
Vue.component('dynamic-binding', {
template: `
<div style="display: flex;">
<input
v-for="field in Object.keys(mainPdf)" :key="field"
v-model="mainPdf[field]"
>
</div>
`,
data() {
return {
mainPdf: {},
};
},
methods: {
fromDb(val = 'left_margin=0&bot_margin=1&right_margin=2&up_margin=3') {
const db = new URLSearchParams(val);
this.mainPdf = Object.fromEntries(db);
},
},
mounted() {
this.fromDb();
},
});
new Vue({ el: '#app' });
<div id="app">
<dynamic-binding></dynamic-binding>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

How do I set a default value for v-model using computed property

I have two input fields for dates: to and from.
I want the user to be able to select dates that I will send a request to the backend. That is why I am using a computer property - in the setter I will validate the dates to make sure from is less than to and to is not less than from.
How do I set default values for those inputs?
I am using computed properties so I can set default values for both inputs. One value is set to now, the other is 1 week ago.
<template>
<div class="logs-listing-table">
<div class="mb-1 filter-actions-wrapper">
<input type="date" v-model="this.fromDate">
<input type="date" placeholder="this.toDate">
</div>
</div>
</template>
<script>
export default {
name: 'BnbReport',
data () {
return {
fromDate: this.fromDateDefault(),
toDate: this.toDateDefault()
}
},
computed: {
fromDateDefault () {
var previousPeriod = new Date()
previousPeriod.SetDate(previousPeriod.getDate() - 7)
previousPeriod.toISOString().substr(0, 10)
this.fromDate = previousPeriod
return this.fromDate
},
toDateDefault () {
var today = new Date()
today.toISOString().substr(0, 10)
this.toDate = today
return this.toDate
}
}
}
</script>
However, eslint throws me an error:
Unexpected side effect in "fromDateDefault" computed property
Unexpected side effect in "toDateDefault" computed property
You can add get and set functions into your computed property.
HTML:
<input type="date" v-model="fromDateDefault">
JS:
computed: {
fromDateDefault: {
get() {
//your validation
return this.fromDate;
},
set(val) {
this.fromDate = val;
},
},
}
You can read more about the setters and getters in the official doc:
https://v3.vuejs.org/guide/computed.html#computed-properties

Vue sorting a frozen list of non-frozen data

I have a frozen list of non-frozen data, the intent being that the container is not reactive but the elements are, so that an update to one of the N things does not trigger dependency checks against the N things.
I have a computed property that returns a sorted version of this list. But Vue sees the reactive objects contained within the frozen list, and any change to an element results in triggering the sorted computed prop. (The goal is to only trigger it when some data about the sort changes, like direction, or major index, etc.)
The general concept is:
{
template: someTemplate,
data() {
return {
list: Object.freeze([
Vue.observable(foo),
Vue.observable(bar),
Vue.observable(baz),
Vue.observable(qux)
])
}
},
computed: {
sorted() {
return [...this.list].sort(someOrdering);
}
}
}
Is there a Vue idiom for this, or something I'm missing?
...any change to an element results in triggering the sorted computed prop
I have to disagree with that general statement. Look at the example below. If the list is sorted by name, clicking "Change age" does not trigger recompute and vice versa. So recompute is triggered only if property used during previous sort is changed
const app = new Vue({
el: "#app",
data() {
return {
list: Object.freeze([
Vue.observable({ name: "Foo", age: 22}),
Vue.observable({ name: "Bar", age: 26}),
Vue.observable({ name: "Baz", age: 32}),
Vue.observable({ name: "Qux", age: 52})
]),
sortBy: 'name',
counter: 0
}
},
computed: {
sorted() {
console.log(`Sort executed ${this.counter++} times`)
return [...this.list].sort((a,b) => {
return a[this.sortBy] < b[this.sortBy] ? -1 : (a[this.sortBy] > b[this.sortBy] ? 1 : 0)
});
}
}
})
Vue.config.productionTip = false;
Vue.config.devtools = false;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.12/vue.min.js"></script>
<div id="app">
<div>Sorted by: {{ sortBy }}</div>
<hr>
<button #click="list[0].name += 'o' ">Change name</button>
<button #click="list[0].age += 1 ">Change age</button>
<hr>
<button #click="sortBy = 'name'">Sort by name</button>
<button #click="sortBy = 'age'">Sort by age</button>
<hr>
<div v-for="item in sorted" :key="item.name">{{ item.name }} ({{item.age}})</div>
</div>

VueJS dynamic data + v-model

In my data object, I need to push objects into an array called editions.
data() {
return {
editions: []
}
}
To do this, I am dynamically creating a form based on some predetermined field names. Here's where the problem comes in. I can't get v-model to cooperate. I was expecting to do something like this:
<div v-for="n in parseInt(total_number_of_editions)">
<div v-for="field in edition_fields">
<input :type="field.type" v-model="editions[n][field.name]" />
</div>
</div>
But that isn't working. I get a TypeError: _vm.editions[n] is undefined. The strange thing is that if I try this: v-model="editions[n]"... it works, but I don't have the property name. So I don't understand how editions[n] could be undefined. This is what I'm trying to end up with in the data object:
editions: [
{
name: "sample name",
status: "good"
},
...
]
Can anyone advise on how to achieve this?
But that isn't working. I get a TypeError: _vm.editions[n] is undefined.
editions is initially an empty array, so editions[n] is undefined for all n. Vue is essentially doing this:
const editions = []
const n = 1
console.log(editions[n]) // => undefined
The strange thing is that if I try this: v-model="editions[n]"... it works
When you use editions[n] in v-model, you're essentially creating the array item at index n with a new value. Vue is doing something similar to this:
const editions = []
const n = 2
editions[n] = 'foo'
console.log(editions) // => [ undefined, undefined, "foo" ]
To fix the root problem, initialize editions with an object array, whose length is equal to total_number_of_editions:
const newObjArray = n => Array(n) // create empty array of `n` items
.fill({}) // fill the empty holes
.map(x => ({...x})) // map the holes into new objects
this.editions = newObjArray(this.total_number_of_editions)
If total_number_of_editions could change dynamically, use a watcher on the variable, and update editions according to the new count.
const newObjArray = n => Array(n).fill({}).map(x => ({...x}))
new Vue({
el: '#app',
data() {
const edition_fields = [
{ type: 'number', name: 'status' },
{ type: 'text', name: 'name' },
];
return {
total_number_of_editions: 5,
editions: [],
edition_fields
}
},
watch: {
total_number_of_editions: {
handler(total_number_of_editions) {
const count = parseInt(total_number_of_editions)
if (count === this.editions.length) {
// ignore
} else if (count < this.editions.length) {
this.editions.splice(count)
} else {
const newCount = count - this.editions.length
this.editions.push(...newObjArray(newCount))
}
},
immediate: true,
}
}
})
<script src="https://unpkg.com/vue#2.6.10/dist/vue.min.js"></script>
<div id="app">
<label>Number of editions
<input type="number" min=0 v-model="total_number_of_editions">
</label>
<div><pre>total_number_of_editions={{total_number_of_editions}}
editions={{editions}}</pre></div>
<fieldset v-for="n in parseInt(total_number_of_editions)" :key="n">
<div v-for="field in edition_fields" :key="field.name+n">
<label>{{field.name}}{{n-1}}
<input :type="field.type" v-if="editions[n-1]" v-model="editions[n-1][field.name]" />
</label>
</div>
</fieldset>
</div>

how to do filters in vue.js

i am new to vue.js.so i want to apply a filter thing in my project.i tried to do this from past 2 to 3 days..but i couldn't..can any one help me how to do this..
I have 3 input boxes one is experience,expected_ctc,and profile_role depending on these 3 i want to display the results..
Here is my js page:
const app = new Vue({
el: '#app',
data() {
return {
page: 0,
itemsPerPage: 3,
}
},
components: { Candidate },
methods: {
//custom method bound to page buttons
setPage(page) {
this.page = page-1;
this.paginedCandidates = this.paginate()
},
paginate() {
return this.filteredCandidates.slice(this.page * this.itemsPerPage, this.page * this.itemsPerPage + this.itemsPerPage)
},
},
computed: {
//compute number of pages, we always round up (ceil)
numPages() {
console.log(this.filteredCandidates)
return Math.ceil(this.filteredCandidates.length/this.itemsPerPage);
},
filteredCandidates() {
//filter out all candidates that have experience less than 10
const filtered = window.data.candidates.filter((candidate) => {
if(candidate.experience === 5) {
return false;
}
return true;
})
console.log(filtered);
return filtered;
},
paginedCandidates() {
return this.paginate()
}
}
});
here is my buttons from view page:
<div class="container">
<b>Experience:</b><input type="text" v-model="experience" placeholder="enter experience">
<b>Expected CTC:</b><input type="text" v-model="expected_ctc" placeholder="enter expected ctc">
<b>Profile Role:</b><input type="text" v-model="profile_role_id" placeholder="enter role">
<input type="button" name="search" value="search" >
</div>
Can anyone help me..
Thanks in advance..
Ok let's start with a smaller example. Lets say you have "Candidates" one one candidate might look like
{
name: 'John Doe',
expected_ctc: 'A',
experience: 'B',
profile_role_id: 1
}
From your current state I'd say you have all candidates in an array returned by laravel. Let's say we're in your current template where you have your vue app
<div id="app">
<!-- lets start with one filter (to keept it clean) -->
<input type="text" v-model="experienceSearch"/>
<ul class="result-list">
<li v-for="result in candidatelist">{{ result.name }}</li>
</ul>
</div>
And now to the script
// always init your v-model bound props in data
// usually you wouldn't take the candidates from the window prop. However, to keep it easy for you here I will stick to this
data: function() {
return {
experienceSearch: '',
candidates: window.data.candidates
}
},
// the list that is displayed can be defined as computed property. It will re-compute everytime your input changes
computed: {
candidatelist: function() {
// now define how your list is filtered
return this.candidates.filter(function(oCandidate) {
var matches = true;
if (this.experienceSearch) {
if (oCandidate.experience != this.experienceSearch) {
matches = false;
}
}
// here you can define conditions for your other matchers
return matches;
}.bind(this));
}
}
General steps:
all candidates are in data -> candidates
relevant (filtered) candidates are represented by the computed prop candidatelist
inputs are bound with v-model to EXISTING data prop definitions
Fiddle https://jsfiddle.net/sLLk4u2a/
(Search is only exact and Case Sensitive)