Validating a non existent field error when trying to use vee-validate - vue.js

I am trying to make a multistep form. For that I made some Input, Dropdown Components.
FormInput.vue
<template>
<div class="field">
<label class="label has-text-left"
:for="fieldId">
{{ labelText }}
</label>
<div class="control">
<input
v-model="inputValue"
v-bind="$attrs"
class="input"
:id="fieldId"
#input="event => {$emit('input', event.target.value)}"
:class="{'is-danger': error,
'is-success': !error && instance && instance!==''}" >
</div>
<p class="help has-text-left danger"
v-show="error">
{{ error }}
</p>
</div>
</template>
<script>
export default {
name: 'FormInput',
props: {
labelText: String,
instance: [Number, String],
fieldId: String,
error: String
},
data () {
return {
inputValue: null
}
},
mounted () {
this.inputValue = this.instance
},
$_veeValidate: {
name () {
this.fieldId
},
value () {
this.instance
}
},
watch: {
instance: function(newValue) {
this.inputValue = newValue
}
}
}
</script>
I am using this FormInput components in many forms. Eg.
QuerySportsFitnessForm.vue
<div class="modal-form" v-if="step === 5">
<FormDropdown
v-if="form.standard !== 'dietician'"
labelText="What is the gender of the student??"
v-model="form.gender"
:options="genderArray"
:instance="form.gender"
ref="gender"></FormDropdown>
<FormInput
type="text"
labelText="Your locality"
v-model="form.location"
:instance="form.location"
fieldId="location"
v-validate="'required'"
name="location"
:error="errors.first('location')"
placeholder="eg.Heerapura"></FormInput>
<FormInput
type="textarea"
labelText="Your full address"
v-model="form.address"
:instance="form.address"
fieldId="address"
v-validate="'required|min:10'"
name="address"
:error="errors.first('address')"
placeholder="Enter your postal address"></FormInput>
<FormInput
type="textarea"
labelText="Anything else you would like to share with us?"
v-model="form.comment"
:instance="form.comment"
fieldId="comment"
placeholder="Comment here"></FormInput>
</div>
<script>
import axios from 'axios'
import FormInput from './FormInput'
import FormDropdown from './FormDropdown'
import FormCheckbox from './FormCheckbox'
export default {
components: {
FormDropdown,
FormInput,
FormCheckbox
},
name: 'QuerySportsFitnessForm',
props: {
},
data () {
return {
modalStatus: false,
step: 1,
progressValue: 0,
form: {
fees: 1000,
category: 'Sports and Fitness',
standard: '',
subjects: [],
level: '',
type_coaching: '',
travel: '',
number_of_student: '',
coaching_location: '',
days: '',
gender_preference: '',
location: '',
address: '',
name: '',
age: '',
contact: '',
email: '',
gender: '',
comment: ''
},
typeCoachingArray: [
{ value: "batch", text: "In a Batch"},
{ value: "1-on-1", text: "1-on-1 Sessions"},
{ value: "flexible", text: "Flexible to get best tutor"}
],
travelArray: [
{ value: "0-1", text: "0-1 Km"},
{ value: "0-3", text: "0-3 Km"},
{ value: "0-5", text: "0-5 Km"},
{ value: "more than 5", text: "More than 5 Km"}
],
coachingLocationArray: [
{ value: "at home", text: "At Home"},
{ value: "at tutor", text: "At Tutor's Location"},
{ value: "flexible", text: "Flexible to get best tutor"},
],
genderPreferenceArray: [
{ value: "male", text: "Male" },
{ value: "female", text: "Female" },
{ value: "none", text: "No preference" }
],
daysArray: [
{ value: "1", text: "1 day a week" },
{ value: "2", text: "2 days a week" },
{ value: "3", text: "3 days a week" },
{ value: "4", text: "4 days a week" },
{ value: "5", text: "5 days a week" },
{ value: "6", text: "6 days a week" },
{ value: "7", text: "7 days a week" }
],
levelArray: [
{ value: "beginner", text: "Beginner" },
{ value: "intermediate", text: "Intermediate" },
{ value: "advanced", text: "Advanced" }
],
genderArray: [
{ value: "male", text: "Male" },
{ value: "female", text: "Female" }
],
numberOfStudentArray: [
{ value: "One", text: "One" },
{ value: "Two", text: "Two" },
{ value: "Three", text: "Three" },
{ value: "More than Three", text: "More than Three" },
],
dieticianSubjects: [
"Weight Loss",
"Weight Gain",
"Health Condition",
"Sports Conditioning Diets"
],
martialArtsSubjects: [
"Karate",
"Taekwondo",
"Wing Chun",
],
trainerSubjects: [
"General Fitness",
"Intermediate Bodybuilding",
"Hardcore Bodybuilding"
],
yogaSubjects: [
"Power Yoga",
"Therapeutic Yoga",
"Yoga for Senior Citizen",
"Pregnancy Yoga",
"Yoga for Everyone"
]
}
},
mounted () {
this.form.standard = this.$route.params.standard
if (['dietician', 'trainer', 'yoga', 'martial-arts'].indexOf(this.form.standard) !== -1) {
this.step = 1
}
else {
this.step = 2
}
},
methods: {
modalToggle() {
this.modalStatus = !this.modalStatus
},
/*addToInstance method is corrosponding to checkbox component*/
addToInstance(e) {
if (this.form.subjects.indexOf(e) ===-1) {
this.form.subjects.push(e)
}
else {
this.form.subjects.splice(this.form.subjects.indexOf(e), 1)
}
},
prev() {
this.progressValue -= 25
this.step--;
},
next() {
if (this.step === 1) {
this.$validator.validate('subjects', this.form.subjects)
if (this.form.subjects.length!==0) {
this.step++
this.progressValue += 20
}
}
else if (this.step === 2) {
this.$refs.level.dropdownToggle()
this.$refs.genderPreference.dropdownToggle()
this.$refs.days.dropdownToggle()
if (['dietician', 'trainer', 'yoga', 'zumba'].indexOf(this.form.standard) === -1) {
if (this.form.level !== '' && this.form.days !== '') {
this.step++
this.progressValue += 20
}
}
else if (['dietician', 'trainer', 'yoga'].indexOf(this.form.standard) !== -1) {
if(this.form.gender_preference !== '' && this.form.days !== '') {
this.step++
this.progressValue +=20
}
}
else if (this.form.standard === 'zumba') {
if (this.form.days !== '') {
this.step++
this.progressValue += 20
}
}
}
else if (this.step === 3) {
if (this.form.standard !== 'dietician') {
this.$refs.typeCoaching.dropdownToggle()
}
if (['chess', 'skating', 'trainer', 'yoga', 'zumba'].indexOf(this.form.standard) !== -1 && this.form.type_coaching!=='batch') {
this.$refs.coachingLocation.dropdownToggle()
}
if (this.form.coaching_location !== 'at home') {
this.$refs.travel.dropdownToggle()
}
if (this.form.standard !== 'dietician') {
if (this.form.type_coaching !== '') {
if (['chess', 'skating', 'trainer', 'yoga', 'zumba'].indexOf(this.form.standard) !== -1) {
if (this.form.type_coaching !== 'batch' && this.form.coaching_location !=='') {
if (this.form.coaching_location !== 'at home' && this.form.travel !== '') {
this.step++
this.progressValue += 20
}
else if (this.form.coaching_location === 'at home' && this.form.travel === '') {
this.step++
this.progressValue += 20
}
}
else if (this.form.type_coaching === 'batch' && this.form.travel !== '') {
this.step++
this.progressValue += 20
}
}
else if (['chess', 'skating', 'trainer', 'yoga', 'zumba'].indexOf(this.form.standard) === -1) {
if (this.form.travel !== '') {
this.step++
this.progressValue += 20
}
}
}
}
else if (this.form.standard === 'dietician') {
if (this.form.coaching_location !== 'at home' && this.form.travel !== '') {
this.step++
this.progressValue += 20
}
else if (this.form.coaching_location === 'at home' && this.form.travel === '') {
this.step++
this.progressValue += 20
}
}
}
else if (this.step === 4) {
this.$validator.validate('name', this.form.name)
this.$validator.validate('contact', this.form.contact)
this.$validator.validate('email', this.form.email)
this.$validator.validate('age', this.form.age).then(() => {
if (this.errors.items.length === 0) {
this.step++
this.progressValue += 20
}
})
}
},
//Problem with this block I think
validateBeforeSubmit() {
this.$refs.gender.dropdownToggle()
this.$validator.validate('location', this.form.location)
this.$validator.validate('address', this.form.address)
if (this.form.standard === 'dietician') {
if (this.errors.items.length === 0) {
this.addQuery()
this.modalToggle()
}
}
else if (this.form.standard !== 'dietician') {
if (this.errors.items.length === 0 && this.form.gender !== '') {
this.addQuery()
this.modalToggle()
}
}
},
emptyCoachingLocation() {
this.form.coaching_location = ''
},
emptyTravel() {
this.form.travel = ''
},
addQuery() {
axios({
method: 'post',
url: 'http://127.0.0.1:8000/api/hobby-query/',
data: {
fees: this.form.fees,
category: this.form.category,
standard: this.form.standard,
subjects: this.form.subjects,
level: this.form.level,
type_coaching: this.form.type_coaching,
travel: this.form.travel,
number_of_student: this.form.number_of_student,
coaching_location: this.form.coaching_location,
days: parseInt(this.form.days),
gender_preference: this.form.gender_preference,
location: this.form.location,
address: this.form.address,
name: this.form.name,
age: parseInt(this.form.age),
contact: this.form.contact,
email: this.form.email,
student_gender: this.form.gender,
comment: this.form.comment
}
}).then(() => {
this.form.subjects = [],
this.form.level = '',
this.form.type_coaching = '',
this.form.travel = '',
this.form.number_of_student = '',
this.form.coaching_location = '',
this.form.days = '',
this.form.gender_preference = '',
this.form.location = '',
this.form.address = '',
this.form.name = '',
this.form.age = '',
this.form.contact = '',
this.form.email = '',
this.form.gender = '',
this.form.comment = ''
})
.catch((error) => {
console.log(error);
});
}
}
}
</script>
I only included one div for example. When I am click "next" button method next() works without any problem. When I click submit button it fires up validateBeforeSubmit() method. And I get this error 2 times in console of developer tools.
Uncaught (in promise) Error: [vee-validate] Validating a non-existent field: "". Use "attach()" first.
at createError (vee-validate.esm.js?00d1:297)
at Validator._handleFieldNotFound (vee-validate.esm.js?00d1:2282)
at Validator.validate (vee-validate.esm.js?00d1:1959)
at ScopedValidator.validate (vee-validate.esm.js?00d1:3276)
at VueComponent.validateBeforeSubmit (QuerySportsFitnessForm.vue?cb73:448)
at invoker (vue.esm.js?efeb:2027)
at HTMLButtonElement.fn._withTask.fn._withTask (vue.esm.js?efeb:1826)
createError # vee-validate.esm.js?00d1:297
_handleFieldNotFound # vee-validate.esm.js?00d1:2282
validate # vee-validate.esm.js?00d1:1959
validate # vee-validate.esm.js?00d1:3276
validateBeforeSubmit # QuerySportsFitnessForm.vue?cb73:448
invoker # vue.esm.js?efeb:2027
fn._withTask.fn._withTask # vue.esm.js?efeb:1826
I tried to give .then promise after validate method call also but it didn't changed anything. like this
validateBeforeSubmit() {
this.$refs.gender.dropdownToggle()
this.$validator.validate('location', this.form.location)
this.$validator.validate('address', this.form.address).then(() {
if (this.form.standard === 'dietician') {
if (this.errors.items.length === 0) {
this.addQuery()
this.modalToggle()
}
}
else if (this.form.standard !== 'dietician') {
if (this.errors.items.length === 0 && this.form.gender !== '') {
this.addQuery()
this.modalToggle()
}
}
})
}
What am i doing wrong, I am not able to figure it out myself

I think this issue is happening because either location or address is not present in html due to step === 5 condition and you still try to validate that part. You can put below condition to get rid of this error===>
if (this.$validator.fields.find({ name: 'location' })) {
this.$validator.validate('location');
}

The problem seems to be that the validation's value change listener on the input was getting fired when cleared the variable, which then tried to validate the input, but the input was no longer in the validator's field list because it was detached when it was hidden.
this.$validator.pause()
this.$nextTick(() => {
this.$validator.errors.clear()
this.$validator.fields.items.forEach(field => field.reset())
this.$validator.fields.items.forEach(field => this.errors.remove(field))
this.$validator.resume()
})
This code will solve the issue.

Related

Unable to validate a child component from a parent component

I have a selectbox component. I want to reused it in other components.I'm able to reused the selectbox component in other components by adding v-model directive on custom input component but unable to validate selectbox component from other components by using vuetify validation rules.
Test.vue
<v-form ref="form" class="mx-4" v-model="valid">
<Selectbox :name="ward_no" :validationRule="required()" v-model="test.ward_no"/>
<v-btn primary v-on:click="save" class="primary">Submit</v-btn>
export default {
data() {
return {
test: {
ward_no: ''
},
valid: false,
required(propertyType) {
return v => (v && v.length > 0) || `${propertyType} is required`;
},
};
}
Selectbox.vue
<select #change="$emit('input', $event.target.value)" >
<option
v-for="opt in options"
:key="opt.value"
:value="opt.value"
:selected="value === opt.value"
>
{{errorMessage}}
{{ opt.label || "No label" }}
</option>
</select>
export default {
props: {
label: {
type: String,
required: true
},
validationRule: {
type: String,
default: 'text',
validate: (val) => {
// we only cover these types in our input components.
return['requred'].indexOf(val) !== -1;
}
},
name: {
type: String
},
value: {
type: String,
required: true
}
},
data() {
return {
errorMessage: '',
option: "lorem",
options: [
{ label: "lorem", value: "lorem" },
{ label: "ipsum", value: "ipsum" }
]
};
},
methods:{
checkValidationRule(){
if(this.validationRule!="")
{
return this.validationRule.split('|').filter(function(item) {
return item();
})
// this.errorMessage!= ""?this.errorMessage + " | ":"";
}
},
required() {
this.errorMessage!= ""?this.errorMessage + " | ":"";
this.errorMessage += name+" is required";
},
}
};

Vue.js multiple search with checkboxes

I'm trying to create a search form with input text fields and checkboxes.
Right now I have the search working for text fields but I can't make it work for checkboxes.
I'm totally new with vue.js so probably I'm missing some basic stuff.
The problem is in the computed part in the last filter, with the categories checkboxes:
computed: {
filteredExperiences() {
return this.experiences.filter( item => {
return (
item.destination.toLowerCase().indexOf(this.searchDestinations.toLowerCase()) > -1
&& item.title.toLowerCase().indexOf(this.searchExperiences.toLowerCase()) > -1
&& item.categories.map(cat => cat.title.toLowerCase()).indexOf(this.checkedCategories.toLowerCase()) > -1
)
})
}
}
So searchDestinations and searchExperiences work fine but search by categories doesn't.
Any idea why? What am I doing wrong?
This is the full code:
var app = new Vue({
el: '#app',
data: {
destinations: [{
title: 'Madrid',
slug: 'madrid'
},
{
title: 'London',
slug: 'london'
},
{
title: 'Chicago',
slug: 'chicago'
},
{
title: 'Los Angeles',
slug: 'los-angeles'
}
],
categories: [{
title: 'Concerts',
slug: 'concerts'
},
{
title: 'Museums',
slug: 'museums'
},
{
title: 'Theaters',
slug: 'theaters'
},
{
title: 'Cinemas',
slug: 'cinemas'
}
],
experiences: [{
id: 1,
title: 'Bruce Springsteen Live Madrid',
destination: 'Madrid',
categories: ['concerts', 'theaters'],
duration: '2h'
},
{
id: 2,
title: 'Mulan 2 the movie',
destination: 'London',
categories: ['cinemas', 'theaters'],
duration: '2h'
},
{
id: 3,
title: 'British Museum',
destination: 'London',
categories: ['museums'],
duration: '3h'
}
],
checkedCategories: [],
searchDestinations: '',
searchExperiences: ''
},
computed: {
filteredExperiences() {
return this.experiences.filter(item => {
return (item.destination.toLowerCase().indexOf(this.searchDestinations.toLowerCase()) > -1 && item.title.toLowerCase().indexOf(this.searchExperiences.toLowerCase()) > -1)
})
}
}
});
Here is the codepen:
See the Pen
vue.js filtered multi-search by Javier (#oterox)
on CodePen.
the problem is here:
&& item.categories.map(cat => cat.title.toLowerCase()).indexOf(this.checkedCategories.toLowerCase()) > -1
like this it should work:
computed: {
filteredExperiences() {
return this.experiences.filter( item => {
if(item.destination.indexOf(this.searchDestinations) < 0) { return false }
if (item.title.indexOf(this.searchExperiences) < 0 ) { return false }
let matchedCats = item.categories.filter(cat => {
let hasCat = this.checkedCategories.findIndex(checkCat => cat.toLowerCase() === checkCat.toLowerCase());
return hasCat > -1;
})
if(this.checkedCategories.length > 0 && matchedCats.length < 1)
{
return false;
}
return true;
})
}
}

Vuejs2: Vue Tables 2 - Multiple Custom filters

I'm trying to use a Vue table 2 filter to filter data by date, unfortunately it is not wroking and I am not able to find the reason. Has anyone tried such multiple filters with Vue table 2?
I went through the documentation but cannot find a solution.
https://matanya.gitbook.io/vue-tables-2/custom-filters
Html code to filter the data by date
<div class="col-md-4">
<div class="form-group">
<label for="sel1">Start Date:</label>
<input type="text" class="form-control" #keyup="applyFilterSearchText(searchText)" v-model="searchText" placeholder="End date" />
</div>
</div>
import { Event } from "vue-tables-2";
import axios from "axios";
export default {
title: "HelloWorld",
props: {
msg: String
},
data() {
return {
letters: ["Filled", "Unfilled", "Expired"],
selectedLetter: "",
searchText: "",
columns: ["refNumber", "vacancyTitle", "sector", "startDate", "endDate", "vacancyStatus"],
//data: getdetails(),
options: {
headings: {
refNumber: "Ref",
vacancyTitle: "Title",
sector: "Sector",
startDate: "Start",
endDate: "End",
vacancyStatus: "Status"
},
customFilters: [
{
name: "alphabet",
callback: function(row, query) {
return row.vacancyStatus == query;
}
},
{
name: "datefilter",
callback: function(row, query) {
return row.startDate == query;
}
}
],
// filterAlgorithm: {
// textsearch(row, query) {
// return (row.title).includes(query);
// }
// },
sortable: ["startDate", "vacancyTitle","endDate"],
sortIcon: {
base: "fa",
is: "fa-sort",
up: "fa-sort-asc",
down: "fa-sort-desc"
},
texts: {
filter: "Search by text:"
}
},
tableData:[],
};
},
methods: {
applyFilter(event) {
this.selectedLetter = event.target.value;
Event.$emit("vue-tables.filter::alphabet", this.selectedLetter);
},
applyFilterSearchText() {
console.log(this.searchText,"heiiiiiiiiiiii");
Event.$emit("vue-tables.filter::datefilter", this.searchText);
},
getdetails(){
axios.get("https://localhost:44399/api/Vacancy")
.then((res) => {
console.log(res.data,"ressssssss");
this.tableData = res.data;
})
.catch(function(error) {
console.log("Error: ", error);
});
}
},
mounted() {
this.getdetails();
}
};
A potential solution to that is to sort the data before using it in your data-table. Start by creating a computed of your data but with all your potential filters in it and create data variables with "parameters" (sort direction, sort column...)
export default {
title: "HelloWorld",
props: {
msg: String
},
data () {
return {
yourData: [],
sortBy: 'name',
sortDir: 'asc',
filterSearch: ''
}
},
computed: {
filteredData () {
if (filterSearch != '') {
let _this = this;
return this.sortedData.filter(item => {
return item.name.toLowerCase().includes(_this.filterSearch.toLowerCase());
})
} else {
return this.sortedData;
}
},
sortedData() {
return this.yourData.sort((a, b) => {
let modifier = 1;
if (this.sortBy == "order") {
if (this.sortDir === 'asc') {
return a[this.sortBy] - b[this.sortBy]
} else if (this.sortDir === 'desc') {
return b[this.sortBy] - a[this.sortBy]
}
} else {
if (this.sortDir === 'desc') modifier = -1;
if (a[this.sortBy] < b[this.sortBy]) return -1 * modifier;
if (a[this.sortBy] > b[this.sortBy]) return modifier;
return 0;
}
});
}
}
}
With that you just have to replace the props value you use to pass data to your VueTables

Reset Vue Bootstrap Table

i am using vue-bootstrap4-table in my application i have a custom input though which i search and populate the data,now i need to build a feature in which their is a cross button inside the search field and on clicking on it it should reset the table to empty state here is my code
<template>
<auto-complete
#autocomplete-result-selected="setCustomer"
placeholder="Enter Customer name"
:selected="selectedCustomer"
:styles="{width: 'calc(100% - 10px)'}"
index="locations"
attribute="name"
>
<template slot-scope="{ hit }">
<span>
{{ hit.customer.company && hit.customer.company + ' - ' }}{{ hit.customer.fname }}
{{ hit.customer.lname }}
</span>
</template>
</auto-complete>
<i class="fas fa-times" #click="clearTable()" v-show="selectedCustomer"></i>
</div>
</div>
</template>
<script>
import http from "../../helpers/api.js";
import AutoComplete from "../autocomplete/Autocomplete";
import axios from "axios";
import VueBootstrap4Table from "vue-bootstrap4-table";
export default {
components: {
"auto-complete": AutoComplete,
VueBootstrap4Table
},
computed: {},
data() {
return {
value: "",
selectedCustomer: "",
selectedFirstName: "",
selectedLastName: "",
selectedFields: [
{ name: "Invoice", value: "invoices" },
{
name: "Estimate",
value: "workorder_estimates"
}
],
filters: [
{ is_checked: true, value: "invoices", name: "Invoice" },
{ is_checked: true, value: "workorder_estimates", name: "Estimate" }
],
selectedFilters: [],
estimateChecked: false,
invoiceChecked: false,
config: {
card_mode: false,
show_refresh_button: false,
show_reset_button: false,
global_search: {
placeholder: "Enter custom Search text",
visibility: false,
case_sensitive: false
},
pagination: true,
pagination_info: false,
per_page: 10,
rows_selectable: true,
server_mode: true,
preservePageOnDataChange: true,
selected_rows_info:true
},
classes: {},
rows: [],
columns: [
{
label: "TYPE",
name: "type"
},
{
label: "ID",
name: "distinction_id"
},
{
label: "CUSTOMER NAME",
name: "full_name"
},
{
label: "SERVICE DATE",
name: "service_date"
},
{
label: "ADDRESS",
name: "address1"
},
{
label: "CREATE DATE",
name: "created_at"
}
],
queryParams: {
sort: [],
filters: [],
global_search: "",
per_page: 10,
page: 1
},
selected_rows: [],
total_rows: 0
};
},
methods: {
onNameSearch() {
this.selectedFilters = ["invoices", "workorder_estimates"];
this.fetchData();
},
clearTable(){
this.rows=[];
console.log(this.config.selected_rows_info);
this.config.selected_rows_info=false;
},
onChangeQuery(queryParams) {
console.log(queryParams);
this.queryParams = queryParams;
this.fetchData();
},
onRowClick(payload) {
console.log(payload);
},
setCustomer(selectedResult) {
this.selectedCustomer = selectedResult.customer.company
? `${selectedResult.customer.company + " - "}${
selectedResult.customer.fname
} ${selectedResult.customer.lname}`
: `${selectedResult.customer.fname} ${selectedResult.customer.lname}`;
this.selectedFirstName = selectedResult.customer.fname;
this.selectedLastName = selectedResult.customer.lname;
},
changeCheck(event, index, value) {
var checked = event.target.checked;
switch (value) {
case "invoices":
if (checked) {
this.selectedFields.push({ name: "Invoice", value: "invoices" });
this.invoiceChecked = true;
var data = this.filters[index];
data.is_checked = true;
Vue.set(this.filters, data, index);
} else {
var index = this.selectedFields.findIndex(
item => item.value === value
);
this.selectedFields.splice(index, 1);
this.invoiceChecked = false;
var data = this.filters[index];
data.is_checked = false;
Vue.set(this.filters, data, index);
}
break;
case "workorder_estimates":
if (checked) {
this.selectedFields.push({
name: "Estimate",
value: "workorder_estimates"
});
var data = this.filters[index];
data.is_checked = true;
Vue.set(this.filters, data, index);
} else {
var index = this.selectedFields.findIndex(
item => item.value === value
);
this.selectedFields.splice(index, 1);
this.estimateChecked = false;
var data = this.filters[index];
data.is_checked = false;
Vue.set(this.filters, data, index);
}
break;
}
},
removeFilter(index, value) {
switch (value) {
case "workorder_estimates":
this.selectedFields.splice(index, 1);
this.estimateChecked = false;
var i = this.filters.findIndex(item => item.value === value);
var data = this.filters[i];
data.is_checked = false;
Vue.set(this.filters, data, i);
break;
case "invoices":
this.selectedFields.splice(index, 1);
this.invoiceChecked = false;
var i = this.filters.findIndex(item => item.value === value);
var data = this.filters[i];
data.is_checked = false;
Vue.set(this.filters, data, i);
break;
}
},
updateFilters() {
this.selectedFilters = [];
this.selectedFields.forEach(element => {
this.selectedFilters.push(element.value);
});
if(this.selectedFilters.length == 0){
this.selectedFilters = ['invoices', 'workorder_estimates'];
}
this.fetchData();
},
async fetchData() {
var final = [];
try {
var result = await http.post("/estimate-invoice-search", {
type: this.selectedFilters,
search: {
value: this.selectedFirstName + " " + this.selectedLastName
},
per_page: this.queryParams.per_page,
page: this.queryParams.page,
sort: this.queryParams.sort
});
this.total_rows = result.recordsFiltered;
result.data.forEach(element => {
element.full_name = element.first_name + " " + element.last_name;
final.push(element);
});
this.rows = final;
} catch (error) {
console.log(error);
}
}
},
mounted() {}
};
</script>
now the method named clearTable here i want to reset my table to the point lie we see on page refresh in the method i used this.rows=[]; this clears all the rows which is exactly what i want but the text which shows the number of rows is still their and i cant seem to remove it please view the below image for clarification
i read the documentation on link but cant seem to find a solution for hiding the text, is their any way?
It looks like you're using total_rows as the variable for the number of rows in your template here:
<span>{{total_rows}}</span> Result(s)
The only spot in code that you set this value is in fetchData() where you set:
this.total_rows = result.recordsFiltered;
You can either:
1) Make total_rows a computed property (recommended) that returns the length of rows (I believe rows is always the same length as total_rows from your code)
-or-
2) Just set this.total_rows = 0; in your clearTable() function

Remove category_id property from ColumnValue object in Vue template

I want to remove category_id from {{ columnValue }}, but what is the best way to to that, because i need category_id in the first part ?
<table>
<tr>
<td v-for="columnValue, column in record">
<template v-if="editing.id === record.id && isUpdatable(column)">
<template v-if="columnValue === record.category_id">
<select class="form-control" v-model="editing.form[column]">
<option v-for="column in response.joins">
{{ column.category }} {{ column.id }}
</option>
</select>
</template>
<template v-else="">
<div class="form-group">
<input class="form-control" type="text" v-model= "editing.form[column]">
<span class="helper-block" v-if="editing.errors[column]">
<strong>{{ editing.errors[column][0]}}</strong>
</span>
</div>
</template>
</template>
<template v-else="">
{{ columnValue }} // REMOVE category_id here!
</template>
</td>
</tr>
</table>
And the view (its the number under group i want to remove):
The DataTable view
The script:
<script>
import queryString from 'query-string'
export default {
props: ['endpoint'],
data () {
return {
response: {
table: null,
columntype: [],
records: [],
joins: [],
displayable: [],
updatable: [],
allow: {},
},
sort: {
key: 'id',
order: 'asc'
},
limit: 50,
quickSearchQuery : '',
editing: {
id: null,
form: {},
errors: []
},
search: {
value: '',
operator: 'equals',
column: 'id'
},
creating: {
active: false,
form: {},
errors: []
},
selected: []
}
},
filters: {
removeCategoryId: function (value) {
if (!value) return ''
delete value.category_id
return value
}
},
computed: {
filteredRecords () {
let data = this.response.records
data = data.filter((row) => {
return Object.keys(row).some((key) => {
return String(row[key]).toLowerCase().indexOf(this.quickSearchQuery.toLowerCase()) > -1
})
})
if (this.sort.key) {
data = _.orderBy(data, (i) => {
let value = i[this.sort.key]
if (!isNaN(parseFloat(value)) && isFinite(value)) {
return parseFloat(value)
}
return String(i[this.sort.key]).toLowerCase()
}, this.sort.order)
}
return data
},
canSelectItems () {
return this.filteredRecords.length <=500
}
},
methods: {
getRecords () {
return axios.get(`${this.endpoint}?${this.getQueryParameters()}`).then((response) => {
this.response = response.data.data
})
},
getQueryParameters () {
return queryString.stringify({
limit: this.limit,
...this.search
})
},
sortBy (column){
this.sort.key = column
this.sort.order = this.sort.order == 'asc' ? 'desc' : 'asc'
},
edit (record) {
this.editing.errors = []
this.editing.id = record.id
this.editing.form = _.pick(record, this.response.updatable)
},
isUpdatable (column) {
return this.response.updatable.includes(column)
},
toggleSelectAll () {
if (this.selected.length > 0) {
this.selected = []
return
}
this.selected = _.map(this.filteredRecords, 'id')
},
update () {
axios.patch(`${this.endpoint}/${this.editing.id}`, this.editing.form).then(() => {
this.getRecords().then(() => {
this.editing.id = null
this.editing.form = {}
})
}).catch((error) => {
if (error.response.status === 422) {
this.editing.errors = error.response.data.errors
}
})
},
store () {
axios.post(`${this.endpoint}`, this.creating.form).then(() => {
this.getRecords().then(() => {
this.creating.active = false
this.creating.form = {}
this.creating.errors = []
})
}).catch((error) => {
if (error.response.status === 422) {
this.creating.errors = error.response.data.errors
}
})
},
destroy (record) {
if (!window.confirm(`Are you sure you want to delete this?`)) {
return
}
axios.delete(`${this.endpoint}/${record}`).then(() => {
this.selected = []
this.getRecords()
})
}
},
mounted () {
this.getRecords()
},
}
</script>
And here is the json:
records: [
{
id: 5,
name: "Svineskank",
price: "67.86",
category_id: 1,
category: "Flæskekød",
visible: 1,
created_at: "2017-09-25 23:17:23"
},
{
id: 56,
name: "Brisler vv",
price: "180.91",
category_id: 3,
category: "Kalvekød",
visible: 0,
created_at: "2017-09-25 23:17:23"
},
{
id: 185,
name: "Mexico griller 500 gram",
price: "35.64",
category_id: 8,
category: "Pølser",
visible: 0,
created_at: "2017-09-25 23:17:23"
},
{
id: 188,
name: "Leverpostej 250 gr.",
price: "14.25",
category_id: 9,
category: "Pålæg",
visible: 1,
created_at: "2017-09-25 23:17:23"
},
}]
.. and so on......
I would recommend using a filter in Vue to remove the property, such as:
new Vue({
// ...
filters: {
removeCategoryId: function (value) {
if (!value) return ''
delete value.category_id
return value
}
}
})
An then use this in your template:
{{ columnValue | removeCategoryId }}
Update: I misunderstood the scope of the loop. This works, and I verified on jsfiddle: https://jsfiddle.net/spLxew15/1/
<td v-for="columnValue, column in record" v-if="column != 'category_id'">