dynamically add input as well as dropdown in vuejs - vuejs2

I m trying to add a dynamical input along with dropdown for that i m using vue-serach-select let me show my code then issue in detail
<template>
<button #click="addRow1"></button>
<table class="table table-striped">
<thead>
<tr style="font-size: 12px; text-align: center;">
<th class="span2" >Product Name</th>
<th class="span2" >Unit</th>
</tr>
</thead>
<tbody id="product_table_body">
<tr v-for="(row, index) in rows">
<td><model-list-select :list="productname"
option-value="product_name"
option-text="product_name"
v-model="row.selectproduct"
placeholder="Search Product Name"
#searchchange="searchprd3">
</model-list-select>
</td>
<td>
<input class="form-control-sm" type="text" v-model="row.new1" disabled="disabled" style="width: 100px;">
</td>
</tr>
</tbody>
</table>
</template>
<script>
export default {
data () {
return {
productname3:[],
rows:[],
}
},
methods:{
addRow1(){
this.rows.push({})
},
searchprd3(search,index){
},
}
}
</script>
now if i click on button one more row is added with dropdown now my problem is that how i can differentiate productname according to dynamic create row i had tried like :list="productname{index},:list="productname.index but none of them worked and last thing i want to pass index parameter in searchprd3 function so i tried like this searchprd3(search,index) in function I m getting index but it throw error for search and if only pass index then also throw error however it work none of parameter is passed from select like this #searchchange="searchprd3" but in function i m not getting index value or is there anyother way to achieve this thing
updated
<tr v-for="(row, index) in rows">
<td><model-list-select :list="row.productname"
option-value="product_name"
option-text="product_name"
v-model="row.selectproduct"
placeholder="Search Product Name"
#searchchange="searchprd3">
</model-list-select>
</td>
</tr>
<script>
searchprd3(searchText,index){
var _this=this
this.$http.get('/api/companyproducts?filter[where][product_name][ilike]=%'+searchText+'%').then(function (response) {
_this.rows.push({productname:response.data})
}).catch(function (error) {
console.log("error.response");
});
},
</script>
i want select option list seprate for every row but my code throw error like "Cannot read property 'map' of undefined"
that is why row push not working for dynamic row is I m missing Something
update2
found my mistake
addRow1(){
this.rows.push({
productnamex:[],
unit:'',
qty:'',
amt:'',
cgst:'',
sgst:'',
igst:''})
},
problem is that i haven't initialize my dropdown at rows click now another problem is that why my drop not get populated

try like this
<template>
<model-list-select :list="row.productnamex"
option-value="product_name"
option-text="product_name"
v-model="row.selectproduct"
placeholder="Search Product Name"
#searchchange="searchprd3($event,index,row)" >
</model-list-select>
</template>
<script>
addRow1(){
console.log(this.rows)
this.rows.push({ productnamex:[],unit:'', qty:'',amt:'', cgst:'', sgst:'', igst:''})
},
searchprd3(searchText,index,row){
console.log(index)
var _this=this
console.log(row)
this.$http.get('/api/companyproducts?filter[where][product_name][ilike]=%'+searchText+'%').then(function (response) {
console.log(response.data)
row.productnamex=response.data
}).catch(function (error) {
console.log("error.response");
});
},
</script>
hope this will help you as well as other enjoy :D

you should be able to do:
:list="productname+index"

You need to manually pass the index into the callback together with the searchtext in order for your searchprd3 method to receive both values.
This is where the inline $event variable in your event listener comes into the action. The $event variable contains the value that is supposedly passed to your callback by the event.
So if you want to pass additional data into the callback aside from the data that is passed by the event, you can manually call the callback function and pass the $event together with the data that you want to pass which in this case, the index variable.
Your event listener should look like this:
#searchchange="searchprd3($event, index)"

Related

Vue js: How to add a class to the closest td on click of Button

I am new to Vue coming off of JS/JQuery. I have a table, and each row has 2 possible buttons and two inputs, all wrapped in <td>. When I click a button I want the nearest input to have a class added. In JQuery I would have used the closest method in selecting the neighbouring <td> Here is my Vue template syntax. Many thanks!
<tbody>
<tr v-for="child in registeredChildren">
<td class="col-2"><a :href="'/getchild/'+ child.child_id">{{child.childFirstName}}</a>&nbsp &nbsp {{child.childLastName}}</td>
<!--========TIME IN===========-->
<td class="col-3 pb-2"}"><input style="text-align:center;" class="form-control editChild initial" type="text" v-model="child.timeIn" ></td>
<td><button v-on:click="updateTimeIn(child)" class="btn btn-outline-success">Reset</button></td>
<!-- //========TIME Out ===========//-->
<td class="col-3 pb-2" ><input style="text-align:center;" class="form-control editChild" type="text" v-model="child.timeOut" ></td>
<td><button v-on:click="updateTimeOut(child)" class="btn btn-outline-success">Reset</button></td>
</tr>
</tbody>
Methods: I was thinking if I could add some code to the UpdateTimeIn and TimeOut methods, this could be an approach?
methods:{
updateTimeIn(child){
this.updatedChild = child;
console.log(child.child_id,child.timeIn)
axios.post('http://kidsclub.test/upDateChildTimeIn', {
child_id: child.child_id,
timeIn: child.timeIn,
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
},
**NB** I have the same for updateTimeOut
You are using Vue, which unlike jQuery, means the data should drive the DOM. In Vue, you don’t have to consider selecting certain dom nodes.
I used to switch from jQuery to Vue, too. I have provided a demo, hope you can find ideas in it.
<button #click="onClick">click me</button>
<div class="fixed-classes" :class="{'dynamic-class': isClick}"></div>
data() {
return {
isClick: false
};
},
methods: {
onClick() {
this.isClick = !this.isClick;
}
}
You can run it online through the code sandbox link: codesandbox
I updated the code based on the comments in the code sandbox.

search bar filter using Vue js

I am trying to filter a table that get data from api and I tried this solution but it doesnt work.
I couldnt find where the problem is and if I pass the search input event listener
and here is my table component :
<template>
<table class="mt-12 border-2 border-gray-600">
<thead>
<tr>
<th v-for="header in data.headers" :key="header" class="text-left border-l-2 border-gray-600 border-b-2 border-gray-600 bg-red-400 ">{{ header }}</th>
</tr>
</thead>
<tbody>
<tr v-for="(rows, index) in data.rows" :key="index">
<td v-for="row in rows" :key="row" class="border-l-2 border-gray-600" >{{ row }}</td>
</tr>
</tbody>
</table>
</template>
<script>
export default {
props: {
data: Object,
default: {}
}
}
</script>
<style src="../assets/tailwind.css"/>
My question:
If anyone can help me to define my problem and solve this ?
Thanks for help.
You can use your data as computed where you pass it as a prop.
<BaseTable :data='data' />
Here instead of using like this create a computed which can be filteredData.
<BaseTable :data='filteredData' />
and in your props you can simply filter it or just send the data as it is.
computed: {
filteredData() {
if(this.search) {
// filter your data as you want and return
}
else // return your main data
}
}
Here is a working simple example:
https://codesandbox.io/s/filterlist-example-vdwhg?file=/src/App.vue
And change your include to includes.
what error you are getting ? I think you are using this.search inside filteredRows function which is not a vue instance property. it should be this.data.search. The search is used with V-model as well so you should declare it outside data (JSON object).

Vue2: Can I pass an optional (global) filter into a reusable component?

I am quite new to Vue.
I am working on a table as component, which is supposed to be a lot of times. So far, so good, but now I want to use a filter, which can be optional passed into it.
That is how I "call" the table:
<table
:headers="headers"
:items="some.data"
></table>
data () {
return {
headers: [
{ title: 'date', value: ['date'], filter: 'truncate(0, 10, '...')' },
]
}
}
Here is my table component
<template>
<div>
<table class="table">
<thead>
<tr>
<!-- <th v-for="header in headers" :key="header.id" scope="col">{{ header.title }}</th> -->
<th v-for="header in headers" :key="header.id" scope="col">
{{ header.title }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="item in items" :key="item.id" scope="col">
<td v-for="header in headers" :key="header.id" scope="row">
<!-- {{item}} -->
<span v-for="val in header.value" :key="val.id">
{{item[val] | truncate(0, 10, '...') }}
</span>
<!-- {{header.filter}} -->
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script >
export default {
name: 'Table',
props: {
headers: Array,
items: Array
}
}
</script>
My global filter:
Vue.filter('truncate', function (text, start, truncLength, clamp = '') {
return text.slice(start, truncLength) + clamp
// return text.slice(0, stop) + (stop < text.length ? clamp || ' ...' : '')
})
I was hopping, to add by that an optional filter (via v-if I would chech for it). So far I can render the filter as string ... but not execute it.
Even if I put the filter in the span, it does not work (it says then, "text.slice is not a function" in the console.
I was not successful with googling it, because with filters/filter it is mostly about how to use .filter(...) on data as JS method, but not as Vue filter.
Any advise?
A filter is a function that runs inside JSX template in html. Example of how to create custom Vue.js filter
Vue.filter('ssn', function (ssn) { // ssn filter
return ssn.replace(/(\d{3})(\d{2})(\d{4})/, '$1-$2-$3');
});
Using it
{{stringToTrans | ssn}}
To use a filter outside this you can use a computed property or standard function like so
convertedDateString() { // computed
return this.$moment(this.dateString).format('MM/DD/YYYY')
}
convertedDateString(dateString) { // method
return this.$moment(dateString).format('MM/DD/YYYY')
}

Validate dynamic input field in vue.js

I have a table in which I add the input field dynamically and I set the validation manually by using Toastr notifications . what the problem is that when I add the input at the first time the validation is working perfectly but when I add another input the validation is not working on new added input. I have tried and searched for the solution but I did not find any solution.Any help will be highly appreciated.
My HTML code :
<table class="table-hover" id="form">
<thead>
<tr>
<th>پلورنکی</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, $index) in rows" :key="row.id">
<td>
<input
dir="rtl"
id="supplier_id1"
v-model="row.supplier_id1"
placeholder="نیټه "
type="text"
name="supplier_id1"
class="form-control"
/>
</td>
</tr>
</tbody>
</table>
<button
class="btn btn-success btn-xs"
#click="getData()"
>
خوندی کړی
</button>
My script code :
export default {
data() {
return {
rows: [
{
supplier_id1: "",
}
],
}
}
methods: {
getData: function() {
if (this.rows[0].supplier_id1 == "") {
toast.fire({
icon: "warning",
html: "<h5> supplier id is required.</h5>"
});
} else {
//if the input is not emptyexecute the coed successfully
}
}
}
}
You will always check for the first row, because of if (this.rows[0]...)
rows[0] will always take the first object in your array
If you always want to validate all the rows, you could check if there are any rows without a supplier id: if (this.rows.filter((row) => row.supplier_id1 === "").length)
I not sure which toast component did you used, but i can do similar mock for your validation message + databinding of your {{row.supplier_id1}}
v-model value of input[type="date] will only valid when you inputted date correctly so this.rows[0].supplier_id1.length == 0 to validate is fine. The reactivity is working fine.
My Working Fiddle: https://jsfiddle.net/bu9twps2/
UPDATE: Your original condition to validate works fine as well, problem likely lies at your toast

How to process the emitted event from the component in v-for of Vuejs

I'm trying to process the emitted the event from the component rendered by the v-for.
For example,
I've made a combobox component that emits the event when changing the value.
It emits the event by this.$emit('item_change', item);.
I want to process this event for the corresponded user.
In the below code, I want to change the status value of the user when changing the value of the combobox of user.
It gets item as parameter when using v-on:item_change="status_change"
example
But it doesn't get the item as parameter in v-on:item_change="status_change(item , user)" though combobox emits the event with item, and status of user keeps the original value.
How could I solve this issue?
JSFiddle Example
<div id="mainapp">
<table>
<thead>
<th>Name</th><th>Status</th>
</thead>
<tbody>
<tr v-for="user in users">
<td>{{user.name}}</td>
<td><combobox v-bind:default="user.status" v-bind:data="status_codes" v-on:item_change="status_change(item, user)"></combobox></td>
</tr>
</tbody>
</table>
</div>
JS code
var combobox = Vue.component('combobox', {
data: function () {
return {
selected_item:{title:'Select', value:-1},
visible:false
}
},
props:['data','default','symbol'],
template: `
<div class="combobox">
<span class="symbol" v-if="!symbol">
<i class="fa fa-chevron-down" aria-hidden="true" ></i>
</span>
<span class="main" v-on:click="toggleVisible">{{selected_item.title}}</span>
<ul class="combodata" v-if="visible">
<li class="item" v-for="item in data" v-on:click="select(item)">{{item.title}}</li>
</ul>
</div>
`,
created:function(){
if(this.data.length>0){
if(this.default == null || this.default == undefined || this.default =='') this.default=0;
this.selected_item = this.data[this.default];
}
},
methods:{
toggleVisible:function(){
this.visible = !this.visible;
},
select:function(item){
if(this.selected_item != item){
this.selected_item= item;
this.$emit('item_change', item);
}
this.visible = false;
}
}
});
var app=new Vue({
el:"#mainapp",
data:{
status_codes:[{title:'Inactive', value:0},{title:'Active', value:1}],
users:[{name:'Andrew', status:1},{name:'Jackson', status:0},{name:'Tom', status:1}]
},
methods:{
status_change:function(item,user){ //This gets only the parameter from the event. How could I pass the additional parameters to this function?
console.log(item,user);
try{
user.status = item.value;
}catch(e){ console.log}
}
}
});
You need to pass $event to your status_change handler instead of item
<div id="mainapp">
<table>
<thead>
<th>Name</th>
<th>Status</th>
</thead>
<tbody>
<tr v-for="user in users">
<td>{{user.name}}</td>
<td>
<combobox v-bind:default="user.status" v-bind:data="status_codes" v-on:item_change="status_change($event, user)"></combobox>
</td>
</tr>
</tbody>
</table>
</div>
JSFiddle
See the Vue docs here about event handling:
Sometimes we also need to access the original DOM event in an inline statement handler. You can pass it into a method using the special $event variable
Use $event
What you need is actually v-on:item_change="status_change($event , user)".
When you do this.$emit('item_change', whatever);, whatever will become $event in the event listener.
https://jsfiddle.net/jacobgoh101/bLsw085r/1/
Try passing parameters to your function like this:
v-on:item_change="status_change(item, user)"
And in your function declaration, specify the parameters:
status_change: function (item, user) {
console.log(item, user);
}