Datatable v-for to produce checkbox or input based on data - vue.js

Wondering how I can get my datatable to build a column that produces either a checkbox or input based on a value from data. This is the what I have but I have a good feeling there is a way better way of doing this.
<div v-for=”shirt in shirts”>
<div v-if=”stock.shirts < 2”>
<td><input type="checkbox"></td>
</div>
<div v-else>
<td><input type="text"> of {{ props.item.shirts }}</td>
</div>
</div>
Any help would be greatly appreciated

reduce your if clause
<td v-for=”shirt in shirts”><input type="checkbox"></td>
<td v-else><input type="text"> of {{ props.item.shirts }}</td>
vue docs - Conditional Rendering
or you can use dynamic components, like so:
<template>
<td>
<component :is="component" :data="passthroughdata" />
</td>
</template>
//...
props: ["value", "passthroughdata"],
data() {
return {
component: {}
},
},
watch: {
value:{
handler: async function(){
try{
await import(`./components/${valueBasedComponent}/index.vue`)
this.component = () => import(`./${valueBasedComponent}/index.vue`)
} catch() {
this.component = () => import(`./${someDefaultComponent}/index.vue`)
}
},
// immediate: true
}
}
vue docs - Dynamic & Async Components

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.

vue bootstrapTable cannot click v-on:click

i cannot click v-on:click after mounted .bootstrapTable()
but not used .bootstrapTable() it is normal to use v-on:click
Do I need to listen to any additional functions?
Or what kind of code should I write?
file.vue
<template>
<div>
<table id="table">
<tr>
<th>#</th>
</tr>
<tr v-for="(d, index) in data" :key="index">
<td><a class="btn btn-secondary" type="button" #click="callText(d.text)">{{d.text}}</a></td>
</tr>
</table>
</div>
</template>
<script>
export default {
name: 'file',
data () {
return {
data: [{"text":'1'},{"text":'2'},{"text":'3'}]
}
},
methods: {
buildTable() {
$('#table').bootstrapTable('destroy').bootstrapTable({})
},
callText(t){
console.log(t);
}
},
mounted: function(){
this.buildTable();
}
}
</script>
You can, and it still works. Are you even looking at your console? The only problem is that the cursor is not changing to a pointer as with an actual button.

How to pass a component to render in props in Vue Js?

I have a situation where i need to render data cell synamically
where tableProps contain all columns and dataProps.
tableProps: {
cols: [{
cellProps: {
class: "as"
},
cellRenderer: ((data) => {
return <a onlick = {
this.onDataClick
}
class = "btn btn-link" > {
data.name
} < /a>
}).bind(this),
dataKey: "name",
dataType: String,
label: "Name",
sortable: true
}
],
enableSelect: true,
onPageChange: this.onPageChange,
onSelect: (selectedRow) => console.log("selectedRow", selectedRow),
onSelectAll: (data) => console.log("slectAllClick", data),
page: 0,
rowProps: {
onClick: (event, rowData) => {
this.onClick(rowData);
}
},
rowsPerPage: 5,
title: "Nutrition"
}
There is a cell renderer where data can be passed to render custom data like buttons anchor etc..
the solution has been found, instead of sending a function, scoped slots can be used to render dynamic contents for each cell. Thank you for showing interest.
**Table.Vue(child, generic-table)**
<table class="table table-bordered">
<thead>
<tr>
<th v-for="col in options.cols" :key="col.id">
<template v-if="col.colRenderer">
{{col.colRenderer(col)}}
</template>
<template v-else>
{{col.label}}
</template>
</th>
</tr>
</thead>
<tbody>
<tr v-for="datum in data" :key="datum.id" #click="(e)=> options.rowProps.onClick ? options.rowProps.onClick(e, datum): ''">
<td v-for="col in options.cols" :key="col.id" #click="()=> col.onClick ? col.onClick(datum[col.dataKey]): ''">
<template v-if="col.cellSlot">
<slot :name="col.cellSlot.name" :data="datum[col.dataKey]"/>
</template>
<template v-else>
{{datum[col.dataKey]}}
</template>
</td>
</tr>
</tbody>
</table>
**Calling component(Parent, with Custom Data cells)**
<v-table
:name="carePlanName"
:options="tableProps"
:total-count="totalCount"
:data="users" >
<div
slot=""
slot-scope="slotProps">
<!-- Define a custom template for CellData Data -->
<!-- `slotProps` to customize each todo. -->
<span v-if="slotProps">✓
<button>{{ slotProps.name }}</button>
</span>
</div>
</v-table>

Vue.js - data access with dynamic components

I have simple web page that shows a result list and users can switch between table or li style.
I got simple Vue with two dynamic components : results-array and results-list.
It works like a charm except when I switch from the first component to the second one: I loose results properties called in mustache (I got blank values with no error) :
{{contact.img_path}} does not show anything
whereas
<img :src="contact.img_path" /> works great
** UPDATE **
Here a simplified jsfiddle to try out: https://jsfiddle.net/eywraw8t/151906/
My files :
contact.js
var list = Vue.component('results-list', {
template: '#results-list-template',
props: ['display_mode', 'contacts']
});
var table = Vue.component('results-array', {
template: '#results-array-template',
props: ['display_mode', 'contacts'],
});
const app = new Vue({
el: '#app',
router,
data: {
currentResultsView: 'results-array',
display_mode: 'array',
contacts: [],
contact: { company: {}, phones: {}, section: {}, schedule_type: {}}, // Declaring Reactive Properties
phone: {} // Declaring Reactive Properties
},
created () {
this.navigate(this.$route.query.page);
},
methods: {
changeDisplay: function(event, type){
this.currentResultsView = (type == "array") ? "results-array" : "results-list";
this.display_mode = type;
console.log('contacts', this.contacts[0].lastname) // WORKS !
},
navigate: function(page){
var page = page > 0 ? page : 1;
axios.get('/', {params: {page: page, fulltext_search: this.fulltext_search, sort_dir: this.sort_dir}})
.then((response) => {
this.contacts = response.data.entries;
});
}
}
});
index.html
<ul>
<li #click="changeDisplay($event, 'hcard')" :class="{active:display_mode == 'hcard'}">Carte de visite</li>
<li #click="changeDisplay($event, 'vcard')" :class="{active:display_mode == 'vcard'}">Vignette verticale</li>
<li #click="changeDisplay($event, 'array')" :class="{active:display_mode == 'array'}">Tableau</li>
</ul>
<div id="app">
<script type="text-x-template" id="results-array-template">
<table>
<tr>
<th></th>
<th>Firstname</th>
<th>Lastname</th>
</tr>
<tr v-for="contact in contacts">
<td><img :src="contact.img_path" class="contact_img" /></td>
<td>{{ contact.firstname }}</td>
<td>{{ contact.lastname }}</td>
</tr>
</table>
</script>
<script type="text-x-template" id="results-list-template">
<ul>
<li v-for="contact in contacts">
{{contact.firstname}} <!-- **Does not show anything** -->
<img :src="contact.img_path" /> <!-- **Works great!** -->
</li>
</ul>
</script>
<div id="results" :class="display_mode" class="clearfix">
<keep-alive>
<component v-bind:is="currentResultsView" :display_options="display_options" :display_mode="display_mode" :contacts="contacts" ></component>
</keep-alive>
</div>
</div>
You should either remove the key contact from the data part of your Vue root instance, or use another name in the v-for iterator (e.g. v-for="myContact in contacts")
UPDATE
Also, you should not use script tags for the template - use template instead, because Chrome ignores non-JavaScript script tags.
The solution - https://codepen.io/TMCDOS/pen/gjYWNY
The solution is to move the two template scripts outside of the #app div

Vue 2 - update value of the array element after click event

Is it possible, when I fire updateCountry method (defined in country-list component), to update the value (if successful call) of that array element, so that the button will dynamically change text based on country.show value?
This is the Vue code I have at the moment:
Vue.component('country-list', {
template: `
<tbody>
<tr is="country" v-for="(country, index) in countries.data">
<td>
<input
type="text"
name="name"
class="form-control country-name"
:value="country.name"
>
</td>
<td>
<select name="show" class="form-control country-show" :value="country.show">
<option value="0">No</option>
<option value="1">Yes</option>
</select>
</td>
<td>
<input
type="text"
name="order"
class="form-control country-order"
:value="country.order"
>
</td>
<td>
<button class="btn btn-primary">
{{ country.show ? "Hide" : "Show" }}
</button>
<button class="btn btn-success"
#click="updateCountry"
:data-id="country.id">Update</button>
</td>
</tr>
</tbody>
`,
props: ['countries'],
methods: {
updateCountry(event) {
let self = this;
let countryID = event.target.dataset.id;
let parent = event.target.closest('.parent');
let countryName = parent.getElementsByClassName('country-name')[0].value;
let countryOrder = parent.getElementsByClassName('country-order')[0].value;
let countryShow = parent.getElementsByClassName('country-show')[0].value;
axios.post('/country/insert', {
id: countryID,
name: countryName,
order: countryOrder,
show: countryShow
})
.then(function (response) {
console.log(self);
})
.catch(function (error) {
console.log(error);
});
}
}
});
Vue.component('country', {
template: `<tr class=parent><slot></slot></tr>`
});
Vue.component('pagination-list', {
template: `
<tfoot>
<tr align="center">
<nav aria-label="Page navigation">
<ul class="pagination">
<li :class="countries.current_page == 1 ? 'disabled' : ''">
<a
:class="countries.current_page == 1 ? 'disabled' : ''"
:href="countries.current_page == 1 ? '#' : countries.prev_page_url"
#click.prevent="pagination(countries.current_page - 1)"
aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<li v-for="i in countries.last_page"
:class="countries.current_page == i ? 'active' : ''"
>
<a
:href="countries.current_page == i ? '#' : '/admin/countries?page='+i"
#click.prevent="pagination(i)"
>{{i}}</a>
</li>
<li>
<a
:href="countries.next_page_url"
#click.prevent="pagination(countries.current_page + 1)"
aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</tr>
</tfoot>
`,
props: ['countries'],
methods: {
pagination(page) {
this.$parent.getCountries(page);
}
}
});
let App = new Vue({
el: '#app-container',
data: {
countries: []
},
created() {
this.getCountries()
},
methods: {
getCountries(page) {
let self = this;
let getParam = page ? '?page=' + page : '';
axios.get('/admin/countries' + getParam)
.then(function (response) {
self.countries = response.data;
})
.catch(function (error) {
console.log(error);
});
},
filterCountries(event) {
let name = event.target.value;
let self = this;
if(name.length > 2) {
axios.get('/country/search', {
params: {
name: name
}
})
.then(function (response) {
self.countries = response.data;
console.log(self.countries);
})
.catch(function (error) {
console.log(error);
});
}
if((event.keyCode === 8 && name.length === 2) || !name.length){
this.getCountries();
}
}
}
})
This code would be much more Vue like if you used v-model and it would cut down on some of the things you are having to do. For example if you update your country-list template like this:
<tbody>
<tr is="country" v-for="(country, index) in countries.data" :key="country">
<td>
<input
type="text"
name="name"
class="form-control country-name"
v-model="country.name"
>
</td>
<td>
<select name="show" class="form-control country-show" v-model="country.show">
<option value="0">No</option>
<option value="1">Yes</option>
</select>
</td>
<td>
<input
type="text"
name="order"
class="form-control country-order"
v-model="country.order"
>
</td>
<td>
<button class="btn btn-primary">
{{ country.show ? "Hide" : "Show" }}
</button>
<button class="btn btn-success"
#click="updateCountry(country)"
:data-id="country.id">Update</button>
</td>
</tr>
</tbody>
Then your updateCountry method could just be this
updateCountry(country) {
axios.post('/country/insert', country)
.catch(err => //do something on error)
}
Because using v-model, all the values are already updated locally, and you are just posting the values to the server. Since you are passing the actual country to the updateCountry method, there is no need to get the values from the inputs.
Note also, I added :key="country" to your v-for because a key is required when you iterate a component. If you have a country.id that would be even better as the key. But, again, I don't understand why you need the country component at all. It's completely unnecessary at this point.