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
},
Related
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>
I have a const array of objects which set to the data property on created(), I am trying to update the object properties as the user entered the form, the Console print shows the value updated, but the DOM is changing. DOM is updated when the key value is changed too but I do not want to change the key value
Data Array:
const invoices = [
{
number: "BBRFL",
client: "Ellison Daugherty",
amount: 8800,
status: "Paid",
},
{
number: "TYUBK",
client: "Myrna Vinson",
amount: 4097,
status: "Paid",
},
{
number: "IRUBR",
client: "Mcmillan Warner",
amount: 6466,
status: "Draft",
},
];
Here is the app.
const app = new Vue({
el: "#app",
components: {
"create-invoice": CreateInvoice,
"invoice-item": InvoiceItem,
},
data() {
return {
invoices: invoices,
status: null,
};
},
created: function () {
const invoices = localStorage.getItem("invoices");
if (invoices) {
this.invoices = JSON.parse(invoices);
}
},
computed: {
count: function () {
return this.filteredInvoices.length;
},
filteredInvoices: function () {
if (this.status) {
return this.invoices.filter((invoice) => invoice.status == this.status);
}
return this.invoices;
},
},
methods: {
saveInvoice(invoice) {
this.invoices.push(invoice);
},
invoiceUpdate(invoice) {
const index = this.invoices.findIndex((i) => i.number === invoice.number);
// this.invoices.splice(index, 1, invoice);
Vue.set(this.invoices[index], "client", invoice.client);
Vue.set(this.invoices[index], "amount", invoice.amount);
Vue.set(this.invoices[index], "status", invoice.status);
},
invoiceDelete(number) {
const index = this.invoices.findIndex((i) => i.number === number);
this.invoices.splice(index, 1);
},
},
watch: {
invoices: {
deep: true,
handler: function (invoices) {
localStorage.setItem("invoices", JSON.stringify(invoices));
},
},
},
template: `
<div>
<div class="row">
<div class="col-md-4 text-left">
<h1>Invoices</h1>
<p class="text-dark">There are {{count}} Total Invoices</p>
</div>
<div class="col-md-4 text-start" style="margin-top: 10px">
<label for="status">Filter</label>
<select name="filter" id="status" class="form-control" v-model="status">
<option value="Draft">Draft</option>
<option value="Paid">Paid</option>
<option value="Pending">Pending</option>
</select>
</div>
<div class="col-md-4 text-right" style="margin-top: 10px">
<button class="btn btn-primary mt-4" id="createInvoice">
New Invoice
</button>
</div>
</div>
<div class="col-md-12">
<div class="row mt-2 mb-2">
<div
class="invoice col-md-12"
>
<invoice-item
v-for="(n, index) in filteredInvoices"
:key="n.number"
:initial-client="n.client"
:initial-number="n.number"
:initial-amount="n.amount"
:initial-status="n.status"
#update-invoice="invoiceUpdate"
#delete-invoice="invoiceDelete"
></invoice-item>
</div>
<div class="text-center" v-if="filteredInvoices.length === 0"><p>No invoice found</p></div>
</div>
</div>
<create-invoice #saveInvoice="saveInvoice" ></create-invoice>
</div>
</div>
`,
});
I had tried, this.$set, Vue.set, Direct assigning to property, assingment using splice function, but none of working. It only works with the change of value of key in for loop. Which I do not want to update.
Jsfiddle
Any Help? Thanks in advance.
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>
I have three components. All of them bind a value.
Below is the blade file with the three components
Blade File:
<div id="app">
<div class="row">
<div class="col-4">
<crud-component :type="'tower'"></crud-component>
</div>
<div class="col-4">
<crud-component :type="'country'"></crud-component>
</div>
<div class="col-4">
<crud-component :type="'department'"></crud-component>
</div>
</div>
</div>
All of these components are dynamic, they only rely on that binded value called :type
The Vue file:
<template>
<div>
<h3>{{capitalize(type)}} <button class="btn btn-primary btn-sm" #click="showAddModal()">Add</button></h3>
<datatable :columns="columns" :sortKey="sortKey" :sortOrders="sortOrders">
<tbody v-if="loading">
<tr>
<td colspan="11"><div class="lds-dual-ring mx-auto"></div></td>
</tr>
</tbody>
<tbody v-else>
<tr v-for="data in retData" :key="data.id">
<td> {{data.id}}</td>
<td> {{data.name}}</td>
<td>
<button class="btn btn-warning btn-sm" #click="showEditModal(data)"> Edit </button>
<button class="btn btn-danger btn-sm" #click="showDeleteModal(data)"> Delete </button>
</td>
</tr>
</tbody>
</datatable>
<!-- MODALS -->
<modal :name="type + '-add-modal'" height="auto">
<div class="row p-3">
<div class="col-12">
<h3>Add {{capitalize(type)}}</h3>
<hr>
<form>
<div class="form-group">
<label for="add-item">{{capitalize(type)}} Name</label>
<input v-validate="'required'" type="text" name="item-name" class="form-control" id="add-item-name" required>
<small class="form-text text-danger">{{errors.first('item-name')}}</small>
</div>
<button type="button" class="float-right btn btn-sm btn-primary" #click="store">Submit</button>
</form>
</div>
</div>
</modal>
<modal :name="type + '-edit-modal'" height="auto">
<div class="row p-3">
<div class="col-12">
<h3>Edit {{capitalize(type)}}</h3>
<hr>
<form>
<div class="form-group">
<label for="edit-item">{{capitalize(type)}} Name</label>
<input v-validate="'required'" name="item-name" type="text" class="form-control" id="edit-item-name" v-model="currentItem.name" required>
<small class="form-text text-danger">{{errors.first('item-name')}}</small>
</div>
<button type="button" class="float-right btn btn-sm btn-primary" #click="store">Submit</button>
</form>
</div>
</div>
</modal>
<modal :name="type + '-delete-modal'" height="auto">
<div class="row p-3">
<div class="col-12">
<h3>Delete {{capitalize(type)}}</h3>
<hr>
<p class="lead">Are you sure you want to delete <strong>{{currentItem.name}}</strong>?</p>
<button type="button" class="float-right btn btn-sm btn-primary" #click="destroy">Submit</button>
</div>
</div>
</modal>
</div>
</template>
<script>
import Datatable from './utilities/DatatableComponent.vue';
import Pagination from './utilities/PaginationComponent.vue';
export default {
components: {
'datatable': Datatable,
'pagination': Pagination,
},
props: ['type'],
mounted() {
this.get(this.type);
},
data() {
let sortOrders = {};
let columns = [
{label: 'ID', name:'id', isSortable: true},
{label: 'NAME', name:'name', isSortable: true},
{label: 'ACTIONS', name:'actions', isSortable: false}
];
columns.forEach(column => {
sortOrders[column.name] = -1;
});
return {
loading: true,
currentItem: '',
isUpdate: false,
sortKey: 'id',
columns: columns,
sortOrders: sortOrders,
tableData: {
draw: 0,
length: 10,
search: '',
column: 'id',
dir: 'desc',
},
pagination: {
lastPage: '',
currentPage: '',
total: '',
lastPageUrl: '',
prevPageUrl: '',
nextPageUrl: '',
from: '',
to: '',
},
retData: []
};
},
methods: {
showEditModal(item) {
this.currentItem = item;
this.$modal.show(this.type + '-edit-modal');
this.isUpdate = true;
},
showAddModal() {
this.$modal.show(this.type + '-add-modal');
},
store() {
this.$validator.validate().then(valid => {
if(!valid) {
return;
} else {
if(this.isUpdate == true) {
axios.post('/api/crud/store', {
type: this.type,
item: this.currentItem,
isUpdate: this.isUpdate
}).then(response => {
this.get(this.type);
this.$modal.hide(this.type + '-edit-modal');
this.isUpdate = false;
this.currentItem = '';
});
} else {
axios.post('/api/crud/store', {
type: this.type,
name: $('#add-item-name').val(),
isUpdate: this.isUpdate
}).then(response => {
this.get(this.type);
this.$modal.hide(this.type + '-add-modal');
});
}
}
});
},
showDeleteModal(item) {
this.currentItem = item;
this.$modal.show(this.type + '-delete-modal');
},
destroy() {
axios.delete('/api/crud/delete', {
data: {
type: this.type,
item: this.currentItem
}
}).then(response => {
this.$modal.hide(this.type + '-delete-modal')
this.currentItem = '';
this.get(this.type)
});
},
capitalize(s) {
if (typeof s !== 'string') return ''
return s.charAt(0).toUpperCase() + s.slice(1)
},
get(type) {
axios.interceptors.request.use(config => {
NProgress.start();
this.loading = true;
return config;
});
axios.interceptors.response.use(response => {
NProgress.done();
this.loading = false;
return response;
});
this.tableData.draw++;
axios.post('/api/crud', {
type: type,
tableData: this.tableData
}).then(response => {
let data = response.data;
if(this.tableData.draw == data.draw) {
this.retData = data.data.data
}
console.log('Done');
});
},
}
}
</script>
<style>
.lds-dual-ring {
display: block;
width: 64px;
height: 64px;
}
.lds-dual-ring:after {
content: " ";
display: block;
width: 46px;
height: 46px;
margin: 5px;
border-radius: 50%;
border: 5px solid #000;
border-color: #000 transparent #000 transparent;
animation: lds-dual-ring 1.2s linear infinite;
}
#keyframes lds-dual-ring {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
The problem is, when I'm trying to update, fetch, or do anything with one component.
It runs all of the API calls to fetch their specific data.
I just want to have that one table load when it's fetching data.
As mentioned in my comment above, you are adding interceptors to your Axios instance every time any of your components calls its get method.
The interceptor code runs on every request / response made through Axios, no matter where it comes from. This is why all your components appear to be loading when a request is made.
I suggest you remove the interceptors and change your code to
get(type) {
NProgress.start()
this.loading = true
this.tableData.draw++
axios.post('/api/crud', {
type: type,
tableData: this.tableData
}).then(response => {
NProgress.done()
this.loading = false
let data = response.data;
if(this.tableData.draw == data.draw) {
this.retData = data.data.data
}
})
}
Data needs to be a function.
data () {
return {
...
}
}
You can't simply have a bunch of variables and also a function like you have. You need to refactor your component.
I am trying to make a form which contains an input group section, in this group, there are one select box and multiple checkboxes. Checkboxes are populated based on the select box selection. There is also an add and remove button to generate and remove input group. The select box is used with v-model to filtered the checkboxes. But when I generate a new input group and make changes, all checkboxes are changed.
I want them to be isolated. How can I achieve?
Here is my Template.
<template>
<form #submit.prevent="onSubmit">
<div v-for="(variationProduct, index) in variationProducts" :key="variationProduct.id">
<div class="from-group mb-4">
<label class="col-form-label"><b>Categories :</b></label>
<select class="form-control mr-2" ref="categories" v-model="category">
<option value="0">Please select category...</option>
<option v-for="category in categories" :key="category.id" :value="category.id">
{{ category.name }}
</option>
</select>
<div v-if="hasError">
<validation-errors v-if="errors['categories.'+index]" :errors="errors">
{{ errors['categories.'+index][0] }}
</validation-errors>
</div>
</div>
<div class="form-group mb-4">
<label class="col-form-lablel"><b>Variation Products :</b></label>
<div class="row">
<div v-for="filteredVariationProduct in filteredVariationProducts" :key="filteredVariationProduct.id">
<div class="col-12">
<input :id="filteredVariationProduct.id" :value="filteredVariationProduct.id" type="checkbox" ref="variationProducts">
<label :for="filteredVariationProduct.id">{{ filteredVariationProduct.name }}</label>
</div>
</div>
</div>
<div v-if="hasError">
<validation-errors v-if="errors['variationProducts.'+index]" :errors="errors">
{{ errors['variationProducts.'+index][0] }}
</validation-errors>
</div>
</div>
<div class="float-right">
<button #click.prevent="add" class="btn btn-success">Add</button>
<button #click.prevent="remove(index)" class="btn btn-danger">Remove</button>
</div>
<br>
<br>
<hr>
</div>
<input type="submit" class="btn btn-primary" value="Submit">
</form>
</template>
Here is my JS.
<script>
import ValidationErrors from './ValidationErrors.vue';
export default {
components: {
'validation-errors': ValidationErrors,
},
data () {
return {
variationProducts: [],
categories: [
{ id: 1, name: 'Technology'},
{ id: 2, name: 'Business'},
{ id: 3, name: 'Marketing'},
{ id: 4, name: 'Development'},
{ id: 5, name: 'Engineering'},
],
category: 0,
activeVariationProducts: [],
count: 1,
errors: {},
hasError: false,
}
},
methods: {
add: function() {
this.count++;
this.errors = {};
this.hasError = false;
this.variationProducts.push({ id: this.count });
},
remove: function (index) {
if ( this.variationProducts.length > 0 && index > -1) {
this.variationProducts.splice(index, 1);
} else {
alert('Must have at least one input!')
}
},
onSubmit: function() {
console.log(this.$refs.variationProducts.value);
},
generateVariationProducts: function(num) {
for(let i = 1; i <= num; i++) {
let activeVariationProduct = {
id: i,
name: 'Product '+ i,
category_id: i
};
this.activeVariationProducts.push(activeVariationProduct);
}
},
},
computed : {
filteredVariationProducts: function () {
let categoryId = parseInt(this.category);
if (categoryId !== 0) {
let filteredVariationProducts = this.activeVariationProducts.filter((variationProduct) => {
return variationProduct.category_id === categoryId;
});
return filteredVariationProducts;
} else {
let filteredVariationProducts = this.activeVariationProducts;
return filteredVariationProducts;
}
}
},
created () {
this.variationProducts.push({ id: this.count });
this.generateVariationProducts(10);
},
}
</script>
Here is a sample code. This code Shows how you can use multiple Checkboxes that is generated dynamically and how to make them isolated -
new Vue({
el : "#app",
data : {
Items : ["One", "Two", "Three"],
newCheckbox : "",
SelectedItems : {
'One' : "",
'Two' : "",
'Three' : "",
},
},
methods:{
add:function(){
Vue.set(this.SelectedItems, this.newCheckbox, false);
this.Items.push(this.newCheckbox);
},
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.22/vue.min.js" type="text/javascript"></script>
<div id="app">
<div>
<label v-for="(item, index) in Items">
<input type="checkbox" v-bind:key="index" v-model="SelectedItems[item]"> {{ item }}
</label>
</div>
<div>
<input type="text" v-model="newCheckbox">
<button #click="add">Add</button>
</div>
<div>
Output : {{ SelectedItems }}
</div>
</div>
You can dynamically add new checkbox and still they are isolated