Make a checkbox selection default out of a group - vue.js

I want to make the second checkbox always selected by default even on page reload like the image-
The user can select other checkboxes later but by default, the second should be selected always.
Here is the checkbox code-
<template>
<div>
<div class="tw-flex tw-flex-wrap">
<div class="tw-w-full lg:tw-w-1/4">
<collabmed-loading v-if="!initialised">Loading Patient Info...</collabmed-loading>
<reception-patient-info
class="tw-px-0 tw-pt-0"
v-else
:patient-id="admissionRequest.patient_id"
>
</reception-patient-info>
</div>
<div class="tw-w-full lg:tw-w-3/4 lg:tw-pl-5">
<acemed-card>
<acemed-title>
Check In Details
<template #right>
<div v-if="initialised" class="tw-text-lg tw-text-gray-800"><strong>Admission Type:</strong> {{ admissionRequest.admission_type_name }}</div>
</template>
</acemed-title>
<div>
<collabmed-loading v-if="!initialised"></collabmed-loading>
<div v-else>
<div class="tw-flex tw-flex-wrap">
<div class="tw-w-full lg:tw-w-1/2">
<div class="tw-flex tw-flex-wrap tw-justify-between">
<div>
<v-tooltip bottom v-if="msetting('inpatient.inpatient_no_prefix')">
<v-btn flat style="min-width: 50px" slot="activator" class="pull-right pt-3">
{{ msetting('inpatient.inpatient_no_prefix') }}-
</v-btn>
<span>IP Number Prefix</span>
</v-tooltip>
</div>
<div>
<v-text-field
v-model="obj.admission.inpatient_no"
class="mr-2"
label="IP Number"
hint="Possible Format: #######/YY"
></v-text-field>
</div>
<div>
<v-tooltip bottom>
<v-btn
color="primary"
style="min-width: 50px"
slot="activator"
#click="generateIpNumber()"
:loading="generating"
>
<v-icon small>mdi-cached</v-icon>
</v-btn>
<span>Generate IP Number</span>
</v-tooltip>
</div>
</div>
</div>
<div class="tw-w-full tw-pt-5 lg:tw-pt-0 lg:tw-w-1/2 lg:tw-pl-5">
<collabmed-date-time-picker
label="Admission Date"
outline
:maxDate="today"
#input="setAdmissionDate"
></collabmed-date-time-picker>
</div>
<div class="tw-w-full lg:tw-w-1/2 tw-pt-5">
<div v-if="! obj.admission.external_doctor">
<div v-if="! obj.admission.doctor_id">
<users-search
:roles-like="['doc']"
:label="'Admission Doctor'"
#results="setDoctor"
></users-search>
</div>
<p v-else class="pt-3 pl-3 border-bottom subheading">Doctor:</p>
</div>
<p v-else class="pt-3 pl-3 border-bottom subheading">External Doctor:</p>
</div>
<div class="tw-w-full lg:tw-w-1/2 tw-pt-5 lg:tw-pl-5">
<div v-if="obj.admission.doctor_id">
<p class="pt-3 pl-3 border-bottom subheading">
{{ obj.admission.doctor_name }}
<v-btn small color="red" icon dark #click="unsetDoctor()">
<v-icon small>delete</v-icon>
</v-btn>
</p>
</div>
<div v-else>
<v-text-field
v-model="obj.admission.external_doctor"
class="mx-2"
label="External Doctor"
hide-details clearable
></v-text-field>
</div>
</div>
<div class="tw-w-full lg:tw-w-1/2 tw-pt-5">
<v-autocomplete
v-model="obj.admission.ward_id"
:items="wards"
#change="updateBeds()"
item-text="name"
item-value="id"
label="Select a Ward"
hide-details
outline
></v-autocomplete>
</div>
<div class="tw-w-full lg:tw-w-1/2 tw-pt-5 lg:tw-pl-5">
<div v-if="wardCashCharge" class="pl-3">
<p class="font-weight-bold title">Ward Charges</p>
<p>Cash Charge: <strong>{{ wardCashCharge | numberFormat }}</strong></p>
<p>Insurance Charge: <strong>{{ wardInsuranceCharge | numberFormat }}</strong></p>
</div>
</div>
<div class="tw-w-full lg:tw-w-1/2 tw-pt-5">
<v-autocomplete
v-model="obj.admission.bed_id"
:disabled="! obj.admission.ward_id"
:items="beds"
item-text="name"
item-value="id"
label="Select a Bed"
hide-details
outline
></v-autocomplete>
<p v-if="overbookingAllowed"><em>Over-booking of beds has been allowed in the system</em></p>
</div>
<div class="tw-w-full lg:tw-w-1/2 tw-pt-5 lg:tw-pl-5">
<v-autocomplete
v-model="obj.admission.charges"
:disabled="! obj.admission.ward_id"
:items="charges"
item-text="name"
item-value="id"
label="Select Other Charge(s)"
class="ml-2"
hide-details multiple
outline chips
></v-autocomplete>
</div>
<div class="tw-w-full lg:tw-w-1/2 tw-pt-5">
<v-alert :value="true" v-if="errors.any()" type="error" outline>
<div v-html="errors.display()"></div>
</v-alert>
</div>
<div class="tw-w-full tw-pt-5">
<v-btn block dark color="primary" class="mt-4" :loading="saveLoader" #click="save()">
Admit Patient
<v-icon class="pl-2">arrow_right_alt</v-icon>
</v-btn>
</div>
</div>
</div>
</div>
</acemed-card>
</div>
</div>
</div>
</template>
export default {
props: {
admissionRequestId: {
required: true,
}
},
data() {
return {
admissionRequestObj: new AdmissionRequest(),
obj: new Admission(),
wards: null,
saveLoader: false,
beds: [],
charges: [],
wardCashCharge: null,
wardInsuranceCharge: null,
today: moment(new Date()).format('YYYY-MM-DD HH:MM:ss'),
overbookingAllowed: false,
generating: false,
}
},
computed: {
...mapGetters([
'getWards',
]),
admissionRequest() {
return this.admissionRequestObj.selected
},
initialised() {
return this.wards && this.admissionRequest
},
saved() {
return this.obj.saved
},
submitted() {
return this.obj.form.submitted
},
contaminated() {
return this.obj.form.errorDetected;
},
errors() {
return this.obj.form.errors;
},
generatedIpNuber() {
return this.obj.generatedIpNuber
}
},
watch: {
contaminated(val) {
if(val) {
this.saveLoader = false
}
},
submitted(val) {
if(val) {
this.saveLoader = false
}
},
saved(val) {
if(val) {
this.saveLoader = false
this.dialog = false
window.location = route('inpatient.admissions.index').relative()
}
},
admissionRequest(val) {
if(val) {
this.obj.admission.admission_request_id = val.id
this.obj.admission.visit_id = val.visit_id
this.obj.admission.inpatient_no = val.visit.patient.inpatient_no
this.obj.admission.patient_id = val.visit.patient.id
}
},
getWards(val) {
if(val) {
this.wards = this.getWards.data
}
},
generatedIpNuber(val) {
this.generating = false
if(val)
this.obj.admission.inpatient_no = val
}
},
methods: {
...mapActions([
'setWards',
]),
initialise() {
this.admissionRequestObj.find(this.admissionRequestId)
this.setWards()
this.obj.admission.admission_date = this.today
this.overbookingAllowed = this.$options.methods.msetting('inpatient.allow_overbooking_of_wards') == 1
},
updateBeds() {
let ward = _.find(this.wards, {id: this.obj.admission.ward_id})
this.wardCashCharge = ward.cash_cost
this.wardInsuranceCharge = ward.insurance_cost
this.beds = _.map(ward.beds, item => {
let name = "Bed No. " + item.number
! item.is_available ? name += " (Unavailable)" : '';
let disabled = ! item.is_available
this.overbookingAllowed ? disabled = false : null
return {
name: name,
id: item.id,
disabled: disabled
}
})
let firstAvailableBed = _.find(this.beds, { disabled: false })
firstAvailableBed ? this.obj.admission.bed_id = firstAvailableBed.id : null
if(this.charges && this.charges.length && this.charges.length >=2) {
// charges[1] = second item
this.obj.admission.charges.push(this.charges[1].id)
}
this.charges = _.map(ward.charges, item => {
let name = item.name + " - Kshs. " + item.cost;
item.type == 'recurring' ? name += " [RECURRING]" : '';
return {
id: item.id,
name: name
}
})
},
setDoctor(doctor) {
this.obj.admission.doctor_id = doctor.id
this.obj.admission.doctor_name = doctor.full_name
},
unsetDoctor() {
this.obj.admission.doctor_id = null
this.obj.admission.doctor_name = null
},
generateIpNumber() {
this.generating = true
this.obj.generateInpatientNumber()
},
setAdmissionDate(datetime) {
this.obj.admission.admission_date = datetime
},
save() {
this.saveLoader = true
this.obj.save()
}
},
mounted() {
this.initialise()
}
}
</script>
<style scoped lang="scss">
</style>
The api data looks like-
When I select bed, I call a method to fetch the charges. Thats where I have placed the code to select the admission charge where second charge item should always be selected.

If you only want to keep the second item by default selected, then on the mounted hook, just find the second item's id in your charges array, and push this id to your v-model variable (obj.admission.charges) and you should see that the second item is always selected.
Here is the demo-
NOTE-
I used your API data inside the data property of Vue as I can't send requests to your server. I also assumed the possible structure of obj.admission because you didn't mention it.
<!DOCTYPE html>
<html>
<head>
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#4.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
</head>
<body>
<div id="app">
<v-app>
<v-container>
<v-autocomplete
v-model="obj.admission.charges"
:disabled="!obj.admission.ward_id"
:items="charges"
item-text="name"
item-value="id"
label="Select Other Charge(s)"
class="ml-2"
hide-details
multiple
outlined
chips
>
</v-autocomplete>
</v-container>
</v-app>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script>
<script>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data() {
return {
search: null,
obj: {
admission: {
charges: [],
ward_id: "something",
}
},
charges: [
{
id: 2,
name: "Nursing Fee",
cost: "3000.00",
type: "recurring",
created_at: "2022-08-23 08:00",
},
{
id: 31,
name: "Admission Fee",
cost: "once",
type: "3000.00",
created_at: "2022-08-23 08:00",
},
{
id: 32,
name: "Dr. inpatient visit",
cost: "3000.00",
type: "once",
created_at: "2022-08-23 08:00",
},
{
id: 36,
name: "Dr. Anne Masicka",
cost: "3000.00",
type: "once",
created_at: "2022-08-23 08:00",
},
{
id: 29,
name: "Dr. inpatient visit (Dr. Marwa)",
cost: "3000.00",
type: "once",
created_at: "2022-08-23 08:00",
}
]
}
},
mounted() {
if(this.charges && this.charges.length && this.charges.length >=2) {
// charges[1] = second item
this.obj.admission.charges.push(this.charges[1].id)
}
}
})
</script>
</body>
</html>

Related

VueJs - Conditionaly showing elements in table

I have pretty simple table of users here with only 4 cols, and i want to show a button for each user depending on his status 'isActive'. If user is active i want to show button with text 'disable' and vice versa. I am little bit stuck with this because i dont have an idea how can i show these buttons, because i am using vuexy template for this project(admin panel). Is there a way to do this with JSX?
Please take a look at code, i am getting data from mysql with nodejs. Ask me if you need more info. Thanks.
<template>
<div>
<div class="container">
<b-card-text class="mb-2">
<div
v-if="showLoginError"
class="text-center bg-danger colors-container rounded text-white width-360 height-50 d-flex align-items-center justify-content-center mr-1 ml-50 my-1 shadow"
>
<span>{{ loginError }}</span>
</div>
</b-card-text>
<b-card-text class="mb-2">
<div
v-if="showSuccessMessage"
class="text-center bg-success colors-container rounded text-white width-360 height-50 d-flex align-items-center justify-content-center mr-1 ml-50 my-1 shadow"
>
<span>{{ successMessage }}</span>
</div>
</b-card-text>
<section id="card-actions" class="input-section">
<b-row>
<b-col cols="8">
<b-card-actions ref="cardAction">
<validation-observer ref="simpleRules">
<b-form>
<b-row>
<b-col md="6">
<b-form-group>
<validation-provider
#default="{ errors }"
name="First Name"
rules="required"
>
<b-form-input
v-model="name"
:state="errors.length > 0 ? false:null"
placeholder="Twitter username"
/>
</validation-provider>
</b-form-group>
</b-col>
<b-col cols="12">
<b-button
variant="primary"
type="submit"
#click.prevent="validationForm"
>
Submit
</b-button>
</b-col>
</b-row>
</b-form>
</validation-observer>
</b-card-actions>
</b-col>
</b-row>
</section>
// This is table
<b-table responsive="sm" :items="items"/>
</div>
</div>
</template>
<script>
import { ValidationProvider, ValidationObserver } from 'vee-validate'
import {
BFormInput, BFormGroup, BForm, BRow, BCol, BButton, BTable,
} from 'bootstrap-vue'
import { required } from '#validations'
import axios from 'axios'
import { getUserToken } from '#/auth/auth'
export default {
components: {
ValidationProvider,
ValidationObserver,
BFormInput,
BFormGroup,
BForm,
BRow,
BCol,
BButton,
BTable,
},
data() {
return {
name: '',
successMessage: '',
showSuccessMessage: false,
loginError: '',
showLoginError: false,
required,
items: [],
}
},
beforeMount() {
this.getAllUsers()
},
methods: {
getAllUsers() {
const API_URL = `${this.$server}/api/twitter/allusers`
const params = {
token: getUserToken(),
}
axios.post(API_URL, null, { params }).then(res => {
if (res.data) {
res.data.forEach(element => {
let isActive = 'active'
if (element.isActive === 0) {
isActive = 'disabled'
}
const arr = {
twitter_name: element.twitter_name,
twitter_username: element.twitter_username,
twitter_id: element.twitter_id,
userActive: isActive,
}
this.items.push(arr)
})
}
})
},
validationForm() {
const API_URL = `${this.$server}/api/twitter/adduser`
const params = {
twitter_username: this.name,
token: getUserToken(),
}
axios.post(API_URL, null, { params }).then(res => {
if (res.data.success) {
this.successMessage = res.data.message
this.showSuccessMessage = true
// Hide message after 5sec
setTimeout(() => {
this.successMessage = ''
this.showSuccessMessage = false
}, 5000)
} else {
this.loginError = res.data.message
this.showLoginError = true
// Hide message after 5sec
setTimeout(() => {
this.loginError = ''
this.showLoginError = false
}, 5000)
}
})
},
},
}
</script>
I'm a little bit confused, where do you want to show your button ?
If it's in the table, you can use the custom templation of Bootstrap-Vue, you'll find the doc here with an example : https://bootstrap-vue.org/docs/components/table#custom-data-rendering
EDIT: here an example for your case
<b-table responsive="sm" :items="items">
<template #cell(userActive)="data">
<b-button v-if="data.userActive">Disabled</b-button>
<b-button v-else>Enabled</b-button>
</template>
</b-table>

My page reloads, and the added task wont register

I am creating a to do list for my exam. For some reason the page keep reload when I click add task, and the tasks wont register. I am new to Vue.js and Javascript.
I have problems with finding the issue. It is a simple code, not to complex, but the add task part is not working.
Here is my code:
<template >
<section class="todolist">
<h1 class="title">{{ title }}</h1>
<form class="container">
<h3 class="container__title">New Task </h3>
<input class="container__input" type="text" placeholder="Enter task" v-model="task">
<button class="container__button" #click="addPlanningTask">Add Task</button>
<h3 class="container__title-second">To Do List</h3>
<ul>
<li v-for="(task, index) in tasks" :key="index">
<span>{{ task.name }} </span>
<button class="todolist__button" #click="deletePlanningTask">Remove</button>
</li>
</ul>
<h4 class="container__list-title" v-if="task.length === 0">
List is empty!</h4>
</form>
</section>
<div class="guestlist">
<h4 class="guestlist__title">{{ invited }}</h4>
<span>{{ guestList }}</span>
<button class="guestlist__button" #click="toggleGuestList">Guestlist</button>
<div v-if="isGuestListVisible === true">
<ul>
<li v-for="guest in people" :key="guest.id.value">
{{ guest.name.first }} {{ guest.name.last }}</li>
</ul>
</div>
</div>
</template>
export default {
props: {
titleName: {
type: String,
default: 'todolist',
},
},
data() {
return {
title: 'Planning the party!',
task: '',
tasks: [{
name: ''
}],
invited: 'Who is invited?',
guestList: '',
people: [],
name: '',
isGuestListVisible: false
}
},
created() {
this.addGuest();
},
methods: {
async addGuest() {
const url = 'https://randomuser.me/api/?page=2&results=8';
const res = await fetch(url);
const { results } = await res.json();
this.people = results;
},
toggleGuestList() {
this.isGuestListVisible = !this.isGuestListVisible;
},
addPlanningTask() {
if(this.task.length === 0)
return;
this.tasks.push({
name: this.task
});
},
deletePlanningTask(index) {
this.tasks.splice(index, 1);
},
},
};
</script>
You can use #submit.prevent on form if you don't want to reload page:
new Vue({
el: "#demo",
props: {
titleName: {
type: String,
default: 'todolist',
},
},
data() {
return {
title: 'Planning the party!',
task: '',
tasks: [],
invited: 'Who is invited?',
guestList: '',
people: [],
name: '',
isGuestListVisible: false
}
},
created() {
this.addGuest();
},
methods: {
async addGuest() {
const url = 'https://randomuser.me/api/?page=2&results=8';
const res = await fetch(url);
const { results } = await res.json();
this.people = results;
},
toggleGuestList() {
this.isGuestListVisible = !this.isGuestListVisible;
},
addPlanningTask() {
if (this.task.length === 0) return;
this.tasks.push({ name: this.task });
},
deletePlanningTask(index) {
this.tasks.splice(index, 1);
},
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo" >
<section class="todolist">
<h1 class="title">{{ title }}</h1>
<form class="container" #submit.prevent>
<h3 class="container__title">New Task </h3>
<input class="container__input" type="text" placeholder="Enter task" v-model="task">
<button class="container__button" #click="addPlanningTask">Add Task</button>
<h3 class="container__title-second">To Do List</h3>
<ul>
<li v-for="(task, index) in tasks" :key="index">
<span>{{ task.name }} </span>
<button class="todolist__button" #click="deletePlanningTask">Remove</button>
</li>
</ul>
<h4 class="container__list-title" v-if="task.length === 0">List is empty!</h4>
</form>
</section>
<div class="guestlist">
<h4 class="guestlist__title">{{ invited }}</h4>
<span>{{ guestList }}</span>
<button class="guestlist__button" #click="toggleGuestList">Guestlist</button>
<div v-if="isGuestListVisible === true">
<ul>
<li v-for="guest in people" :key="guest.id.value">
{{ guest.name.first }} {{ guest.name.last }}</li>
</ul>
</div>
</div>
</div>

Cannot get click in Vue.js to work the way I'd like

everyone, I am new to vuejs and vuetify and trying to make a book app but the problem is all the code is complete but when I click on the dropdown item it shows all the books item but I want to show only selected book item.
This is my HTML where I am stuck I am doing mistakes here this and I am failed many times cannot get my answer
<v-container fluid>
<v-row aign="center">
<v-col cols="12">
<v-toolbar-title>State Selection</v-toolbar-title>
<div v-on-clickaway="away" class="searchField dropdown">
<v-text-field
:label="labeling"
v-model="search"
#input="waitForSearch"
>
</v-text-field>
<!-- <div class="bookParent" v-for="item in items" :key="item.id"> -->
<!-- <img :src="item.volumeInfo.imageLinks.thumbnail" /> -->
<div
class="clickUpdateElement"
v-for="(item, index) in items"
:key="item.id"
>
<HelloWorld v-show="show">
<template v-slot:contentHandler class="option" id="option1">
<div
#click="clickCard(item, $event.target)"
class="containerForI"
>
<v-img>
<img :src="item.volumeInfo.imageLinks.thumbnail" />
</v-img>
<a class="anchorTag">{{ item.volumeInfo.title }}</a>
<!-- <span>{{ item.volumeInfo.author }}</span> -->
</div>
</template>
</HelloWorld>
<div class="content">
<Content v-show="show2" #load="updateCard(item, $event.target)">
<template v-slot:cardContent>
<v-card class="mx-auto" elevation="2" outlined shaped>
<v-list-item three-line>
<v-list-item-avatar>
<!-- <v-img :src="imageSrc"></v-img> -->
</v-list-item-avatar>
<v-list-item-content>
<v-card-title>
{{ item.volumeInfo.title }}
</v-card-title>
<v-card-subtitle>
{{ index }} {{ item.volumeInfo.description }}
</v-card-subtitle>
</v-list-item-content>
<v-card-actions>
<v-btn primary>Act</v-btn>
</v-card-actions>
</v-list-item>
</v-card>
</template>
</Content>
</div>
</div>
<v-btn #click="show2 = false">Remove</v-btn>
</div>
</v-col>
</v-row>
</v-container>
MY JS
import axios from "axios";
import { directive as onClickaway } from "vue-clickaway";
import HelloWorld from "../components/HelloWorld";
import Content from "../components/Content";
export default {
name: "Home",
directives: {
onClickaway: onClickaway,
},
data() {
return {
BASE_URL: "https://www.googleapis.com/books/v1/volumes",
items: [],
search: "",
timerId: "",
labeling: "Search For Book",
show: false,
show2: false,
imageSrc: "",
showTitle: "",
showDescription: "",
};
},
components: {
HelloWorld,
Content,
},
created() {},
computed: {},
//Fetch the required Information from Google Book Api
watch: {},
methods: {
async getBooks() {
this.show = true;
let response = await axios.get(`${this.BASE_URL}`, {
params: {
q: this.search,
apikey: "",
},
});
this.items = response.data.items;
console.log(this.items);
},
away() {
console.log("clicked away");
this.show = false;
},
clickCard(item, target) {
console.log(item);
console.log(target);
this.show = false;
this.show2 = true;
},
updateCard(item, target) {
console.log(item);
console.log(target);
},
//Method That Take and wait for the Input
waitForSearch() {
// this.search = "";
clearTimeout(this.timerId);
this.timerId = setTimeout(() => {
this.getBooks();
}, 1000);
},
},
Content.vue i just used slot nothing else
<div class="container">
<div class="row">
<slot name="cardContent"></slot>
</div>
</div>
HelloWorld.vue
html
<div class="menu pointerCursor hide">
<slot name="contentHandler"></slot>
</div>
I try many times but failed. Any leads, please?
What I would try is to keep a record of the index that I want to show.
So what you could do is the following:
1.Change the code calling ClickCard
<div #click="clickCard(item, index)" class="containerForI">
2.Assign the value of index to a component variable
clickCard(item, index) {
console.log(item);
this.indexToShow = index;
this.show = false;
this.show2 = true;
},
3.Initialize the aforementioned variable in your component
data() {
return {
BASE_URL: "https://www.googleapis.com/books/v1/volumes",
indexToShow: null,
...
4.Finally, check if the currently selected index is the one to show
<Content v-show="indexToShow === null || indexToShow === index"
If you want to show all items, after showing only 1, you will have to set indexToShow to null. The Content component is checking for it.

How to disabled v-slot for row in Table Bootstrap Vue

I writing bootstrap component for inline edititng in table
I noticed that slots have priority: cell(%cell%) above cell()
How can I turn off a v-slot:cell(%cell%) for a specific row in a table?
<b-table ...>
<template v-slot:cell()="data">
<b-input
v-if="data.item.editing && data.field.editable"
v-model="tableData[data.index][data.field.key]"
/>
<span v-else>{{data.value}}</span>
</template>
<template
v-for="(_, slot) of $scopedSlots"
v-slot:[slot]="scope"
>
<slot
name="cell()"
v-bind="scope"
/>
</template>
<b-table>
If I'm understanding correctly, you want to be able to have a slot to customize the layout when the field is not being editted.
For this you will have to create your own component, wrapping <b-table>, and create your own slot.
<template v-slot:cell()="data">
<b-input
v-if="data.item.editing && data.field.editable"
v-model="tableData[data.index][data.field.key]"
/>
<span v-else>
<slot :name="`noedit(${data.field.key})`" v-bind="data">
{{ data.value }}
</slot>
</span>
</template>
The above code, will then allow you to use the slot noedit(field_key) (you can change the slot name to whatever you want), to edit the layout when that field is not in an "editing" state.
Example
Vue.component("data-table", {
template: "#data-table",
computed: {
editableFields() {
return this.fields.filter((field) => field.editable);
}
},
data() {
return {
userRow: null
};
},
props: ["items", "fields"],
methods: {
editUser(user) {
let doEdit = true;
if (
this.userRow &&
!confirm("You have unsaved changes, are you sure you want to continue?")
) {
doEdit = false;
}
if (doEdit) {
this.userRow = { ...user };
}
},
saveEdit() {
let user = this.items.find((u) => u.id === this.userRow.id);
Object.assign(user, this.userRow);
this.resetEdit();
},
resetEdit() {
this.userRow = null;
}
}
});
new Vue({
el: "#app",
data() {
return {
fields: [
{ key: "id" },
{ key: "first_name", editable: true },
{ key: "last_name", editable: true },
{ key: "age", editable: true, type: "number", isNumber: true },
{ key: "actions" }
],
items: [
{ id: 1, first_name: "Mikkel", last_name: "Hansen", age: 56 },
{ id: 2, first_name: "Mads", last_name: "Mikkelsen", age: 39 },
{ id: 3, first_name: "Anders", last_name: "Matthesen", age: 42 }
]
};
}
});
<link href="https://unpkg.com/bootstrap#4.5.2/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue#2.16.0/dist/bootstrap-vue.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.16.0/dist/bootstrap-vue.js"></script>
<div id="app">
<data-table :items="items" :fields="fields">
<template v-slot:noedit(first_name)="{ value }">
<b class="text-primary">
{{ value }}
</b>
</template>
<template v-slot:cell(id)="{ value }">
<i class="text-danger">{{ value }}</i>
</template>
</data-table>
</div>
<template id="data-table">
<b-table :items="items" :fields="fields">
<template v-for="field in editableFields" v-slot:[`cell(${field.key})`]="s">
<b-input v-if="userRow && userRow.id === s.item.id" v-model="userRow[s.field.key]" :type="s.field.type || 'text'" :number="s.field.isNumber">
</b-input>
<template v-else>
<slot :name="`noedit(${s.field.key})`" v-bind="s">
{{ s.value }}
</slot>
</template>
</template>
<template v-slot:cell(actions)="{ item }">
<b-button-group v-if="userRow && userRow.id === item.id">
<b-btn variant="success" #click="saveEdit">
Save
</b-btn>
<b-btn variant="danger" #click="resetEdit">
Cancel
</b-btn>
</b-button-group>
<b-btn v-else variant="primary" #click="editUser(item)">
Edit
</b-btn>
</template>
<!-- Pass in slots from parent -->
<template v-for="name in Object.keys($scopedSlots)" v-slot:[name]="scope">
<slot :name="name" v-bind="scope"></slot>
</template>
</b-table>
</template>

vuejs2 el-table-column column prop with computed value

I'm new in vuejs. I don't see how to use a "computed" value in a table of the ui-element librairy. Here is how I tried ..
<template>
<div class="row">
<div class="col-md-12">
<h4 class="title">Commandes en cours</h4>
</div>
<!--<div v-if="$can('manage-order')">You can manage order.</div>-->
<div class="col-12">
<card title="">
<div>
<div class="col-12 d-flex justify-content-center justify-content-sm-between flex-wrap">
<el-select
class="select-default mb-3"
style="width: 200px"
v-model="pagination.perPage"
placeholder="Per page">
<el-option
class="select-default"
v-for="item in pagination.perPageOptions"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
<el-input type="search"
class="mb-3"
style="width: 200px"
placeholder="Search records"
v-model="searchQuery"
aria-controls="datatables"/>
</div>
<div class="col-sm-12">
<el-table stripe
style="width: 100%;"
:data="queriedData"
border>
<el-table-column v-for="column in tableColumns"
:key="column.label"
:min-width="column.minWidth"
:prop="column.prop"
:label="column.label">
</el-table-column>
<el-table-column
:min-width="120"
fixed="right"
label="Actions">
<template slot-scope="props">
<a v-tooltip.top-center="'Like'" class="btn-info btn-simple btn-link"
#click="handleLike(props.$index, props.row)">
<i class="fa fa-heart"></i></a>
<a v-tooltip.top-center="'Edit'" class="btn-warning btn-simple btn-link"
#click="handleEdit(props.$index, props.row)"><i
class="fa fa-edit"></i></a>
<a v-tooltip.top-center="'Delete'" class="btn-danger btn-simple btn-link"
#click="handleDelete(props.$index, props.row)"><i class="fa fa-times"></i></a>
</template>
</el-table-column>
</el-table>
</div>
</div>
<div slot="footer" class="col-12 d-flex justify-content-center justify-content-sm-between flex-wrap">
<div class="">
<p class="card-category">Showing {{from + 1}} to {{to}} of {{total}} entries</p>
</div>
<l-pagination class="pagination-no-border"
v-model="pagination.currentPage"
:per-page="pagination.perPage"
:total="pagination.total">
</l-pagination>
</div>
</card>
</div>
</div>
</template>
<script>
import {Table, TableColumn, Select, Option} from 'element-ui'
import LPagination from 'src/components/Pagination.vue'
import Fuse from 'fuse.js'
export default {
components: {
LPagination,
[Table.name]: Table,
[Select.name]: Select,
[Option.name]: Option,
[TableColumn.name]: TableColumn
},
computed: {
clientName(customer){
return customer.firstname + ' '+ customer.lastname
},
pagedData () {
return this.tableData.slice(this.from, this.to)
},
/***
* Searches through table data and returns a paginated array.
* Note that this should not be used for table with a lot of data as it might be slow!
* Do the search and the pagination on the server and display the data retrieved from server instead.
* #returns {computed.pagedData}
*/
queriedData () {
let result = this.tableData
if (this.searchQuery !== '') {
result = this.fuseSearch.search(this.searchQuery)
this.pagination.total = result.length
}
return result.slice(this.from, this.to)
},
to () {
let highBound = this.from + this.pagination.perPage
if (this.total < highBound) {
highBound = this.total
}
return highBound
},
from () {
return this.pagination.perPage * (this.pagination.currentPage - 1)
},
total () {
this.pagination.total = this.tableData.length
return this.tableData.length
}
},
data () {
return {
pagination: {
perPage: 5,
currentPage: 1,
perPageOptions: [5, 10, 25, 50],
total: 0
},
searchQuery: '',
propsToSearch: ['id_order'],
tableColumns: [
{
prop: 'id_order',
label: 'ID',
minWidth: 200
},
{
prop: "clientName(customer)",
label: 'Client',
minWidth: 200,
}
],
fuseSearch: null,
tableData:[]
}
},
methods: {
handleLike (index, row) {
alert(`Your want to like ${row.name}`)
},
handleEdit (index, row) {
alert(`Your want to edit ${row.name}`)
},
handleDelete (index, row) {
let indexToDelete = this.tableData.findIndex((tableRow) => tableRow.id === row.id)
if (indexToDelete >= 0) {
this.tableData.splice(indexToDelete, 1)
}
}
},
mounted () {
this.fuseSearch = new Fuse(this.tableData, {keys: ['id_order']})
},
created (){
this.$store.dispatch('ps_orders/get_ps_orders').then(
this.tableData = this.$store.getters["ps_orders/orders"])
}
}
</script>
<style>
</style>
My object is like (for a row)
{
"id_order": 4641,
"customer": {
"id_customer": 9008,
"firstname": "Pierre",
"lastname": "dupont"
}
}
In the column "Client" I would like to have "customer.firstname + " " + customer.lastname ... but my computed "method" is not working (I guess it is completly wrong)
Thanks for your help
Here the answer : you can't declare a computed with a parameter, here is how to solve
<el-table-column
label="Client" >
<template slot-scope="scope">
{{ clientName(scope.row.customer) }}
</template>
</el-table-column>
AND
computed: {
clientName(){
return (customer) => customer.firstname + ' '+ customer.lastname
},