I am trying to use autocomplete component "v-suggestions", from https://www.npmjs.com/package/v-suggestions
Want to use in tab row in a loop, since i want to create multiple select boxes, please see the code
<tr
v-for="ingredient in ingredients"
v-bind:key="ingredient.id"
>
<!-- https://www.npmjs.com/package/v-suggestions -->
<td>
<suggestions
v-model="query.suggestions"
:options="options"
:onInputChange="onSelectIngredient">
</suggestions>
</td>
<td>
<input
type="text"
class="form-control"
id=""
v-model="items.quantity"
/>
</td>
<td>
export default {
data() {
let ingredients_auto = ['Onion', 'Salt', 'Oil', 'Sugar']
return {
items: [
{ id: 0, item_name: "x", quantity: "" },
{ id: 1, item_name: "y", quantity: "" },
{ id: 2, item_name: "y", quantity: "" }
],
query: '',
ingredients_auto: ingredients_auto,
ingredients_selected: null,
options: {}
};
methods: {
onSelectIngredient (query) {
if (query.trim().length === 0) {
return null
}
// return the matching countries as an array
return this.ingredients_auto.filter((item) => {
return item.toLowerCase().includes(query.toLowerCase())
})
}
}
I am getting below error in console , any idea why I am see this issue , I think there are issue with v-model, not sure how to fix this
vue.runtime.esm.js?2b0e:1888 TypeError: Cannot use 'in' operator to search for 'suggestions' in Salt
at Proxy.set (vue.runtime.esm.js?2b0e:1076)
at callback (eval at ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"d52508de-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/views/AddDish.vue?vue&type=template&id=646fb311&scoped=true& (app.b02fcecff20360dbbc44.hot-update.js:11), <anonymous>:189:45)
at invokeWithErrorHandling (vue.runtime.esm.js?2b0e:1854)
at VueComponent.invoker (vue.runtime.esm.js?2b0e:2179)
at invokeWithErrorHandling (vue.runtime.esm.js?2b0e:1854)
at VueComponent.Vue.$emit (vue.runtime.esm.js?2b0e:3888)
at VueComponent.query (v-suggestions.js?c4f6:1)
at Watcher.run (vue.runtime.esm.js?2b0e:4568)
at flushSchedulerQueue (vue.runtime.esm.js?2b0e:4310)
at Array.eval (vue.runtime.esm.js?2b0e:1980)
You had couple of mistakes I have rectified go through this
<template>
<table>
<tr
v-for="ingredient in ingredients"
v-bind:key="ingredient.id"
>
<td>
<suggestions
v-model="queries[ingredient.id]"
:options="options"
:onInputChange="onSelectIngredient">
</suggestions>
<!-- note the queries array, each item in it binds to a unique item in ingredients array -->
</td>
<td>
<input
type="text"
class="form-control"
id=""
v-model="ingredient.quantity"
/>
</td>
</tr>
</table>
</template>
<script>
import suggestions from 'v-suggestions'
export default {
name: 'demo',
components: {
suggestions
},
// using component locally, but if want to use globally use Vue.use(suggestions)
data() {
let ingredients_auto = ['Onion', 'Salt', 'Oil', 'Sugar']
let q = [];
for(var i=0; i<ingredients_auto.length; i++) {
q.push('');
}
//since we want queries array to be same length as of ingredients/ingredients_auto
return {
dish_name: "",
ingredients: [
{ id: 0, item_name: "Salt", quantity: "" },
{ id: 1, item_name: "Pepper", quantity: "" },
{ id: 2, item_name: "Oil", quantity: "" }
],
error: "",
selected:[],
units: ['gms', 'pound', 'kgs', 'ml', 'nos', 'liter'],
query: '',
ingredients_auto: ingredients_auto,
ingredients_selected: null,
options: {},
queries: q
};
},
methods: {
onSelectIngredient (query) {
if (query.trim().length === 0) {
return null
}
// return the matching countries as an array
return this.ingredients_auto.filter((item) => {
return item.toLowerCase().includes(query.toLowerCase())
})
}
}
}
</script>
Note that I have made a dynamic array q which I copy to queries because you want each individual textbox to behave independently so typing in one textbox should not affect the text contained in other textboxes
#viney see the
I didn't added that portion, let me add
export default {
data() {
let ingredients_auto = ['Onion', 'Salt', 'Oil', 'Sugar']
return {
dish_name: "",
ingredients: [
{ id: 0, item_name: "Salt", quantity: "" },
{ id: 1, item_name: "Pepper", quantity: "" },
{ id: 2, item_name: "Oil", quantity: "" }
],
error: "",
selected:[],
units: ['gms', 'pound', 'kgs', 'ml', 'nos', 'liter'],
query: '',
ingredients_auto: ingredients_auto,
ingredients_selected: null,
options: {}
};
Related
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;
},
I am attempting to make a custom component in Vue 2.0 that extends the existing functionality of the Bootstrap Vue library <b-table>. It mostly works how I would like it to except that the removeRow and resetData functions defined in the index.jsp don't work how I'd like them to.
removeRow does visually remove the row, and removes it from the data prop but the row reappears after the next interaction (sort, filter, etc.). So it's not actually updating the right thing. I'm trying to use a v-model as a shallow copy of items so that I can make deletions to it without affecting the original set of data but I'm just missing something.
resetData does set the data in the table back correctly, but doesn't re-render the table so you can't see the re-added rows, until you do a separate interaction (sort, filter, etc.), in which case they reappear.
So I know I'm somewhat close but would really appreciate any insight on how to get this working correctly and ways I could improve any part of this component.
OreillyTable.vue.js
const OreillyTable = {
inheritAttrs: false,
data: function () {
return {
filter: null,
sortDesc: false,
hideEmpty: false,
isBusy: false,
currentPage: 1,
data: null
}
},
mounted: function () {
let filtered = this.slots.filter(function(value, index, arr){
return value.customRender;
});
this.slots = filtered;
},
methods: {
oreillyTableSort (a, b, key) {
if (a[key] === null || b[key] === null) {
return a[key] === null && b[key] !== null ? -1 : (a[key] !== null && b[key] === null ? 1 : 0);
} else if (typeof a[key] === 'number' && typeof b[key] === 'number') {
// If both compared fields are native numbers
return a[key] < b[key] ? -1 : (a[key] > b[key] ? 1 : 0)
} else {
// Stringify the field data and use String.localeCompare
return this.toString(a[key]).localeCompare(this.toString(b[key]), undefined, {
numeric: true
});
}
},
toString (val) {
return typeof val !== "undefined" && val != null ? val.toString() : '';
},
oreillyFilter (filteredItems) {
this.totalRows = filteredItems.length;
this.currentPage = 1;
}
},
props: {
fields: {
type: Array
},
items: {
type: Array,
required: true
},
hideEmpty: {
type: Boolean
},
filterPlaceholder: {
type: String,
default: "Filter"
},
sortFunction: {
type: Function,
default: null
},
filterFunction: {
type: Function,
default: null
},
slots: {
type: Array
},
sortBy: {
type: String,
default: null
},
perPage: {
type: Number,
default: 10
},
value: {
}
},
template: `<div :class="{ 'no-events' : isBusy }">
<b-row>
<b-col md="12">
<b-form-group class="mb-2 col-md-3 float-right pr-0">
<b-input-group>
<b-form-input v-model="filter" :placeholder="filterPlaceholder" class="form-control" />
</b-input-group>
</b-form-group>
</b-col>
</b-row>
<div class="position-relative">
<div v-if="isBusy" class="loader"></div>
<b-table stacked="md" outlined responsive striped hover
v-bind="$attrs"
v-model="data"
:show-empty="!hideEmpty"
:items="items"
:fields="fields"
:no-provider-sorting="true"
:no-sort-reset="true"
:filter="filter"
:sort-by.sync="sortBy"
:sort-desc.sync="sortDesc"
:sort-compare="sortFunction === null ? this.oreillyTableSort : sortFunction"
:busy.sync="isBusy"
:current-page="currentPage"
:per-page="perPage"
#filtered="filterFunction === null ? this.oreillyFilter : filterFunction">
<template :slot="slot.key" slot-scope="row" v-for="slot in slots">
<slot :name="slot.key" :data="row"></slot>
</template>
</b-table>
<b-row v-if="items.length > perPage">
<b-col sm="12">
<b-pagination size="md" :total-rows="items.length" v-model="currentPage" :per-page="perPage"></b-pagination>
</b-col>
</b-row>
</div>
</div>`
};
index.jsp
<script>
Vue.use(window.vuelidate.default);
Vue.component('oreilly-table', OreillyTable);
const dashboardItems = [
{ id: 12, firstName: "John", lastName: "Adams", tmNumber: "588999", team: "Corporate", flapjackCount: 4, enrollDate: "2018-11-05" },
{ id: 13, firstName: "George", lastName: "Washington", tmNumber: "422111", team: "America", flapjackCount: 28, enrollDate: "2018-10-01" },
{ id: 14, firstName: "Abraham", lastName: "Lincoln", tmNumber: "358789", team: "America", flapjackCount: 16, enrollDate: "2017-09-02" },
{ id: 15, firstName: "Jimmy", lastName: "Carter", tmNumber: "225763", team: "Core", flapjackCount: 9, enrollDate: "2018-03-02" },
{ id: 16, firstName: "Thomas", lastName: "Jefferson", tmNumber: "169796", team: "Core", flapjackCount: 14, enrollDate: "2018-05-01" }
];
const Dashboard = {
template: `<jsp:include page="dashboard.jsp"/>`,
data: function(){
return {
notification: {
text: "The Great Flapjack Contest will be held on December 25, 2018.",
variant: "primary",
timer: true
},
fields: [
{ key: "name", label: "Name", sortable: true, customRender: true },
{ key: "team", label: "Team", sortable: true },
{ key: "enrollDate", label: "Enrollment Date", sortable: true, formatter: (value) => {return new Date(value).toLocaleDateString();} },
{ key: "flapjackCount", sortable: true },
{ key: "id", label: "", 'class': 'text-center', customRender: true }
]
}
},
methods: {
removeRow: function(id) {
this.$refs.table.isBusy = true;
setTimeout(() => { console.log("Ajax Request Here"); this.$refs.table.isBusy = false; }, 1000);
const index = this.$refs.table.data.findIndex(item => item.id === id)
if (~index)
this.$refs.table.data.splice(index, 1)
},
resetData: function() {
this.$refs.table.data = dashboardItems;
}
}
};
const router = new VueRouter({
mode: 'history',
base: "/ProjectTemplate/flapjack",
routes: [
{ path: '/enroll', component: Enroll },
{ path: '/', component: Dashboard },
{ path: '/404', component: NotFound },
{ path: '*', redirect: '/404' }
]
});
new Vue({router}).$mount('#app');
dashboard.jsp
<compress:html>
<div>
<oreilly-table ref="table" :items="dashboardItems" :slots="fields" :fields="fields">
<template slot="name" slot-scope="row">
{{ row.data.item.firstName }} {{ row.data.item.lastName }} ({{ row.data.item.tmNumber }})
</template>
<template slot="id" slot-scope="row">
Remove
</template>
</oreilly-table>
<footer class="footer position-sticky fixed-bottom bg-light">
<div class="container text-center">
<router-link tag="button" class="btn btn-outline-secondary" id="button" to="/enroll">Enroll</router-link>
<b-button #click.prevent="resetData" size="md" variant="outline-danger">Reset</b-button>
</div>
</footer>
</div>
I tried to reproduce your problem with a simple example (see: https://codesandbox.io/s/m30wqm0xk8?module=%2Fsrc%2Fcomponents%2FGridTest.vue) and I came across the same problem you have. Just like the others already said, I agree that the easiest way to reset original data is to make a copy. I wrote two methods to remove and reset data.
methods: {
removeRow(id) {
const index = this.records.findIndex(item => item.index === id);
this.records.splice(index, 1);
},
resetData() {
this.records = this.copyOfOrigin.slice(0);
}
}
On mount I execute a function that makes a copy of the data. This is done with slice because otherwise it makes only a reference to the original array (note that normally JS is pass-by-value, but as stated in the vue documentation with objects, and thus internally in vue it is pass by reference (see: Vue docs scroll to the red marked text)).
mounted: function() {
this.copyOfOrigin = this.records.slice(0);
}
Now you can simple remove a record but also reset all the data.
SEE FULL DEMO
I hope this fixes your issue and if you have any questions, feel free to ask.
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)"
}
}
I have 2 questions with vue.js 2 and a fiddle here: https://jsfiddle.net/tmun9cxa/1/
When you click a column header, why does my sorting not work? What is the solution?
How do I go about making the search input field search only the pn column?
A lot of the examples ive found are using vue1 and out of date.
<input type="text" value="" v-model="search" placeholder="Search">
<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 products">
<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>
javascript here
var vm = new Vue({
el: '#app',
data: {
currentSort: 'pn',
currentSortDir: 'asc',
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
},{
pn: 1803561,
od: 12,
id: .8,
thickness: .7,
lo: .11,
weight: .5
},{
pn: 170149,
od: 9,
id: .64,
thickness: .6,
lo: .75,
weight: .3
},{
pn: 150149,
od: 15,
id: .22,
thickness: .3,
lo: .55,
weight: .9
},
], // products
},
methods: {
sort:function(col) {
//console.log( 'current: '+this.currentSort );
//console.log( 'col: '+col );
//var colthing = col;
// if you click the same label twice
if(this.currentSort == col){
console.log( 'same col: '+col );
// sort by asc
this.products = this.products.sort((a, b) => {
return a.col >= b.col;
});
}else{
this.currentSort = col;
console.log( 'diff col: '+col );
// sort by desc
this.products = this.products.sort((a, b) => {
return a.col <= b.col;
});
} // end if
}, // sort
}, // methods
}); // vue
the column sorting , as pointed out, was not working because you need to use a[col] instead of a.col
Also, you should consider using a computed value instead of modifying the original data. This makes filtering easier too.
here is the updated script (note that <tr v-for="(product) in products"> needs to be <tr v-for="(product) in showProducts"> for this to work)
var vm = new Vue({
el: '#app',
data: {
currentSort: 'pn',
currentSortDir: 'asc',
search: '',
columns: [
{ label: 'P/N', shortcode: 'pn' },
/// more columns ...
], // columns
products: [
//.... objects
], // products
},
computed: {
showProducts() {
return this.products.filter(a => {
console.log(a.pn)
return (a.pn + '').includes(this.search)
})
.sort((a, b) => {
if (this.currentSortDir === 'asc') {
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){
this.currentSortDir = this.currentSortDir === 'asc' ? 'desc' : 'asc';
}else{
this.currentSort = col;
console.log( 'diff col: '+col );
} // end if
}, // sort
}, // methods
}); // vue
finally, the fiddle: https://jsfiddle.net/tmun9cxa/2/
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'">