Remove category_id property from ColumnValue object in Vue template - vue.js

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'">

Related

Watch triggers only once - vue3

Vue3 newbie here. I am trying to toggle a string value, but watch triggers only once.
<template>
<div>
...
<table>
<thead>
...
<th>
<div className="create-date-label">
<p>Create Date</p>
<i
#click="toggleSortDate"
:className="
sortDirection === SORT_DIRECTIONS.DESCENDING
? 'fa fa-arrow-down'
: 'fa fa-arrow-up'
"
/>
</div>
</th>
...
</div>
</template>
<script>
import Navbar from "../components/Navbar.vue";
import ConfigurationRow from "../components/ConfigurationRow.vue";
const SORT_DIRECTIONS = Object.freeze({
ASCENDING: "ASCENDING",
DESCENDING: "DESCENDING",
});
export default {
name: "Home",
components: {
Navbar,
ConfigurationRow,
},
data() {
return {
configurations: [],
SORT_DIRECTIONS,
sortDirection: '',
};
},
methods: {
toggleSortDate() {
if (this.sortDirection === this.SORT_DIRECTIONS.ASCENDING)
this.sortDirection = this.SORT_DIRECTIONS.DESCENDING;
if (this.sortDirection === this.SORT_DIRECTIONS.DESCENDING)
this.sortDirection = this.SORT_DIRECTIONS.ASCENDING;
},
},
watch: {
sortDirection: function (newDirection) {
console.log("watch sort direction", newDirection); //Prints ASCENDING once
if (newDirection === this.SORT_DIRECTIONS.ASCENDING)
this.configurations = this.configurations.sort(
(a, b) => a.date.getTime() - b.date.getTime()
);
else if (newDirection === this.SORT_DIRECTIONS.DESCENDING)
this.configurations = this.configurations.sort(
(a, b) => b.date.getTime() - a.date.getTime()
);
},
deep: true, //Tried with removing this too, same result
},
created() {
this.configurations = [
{
key: "some_key",
value: "1.4.5.21",
description: "This is a kind of a long description",
date: new Date(),
},
{
key: "another_key",
value: "1.2",
description: "Desc",
date: new Date(),
},
{
key: "min_value",
value: "13",
description:
"This is a kind of a long description This is a kind of a long description This is a kind of a long description ",
date: new Date(),
},
].sort((a, b) => a.date.getTime() - b.date.getTime());
this.sortDirection = this.SORT_DIRECTIONS.DESCENDING;
},
};
</script>
I am using vue3 but do I have to use ref or reactive to achieve this? Anybody have an idea on how this triggers once but not again?
Try this:
toggleSortDate() {
if (this.sortDirection === this.SORT_DIRECTIONS.ASCENDING)
this.sortDirection = this.SORT_DIRECTIONS.DESCENDING;
else if (this.sortDirection === this.SORT_DIRECTIONS.DESCENDING)
this.sortDirection = this.SORT_DIRECTIONS.ASCENDING;
},

Pass API into an array

I am trying to pass the data from methods into my empty array rows ,how i can easly pass it or how to call the API into rows
export default {
data () {
return {
data: {
headers: [
{ title: 'id', key: 'id' },
{ title: 'name', key: 'name' },
{ title: 'city', key: 'city' },
{ title: 'address', key: 'address' }
],
rows: []
}
}
},
components: {
BaseTable
},
methods: {
fetchUsers () {
this.$axios.get('https://605c40b36d85de00170d9a8f.mockapi.io/user/zurich')
.then(({ data }) => {
this.tableData = data
console.log(data)
})
}
}
}
When the response from your api arrives, you just have to add to your property declared in the method data.
new Vue({
el: "#app",
data() {
return {
row: []
}
},
methods: {
fetching() {
fetch('https://rickandmortyapi.com/api/character')
.then(res => res.json())
.then(res => {
console.log(res);
this.row = res.results; //Results added into array
})
.catch(err => console.error(err))
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="fetching">Fetch Api</button>
<div v-for="(item, key) in row" :key="key" style="margin: 2rem auto;" >
<p>- {{ item.id }} | {{ item.name }} | {{ item.status }}</p>
</div>
</div>

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

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

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.

Change table values on change with Vue

I want to change table values when a user selects a value from the dropdown menu. By default, the values are in Metric. If a user selects Standard then I want to run some math on each value and to convert metric to standard. Also being able to switch back to Metric.
https://jsfiddle.net/tmun9cxa/13/
html
<div class="form-filter">
<select name="type" v-model="filter_unit" v-on:change="onSelectUnitChange">
<option value="metric">Metric</option>
<option value="standard">Standard</option>
</select>
</div><!-- /filter -->
<table style="text-align: center;">
<thead>
<tr>
<th v-for="column in columns">
<a
href="#"
v-on:click="sort(column.shortcode)">{{column.label}}
</a>
</th>
</tr>
</thead>
<tbody>
<tr v-for="(product) in showProducts">
<td>{{product.pn}}</td>
<td>{{product.od}}</td>
<td>{{product.id}}</td>
<td>{{product.thickness}}</td>
<td>{{product.lo}}</td>
<td>{{product.weight}}</td>
</tr>
</tbody>
</table>
</div><!-- /app -->
Javascript
var vm = new Vue({
el: '#app',
data: {
currentSort: 'pn',
currentSortDir: 'asc',
category: 'all',
filter_unit: 'metric',
search: '',
columns: [
{ label: 'P/N', shortcode: 'pn' },
{ label: 'OD (De,mm)', shortcode: 'od' },
{ label: 'ID (De,mm)', shortcode: 'id' },
{ label: 'Thickness (De,mm)', shortcode: 'thickness' },
{ label: 'LO', shortcode: 'lo' },
{ label: 'Weight (kg/1000)', shortcode: 'weight' },
], // columns
products: [
{
pn: 170158,
od: 13,
id: .44,
thickness: 1,
lo: .45,
weight: .7,
category: 'chrome',
},{
pn: 1803561,
od: 12,
id: .8,
thickness: .7,
lo: .11,
weight: .5,
category: 'chrome',
},{
pn: 170149,
od: 9,
id: .64,
thickness: .6,
lo: .75,
weight: .3,
category: 'stainless',
},{
pn: 150149,
od: 15,
id: .22,
thickness: .3,
lo: .55,
weight: .9,
category: 'chrome',
},
], // products
},
computed: {
showProducts(){
return this.products
.filter(a => {
return (a.pn + '').includes(this.search)
})
.sort((a, b) => {
if (this.currentSortDir === 'asc') {
//console.log( this.currentSort );
return a[this.currentSort] >= b[this.currentSort];
}
return a[this.currentSort] <= b[this.currentSort];
})
}
},
methods: {
sort:function(col) {
// if you click the same label twice
if(this.currentSort == col){
// sort by asc
this.currentSortDir = this.currentSortDir === 'asc' ? 'desc' : 'asc';
}else{
this.currentSort = col;
}
}, // sort
onSelectUnitChange:function(){
if(this.filter_unit == 'standard'){
// change values of OD using this equation. current OD value * 0.0393701
// change table header OD(De,mm) to OD(De,in)
// also will be doing a similar process to ID and Thickness
console.log('standard change');
}
},
}, // methods
}); // vue
You may add the logic on your computed property and check the v-model of the dropdown. I've updated your sample see https://jsfiddle.net/tmun9cxa/74
With my example I didn't change your existing computed but you can simply add your logic to that
filteredProducts() {
let filteredProducts = []
let _product
this.showProducts.forEach(product => {
_product = product
// do the logic here
if (this.filter_unit === 'metric') {
_product.displayWeight = _product.weight * 25
} else if (this.filter_unit === 'standard') {
_product.displayWeight = _product.weight + 10
}
filteredProducts.push(_product)
})
return filteredProducts
}
Update:
Another option is to use Vue filters. I've updated your example using filters http://jsfiddle.net/eywraw8t/274069
filters: {
convertOd(val, type) {
if (type === 'metric') {
return val * 0.0393701
} else if (type === 'imperial') {
return val
}
}
}
or
Vue.filter('convertOd', function (val, type) {
if (type === 'metric') {
return val * 0.0393701
} else if (type === 'imperial') {
return val
}
})
and to use it in html
<td>{{ product.od | convertOd(filter_unit) }}</td>
You could use computed properties but your code could work as it is.
I just applied conversions on values in the onSelectUnitChange function and it worked.
onSelectUnitChange:function(){
if(this.filter_unit == 'standard'){
this.products.forEach(p => {
p.od *= 0.0393701
p.id *= 0.0393701
p.thickness *= 0.0393701
})
this.columns[1].label = "OD(De,in)"
this.columns[2].label = "ID(De,in)"
this.columns[3].label = "Thickness(De,in)"
} else {
this.products.forEach(p => {
p.od /= 0.0393701
p.id /= 0.0393701
p.thickness /= 0.0393701
})
this.columns[1].label = "OD(De,mm)"
this.columns[2].label = "ID(De,mm)"
this.columns[3].label = "Thickness(De,mm)"
}
}