Search specific data in vue b-table from axios API - javascript

I have created a b-table that stores all the data from the API that has been hit from Swagger UI, since there's a lot of data I wanted to make the search button on top center of page works correctly by inputting store code or branch
How to implement filter for the table so the search button works as it should be? Thanks in advance
Here's a peak of my code (I already tried making filter for Store Code but it seems doesn't work?
<script>
// eslint-disable-next-line no-unused-vars
import { getAllProvinces } from '~/api/delivery'
export default {
data() {
return {
perPage: 0,
currentPage: 1,
rows: 0,
items: [],
fields: [
{
key: 'id',
sortable: true,
label: 'ID',
class: 'truncate',
},
{
key: 'uploadReference',
sortable: true,
label: 'Upload Reference',
class: 'truncate',
},
{
key: 'requestId',
sortable: true,
label: 'Request ID',
class: 'truncate',
},
{
key: 'storeCode',
sortable: true,
label: 'Store Code',
class: 'truncate',
},
{
key: 'branchCode',
sortable: true,
label: 'Branch Code',
class: 'truncate',
},
{
key: 'b2bId',
sortable: true,
label: 'B2B ID',
class: 'truncate',
},
{
key: 'request',
sortable: true,
label: 'Request',
class: 'truncate',
},
{
key: 'response',
sortable: true,
label: 'Response',
class: 'truncate',
},
{
key: 'createDate',
sortable: true,
label: 'Create Date',
class: 'truncate',
},
{
key: 'errorClassification',
sortable: true,
label: 'Error Classification',
class: 'truncate',
},
],
}
},
computed: {},
watch: {
currentPage: {
handler(value) {
this.getAllStock()
},
search() {
const data = this.items
if (this.search.length > 0) {
if (data.filter((item) => item.storeCode === this.search)) {
this.items = data.filter((item) => item.storeCode === this.search)
} else {
this.search = ''
this.getAllStock()
}
} else {
this.getAllStock()
}
},
},
},
// components: {
// },
created() {
this.getAllStock()
},
mounted() {
this.getAllStock()
},
methods: {
getAllStock() {
this.$axios
.get(
'http://swaggerlinkhere?requestPage=' +
this.currentPage +
'&status=1'
)
.then((res) => {
// eslint-disable-next-line no-console
console.log(res.data)
this.items = res.data.stocks
this.allStock = res.data
this.rows = res.data.totalDocuments
// eslint-disable-next-line no-console
// console.log('cek res stock:', JSON.stringify(res.data))
})
},
},
}
</script>
<style>
.truncate {
max-width: 190px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style>
<template>
<div>
<b-form inline>
<label for="status">Status⠀⠀⠀⠀ :</label>
<div class="col-sm-2">
<b-form-input text></b-form-input>
</div>
<div class="branch">
<div class="col-lg-10 text-right">
<b-form inline label-align-sm="right" style="margin-left: 70px">
<div class="col-sm-2" label for="branch">Branch⠀:</div>
<div class="col-sm-8">
<b-form-input text style="margin-left: 33px"></b-form-input>
</div>
<br />
</b-form>
</div>
</div>
</b-form>
</div>
<div>
<b-form inline>
<label for="storecode">Store Code⠀:</label>
<div class="col-sm-2">
<b-form-input text></b-form-input>
</div>
<div class="branch">
<div class="col-lg-12 text-right">
<b-form inline label-align-sm="right">
<div class="input-group col-sm-10">
<b-button
v-model="search"
variant="dark"
style="margin-left: 205px; margin-top: 5px"
>Search</b-button
>
</div>
</b-form>
</div>
</div>
</b-form>
</div>
<br />
<br />
<b-card body>
<b-card-header class="border-0">
<h3 class="mb-0">Stock List</h3>
</b-card-header>
<template>
<p class="mt-3">Current Page: {{ currentPage }}</p>
<div class="text-center">
<b-table
id="my-table"
responsive
dark
striped
hover:true
:items="items"
:fields="fields"
:per-page="0"
:current-page="currentPage"
>
<template v-slot:cell()="data">
<span v-b-tooltip.hover :title="data.value">{{
data.value
}}</span>
</template>
</b-table>
</div>
</template>
<div class="overflow-auto">
<b-card-footer class="py-4 d-flex justify-content-end">
<b-pagination
v-model="currentPage"
:total-rows="rows"
:per-page="perPage"
aria-controls="my-table"
></b-pagination>
</b-card-footer>
</div>
</b-card>
</template>

You can use the bootstrap table filter for both status code and branch code.
var app = new Vue({
el: '#app',
data() {
return {
filter: null,
filterOn: [],
perPage: 0,
currentPage: 1,
rows: 0,
items: [],
fields: [{
key: 'id',
sortable: true,
label: 'ID',
class: 'truncate',
},
{
key: 'uploadReference',
sortable: true,
label: 'Upload Reference',
class: 'truncate',
},
{
key: 'requestId',
sortable: true,
label: 'Request ID',
class: 'truncate',
},
{
key: 'storeCode',
sortable: true,
label: 'Store Code',
class: 'truncate',
},
{
key: 'branchCode',
sortable: true,
label: 'Branch Code',
class: 'truncate',
},
{
key: 'b2bId',
sortable: true,
label: 'B2B ID',
class: 'truncate',
},
{
key: 'request',
sortable: true,
label: 'Request',
class: 'truncate',
},
{
key: 'response',
sortable: true,
label: 'Response',
class: 'truncate',
},
{
key: 'createDate',
sortable: true,
label: 'Create Date',
class: 'truncate',
},
{
key: 'errorClassification',
sortable: true,
label: 'Error Classification',
class: 'truncate',
},
],
}
},
watch: {
currentPage: {
handler(value) {
this.getAllStock()
},
},
},
methods: {
getAllStock() {
this.$axios
.get(
'http://swaggerlinkhere?requestPage=' +
this.currentPage +
'&status=1'
)
.then((res) => {
// eslint-disable-next-line no-console
console.log(res.data)
this.items = res.data.stocks
this.allStock = res.data
this.rows = res.data.totalDocuments
// eslint-disable-next-line no-console
// console.log('cek res stock:', JSON.stringify(res.data))
})
},
onFiltered(filteredItems) {
this.rows = filteredItems.length
this.currentPage = 1
},
},
created() {
this.getAllStock()
},
})
<template>
<div>
<div>
<b-form inline>
<label for="status">Status:</label>
<div class="col-sm-2">
<b-form-input text></b-form-input>
</div>
<b-col lg="6" class="my-1">
<b-form-group label="Filter" label-for="filter-input" label-cols-sm="3" label-align-sm="right" label-size="sm" class="mb-0">
<b-input-group size="sm">
<b-form-input id="filter-input" v-model="filter" type="search" placeholder="Type to Search"></b-form-input>
<b-input-group-append>
<b-button :disabled="!filter" #click="filter = ''">Clear</b-button>
</b-input-group-append>
</b-input-group>
</b-form-group>
</b-col>
<b-col lg="6" class="my-1">
<b-form-group label="Filter On" description="Leave all unchecked to filter on all data" label-cols-sm="3" label-align-sm="right" label-size="sm" class="mb-0">
<b-form-checkbox-group v-model="filterOn" class="mt-1">
<b-form-checkbox value="branchCode">Branch Code</b-form-checkbox>
<b-form-checkbox value="storeCode">store Code</b-form-checkbox>
</b-form-checkbox-group>
</b-form-group>
</b-col>
</b-form>
</div>
<br/>
<br/>
<b-card body>
<b-card-header class="border-0">
<h3 class="mb-0">Stock List</h3>
</b-card-header>
<template>
<p class="mt-3">Current Page: {{ currentPage }}</p>
<div class="text-center">
<b-table id="my-table" :per-page="perPage" :current-page="currentPage" small striped hover responsive show-empty :items="items" :fields="fields" :filter="filter" :filterIncludedFields="filterOn" #filtered="onFiltered">
</b-table>
</div>
</template>
<div class="overflow-auto">
<b-card-footer class="py-4 d-flex justify-content-end">
<b-pagination v-model="currentPage" :total-rows="rows" :per-page="perPage" aria-controls="my-table"></b-pagination>
</b-card-footer>
</div>
</b-card>
</div>
</template>

If I understand you correctly, try to do something like this
var app = new Vue({
el: '#app',
data: {
rawItems:["one", "two", "three", "foo", "bar"],
searchText:"",
filteredItems:[]
},
mounted: function() {
this.filteredItems = this.rawItems
},
methods: {
onSearchClick: function () {
this.filteredItems = this.rawItems.filter(v=>v.indexOf(this.searchText)>=0)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<p>
<input v-model="searchText">
<button #click="onSearchClick">Search</button>
</p>
<p>{{filteredItems}}</p>
</div>

Related

How to make a clone of the array object with new id and same name?

I'm new at vue3 and javascript. I have 2 lists and drag and drop system. The problem is when I drag and drop component from one list to another, I increase an id by 1, but I can't get the name of dragged object and display it. The problem displayed at methods in method "cloneComponent"
<template>
<div class="full-zone">
<div class="components">
<h3>Компоненты бота:</h3>
<draggable
class="dragArea"
:list="list1"
:group="{ name: 'people', pull: 'clone', put: false }"
:clone="cloneComponent"
#change="log"
item-key="id"
>
<template #item="{element}">
<div class="list-group-item">
{{ element.name }}
</div>
</template>
</draggable>
</div>
<div class="constructor">
<h3>Конструктор</h3>
<draggable
class="constructor-list"
:list="list2"
group="people"
#change="log"
item-key="id"
>
<template #item="{ element, index }">
<div class="list-group-item">
{{ element.name }}
<div>
<input type="text" class="input" v-model="element.text" placeholder="Введите текст компонента" />
<span #click="remove(index)" class="remove">x</span>
</div>
</div>
</template>
</draggable>
</div>
<div>
<button class="btn">Сгенерировать бота</button>
</div>
<rawDisplayer class="col-3" :value="list1" title="List 1" />
<rawDisplayer class="col-3" :value="list2" title="List 2" />
</div>
</template>
<script>
import draggable from "vuedraggable";
let idGlobal = 4;
export default {
name: "clone",
display: "Clone",
order: 2,
components: {
draggable
},
data() {
return {
list1: [
{ name: "Сообщение", text: "", id: 1 },
{ name: "Заметка", text: "", id: 2 },
{ name: "Кнопка", text: "", id: 3 },
],
list2: []
};
},
methods: {
log: function(evt) {
window.console.log(evt);
},
cloneComponent() {
return {
id: idGlobal ++,
}
},
remove(idx) {
this.list2.splice(idx, 1);
},
}
};
</script>
How to return not only "id", but "name" at the same time? Please help.
You need to send the item to the other list
// tolist = can be 1 or 2
cloneComponent(item, tolist) {
if (tolist === 2) {
this.list2.push(item)
} else {
this.list1.push(item)
}
}

How to use BootstrapVue's layout and grid system to arrange these checkboxes?

I have a BootstrapVue table like this;
Here's the code for the table;
window.onload = () => {
new Vue({
el: '#app',
computed: {
visibleFields() {
return this.fields.filter(field => field.visible)
}
},
data() {
return {
items: [
{ id: 1, first: 'Mike', last: 'Kristensen', age: 16 },
{ id: 2, first: 'Peter', last: 'Madsen', age: 52 },
{ id: 3, first: 'Mads', last: 'Mikkelsen', age: 76 },
{ id: 4, first: 'Mikkel', last: 'Hansen', age: 34 },
],
fields: [
{ key: 'id', label: 'ID', visible: true },
{ key: 'first', label: 'First Name', visible: true },
{ key: 'last', label: 'Last Name', visible: true },
{ key: 'age', label: 'Age', visible: true },
]
}
}
})
}
<link href="https://unpkg.com/bootstrap#4.4.1/dist/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://unpkg.com/bootstrap-vue#2.2.2/dist/bootstrap-vue.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.2.2/dist/bootstrap-vue.min.js"></script>
<div id='app'>
<b-checkbox
:disabled="visibleFields.length == 1 && field.visible"
v-for="field in fields"
:key="field.key"
v-model="field.visible"
inline
>
{{ field.label }}
</b-checkbox>
<br /><br />
<b-table :items="items" :fields="visibleFields" bordered>
</b-table>
</div>
I want to use BootstrapVue layout and grid system to arrange the checkboxes.
https://bootstrap-vue.org/docs/components/layout
I want the checkboxes to be placed using BootstrapVue's layout and grid system as shown below;
<b-container class="bv-example-row">
<b-row class="justify-content-md-center">
<b-col col lg="12">1 of 3</b-col>
<b-col cols="12" md="auto">Variable width content</b-col>
<b-col col lg="2">3 of 3</b-col>
<b-col col lg="14">3 of 3</b-col>
</b-row>
</b-container>
What complicates matters is the html code for the checkbox which contains v-for. See below;
<b-checkbox
:disabled="visibleFields.length == 1 && field.visible"
v-for="field in fields"
:key="field.key"
v-model="field.visible"
inline
>
{{ field.label }}
</b-checkbox>
I am using vue v2.6, BootstrapVue.
It looks tricky, but doable.
Use v-for loop on <b-col> instead of <b-checkbox>
put <b-col> props like col lg=12 as fields property as an object {col:true,lg:12}
use v-bind to user style props to <b-col>
Here is my attempt in Codepen , I hope that I understood your intention correctly.
I assume that you are trying to render like below.
<b-container class="bv-example-row">
<b-row class="justify-content-md-center">
<b-col col lg="12">
<b-checkbox :disabled="visibleFields.length == 1 && fields[0].visible" v-model="fields[0].visible" inline>
{{ fields[0].label }}
</b-checkbox>
</b-col>
<b-col cols="12" md="auto">
<b-checkbox :disabled="visibleFields.length == 1 && fields[1].visible" v-model="fields[1].visible" inline>
{{ fields[1].label }}
</b-checkbox>
</b-col>
<b-col col lg="2">
<b-checkbox :disabled="visibleFields.length == 1 && fields[2].visible" v-model="fields[2].visible" inline>
{{ fields[2].label }}
</b-checkbox>
</b-col>
<b-col col lg="14">
<b-checkbox :disabled="visibleFields.length == 1 && fields[3].visible" v-model="fields[3].visible" inline>
{{ fields[3].label }}
</b-checkbox>
</b-col>
</b-row>
</b-container>
Adds new props property to your fields
fields:[
{ key: 'id', label: 'ID', visible: true, props:{ col:true, lg:12}},
{ key: 'first', label: 'First Name', visible: true, props:{cols:12, md:'auto' }},
{ key: 'last', label: 'Last Name', visible: true, props:{ col:true ,lg:2 }},
{ key: 'age', label: 'Age', visible: true, props:{col:true, lg:14} },
]
v-for loop with v-bind props
<div id='app'>
<b-container class="bv-example-row">
<b-row class="justify-content-md-center">
<b-col v-for="(field,index) in fields" :key="index" v-bind="field.props">
<b-checkbox :disabled="visibleFields.length == 1 && field.visible" v-model="field.visible" inline>
{{ field.label }}
</b-checkbox>
</b-col>
</b-row>
</b-container>
<br /><br />
<b-table :items="items" :fields="visibleFields" bordered>
</b-table>
</div>

How use a button in v-for loop in Nuxt.js?

I am using a card component of vuetify in a loop to display data but when I click on the button present in the card, all buttons of all cards present in the loop open. How can I do so that only the card button I clicked opens?
Here is my template :
<template>
<v-row>
<v-col
v-for="(prop, i) in Object.keys(linkIdeal)"
:key="i"
cols="6"
lg="2"
md="3"
sm="4"
class="mb-6"
#click="console.log(prop)"
>
<v-card
v-if="linkIdeal[prop].plant_associated[0].category == '1'"
style="z-index: 0"
:class="`mx-auto my-12 plant-card Vegetables`"
width="100%"
>
<v-img
:src="`${linkIdeal[prop].plant_associated[0].image}`"
width="100%"
height="200"
></v-img>
<v-card-title class="white--text card-title justify-center">
{{ linkIdeal[prop].plant_associated[0].name }}
</v-card-title>
<v-card-actions #click="show = !show" style="cursor: pointer">
<span class="white--text btnDescr">Description</span>
<v-spacer></v-spacer>
<v-btn icon>
<v-icon class="white--text">
{{ show ? 'mdi-chevron-up' : 'mdi-chevron-down' }}
</v-icon>
</v-btn>
</v-card-actions>
<v-expand-transition>
<div v-show="show">
<v-divider></v-divider>
<v-card-text>
<span
class="white--text"
v-html="linkIdeal[prop].description"
></span>
</v-card-text>
</div>
</v-expand-transition>
</v-card>
</v-col>
</v-row>
</template>
Here is my script :
import {
mapGetters
} from "vuex";
export default {
props: {},
data: () => ({
linkIdeal: [],
show: false,
}),
computed: {
console: () => console,
...mapGetters({
plantActive: 'permatheque/getPlant',
}),
},
methods: {
async getAssociatedPlant() {
this.$axios.$get('...')
.then(response => {
//this.$store.commit('permatheque/setPlantAssociations', response)
this.linkIdeal = response
console.log(this.linkIdeal)
}).catch(error => {
console.log(error)
});
},
},
mounted() {
this.getAssociatedPlant()
}
}
Thanks for your answer
You are using 1 show variable as a state for all the cards, their open/close state all depend on that, thus when you toggle this state, all cards act accordingly.
If you want to have an open/close state for every single card, then you should add it to each one (like in their own component) OR you can track the opened cards (e.g. by ID) in an array. Both could be a solution to your problem. (snippet coming to demonstrate)
OPEN/CLOSE STATE TRACKED IN AN ARRAY
Vue.component('ToggleCard', {
props: ['id', 'label', 'open'],
methods: {
onClick() {
this.$emit("update:open")
}
},
template: `
<div
class="cursor-pointer"
:class="{
open: open
}"
#click="onClick"
>
{{ label }} - {{ open }}
</div>
`
})
new Vue({
el: "#app",
data() {
return {
openedCards: [],
cards: [{
id: 0,
label: "CARD 1",
},
{
id: 1,
label: "CARD 2",
},
{
id: 2,
label: "CARD 3",
},
]
}
},
methods: {
isOpen(id) {
return this.openedCards.includes(id)
},
updateOpenedCards(id) {
if (this.isOpen(id)) {
this.openedCards = this.openedCards.filter(cardId => cardId !== id)
} else {
this.openedCards = [...this.openedCards, id]
}
}
},
template: `
<div>
<toggle-card
v-for="card in cards"
:key="card.id"
:id="card.id"
:label="card.label"
:open="isOpen(card.id)"
#update:open="() => updateOpenedCards(card.id)"
></toggle-card>
</div>
`
})
.cursor-pointer {
cursor: pointer;
}
.open {
background: green;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>
OPEN/CLOSE STATE TRACKED IN AN SEPARATE COMPONENTS
Vue.component('ToggleCard', {
props: ['id', 'label'],
data() {
return {
open: false,
}
},
template: `
<div
class="cursor-pointer"
:class="{
open: open
}"
#click="open = !open"
>
{{ label }} - {{ open }}
</div>
`
})
new Vue({
el: "#app",
data() {
return {
cards: [{
id: 0,
label: "CARD 1",
},
{
id: 1,
label: "CARD 2",
},
{
id: 2,
label: "CARD 3",
},
]
}
},
template: `
<div>
<toggle-card
v-for="card in cards"
:key="card.id"
:id="card.id"
:label="card.label"
></toggle-card>
</div>
`
})
.cursor-pointer {
cursor: pointer;
}
.open {
background: green;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>

Responsive select menu does not display array values

I have a navbar that displays values depending on selected tabs
Now I want to do exactly the same in mobile view, for that, I have a select menu instead navbar
But value is not changing
But values are not changing when I select different value, what am I doing wrong? Regards
CodePen
Code:
<template>
<div>
<div class="sm:hidden">
<label for="tabs" class="sr-only">Select a tab</label>
<select id="tabs" name="tabs" class="block w-full focus:ring-indigo-500 focus:border-indigo-500 border-gray-300 rounded-md">
<option v-for="tab in tabs" :key="tab.name" :selected="tab.current">{{ tab.name }}</option>
</select>
<div >
<div v-for="tab in tabs" #click="changeTab(tab)" :key="tab.name" :href="tab.href" class="px-12" :class="[tab.current || 'hidden']">
{{ tab.id }} - {{ tab.name }} - {{ tab.href }} - {{ tab.title }} - {{tab.imageSrc}}
</div>
</div>
</div>
<div class="hidden sm:block">
<nav class="flex space-x-4 " aria-label="Tabs" >
<a v-for="tab in tabs" #click="changeTab(tab)" :key="tab.name" :href="tab.href" :class="[tab.current ? 'bg-purple-700 text-white' : 'text-purple-700 hover:text-gray-700', 'px-12 py-2 font-medium text-sm rounded-full font-bold text-lg']" >
{{ tab.name }}
</a>
</nav>
</div>
<div class="hidden sm:block">
<div v-for="tab in tabs" #click="changeTab(tab)" :key="tab.name" :href="tab.href" class="px-12" :class="[tab.current || 'hidden']">
{{ tab.id }} - {{ tab.name }} - {{ tab.href }} - {{ tab.title }} - {{tab.imageSrc}}
</div>
</div>
</div>
</template>
<script lang="ts">
import { ref } from 'vue'
export default {
setup() {
const tabs = ref([
{ id: 1 , title: 'test title one', imageSrc:'/programs/test1.png' , content: '', name: 'LOREM', href: '#test1', current: true },
{ id: 2 , title: 'test title two', imageSrc:'/programs/test2.png', content: '', name: 'IPSUM', href: '#test2', current: false },
{ id: 3 , title: 'test title three', imageSrc:'/programs/test3.png', content: '', name: 'PDF', href: '#test3', current: false },
{ id: 4 , title: 'test title three', imageSrc:'/programs/test3.png', content: '', name: 'PDF', href: '#test3', current: false },
{ id: 5 , title: 'test title three', imageSrc:'/programs/test3.png', content: '', name: 'PDF', href: '#test3', current: false },
{ id: 6 , title: 'test title three', imageSrc:'/programs/test3.png', content: '', name: 'PDF', href: '#test3', current: false },
])
const changeTab = (selectedTab) => {
tabs.value.map(t => {
t.id === selectedTab.id ? t.current = true : t.current = false
});
}
return { tabs, changeTab }
},
computed: {
img() {
return `./images/modal/${encodeURIComponent(this.tabs[0].imageSrc)}.png`
},
},
}
</script>
<style lang="scss" scoped>
nav {
display: flex;
gap: 20px;
background: #E5E5E5;
border-radius: 20px;
width: 100%;
justify-content: space-between;
}
</style>
Your <select> tag has no binding. Usually you should have a v-bind or at least a change handler to update the data.
Your change handler could look like this:
<select
#change="changeTab($event.target.value)"
>
...
</select>

Vue.JS - How to have a button perform two separate actions on the same parent element?

On parent I have:
<template>
<b-container>
<b-modal id="uw-qb-add-item-modal"
ref="uw-qb-add-item-modal"
title="Enter Item Number"
#ok="handleNewItem">
<form #submit.stop.prevent="handleSubmit">
<b-form-input type="text"
placeholder="Enter the item number" />
</form>
</b-modal>
<div class="row mb-3">
<div class="col">
<nuxt-link to="/">
<i class="fa fa-chevron-left" aria-hidden="true"></i>
Quote Build List
</nuxt-link>
</div>
</div>
<div class="row mb-3">
<div class="col-md"><h2>Quote Build <b-badge :variant="buildBadgeVariant">{{ buildBadgeText }}</b-badge></h2></div>
<div class="col-md text-right text-success"><h3><i class="fa fa-usd" aria-hidden="true"></i> {{ buildTotal | formatDollars }}</h3></div>
</div>
<div class="row mb-3">
<div class="col-md form-group">
<build-customer :buildNumber="buildNumber"/>
</div>
<div class="col-md form-group">
<build-address :buildNumber="buildNumber" />
</div>
<div class="col-md form-group">
<build-contact :buildNumber="buildNumber" />
</div>
<div class="col-md form-group">
<label for="uw-qb-due-date">Due Date</label>
<date-picker v-model="dueDate"/>
</div>
</div>
<div class="row mb-3">
<div class="col-sm form-group">
<div class="form-check">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" v-model="internal" />
Internal Quote
</label>
</div>
<build-requester-id v-if="internal" :buildNumber="buildNumber"/>
</div>
<div class="col-sm form-group">
<label>RFQ Number</label>
<b-form-input type="text" v-model="rfqNumber"/>
</div>
<div class="col-sm form-group">
<div class="form-check">
<label class="form-check-label mb-3">
<input class="form-check-input" type="checkbox" v-model="update" />
Quote Update
</label>
<label class="form-check-label">
<input class="form-check-input" type="checkbox" v-model="correctiveAction" />
Corrective Action
</label>
</div>
</div>
<div class="col-sm form-group">
<label>Request Date</label>
<date-picker v-model="requestDate" />
</div>
</div>
<div class="row mb-3">
<div class="col-md text-right">
<b-btn variant="primary"
v-b-toggle="editId"
#click="newEditItem">
<i class="mr-1 fa fa-plus" aria-hidden="true"></i>
Add Item
</b-btn>
</div>
</div>
<b-collapse :id="editId">
<build-item-edit #doOnEmit="expand" :buildNumber="buildNumber"
:itemNumber="editItemNumber"/>
</b-collapse>
<build-item-list #edit="edit" :buildNumber="buildNumber" />
<build-breakdown-edit :buildNumber="buildNumber" :breakdownNumber="editBreakdownNumber"/>
<build-breakdown-list :buildNumber="buildNumber"/>
</b-container>
</template>
<script>
import BuildCustomer from '#/components/buildCustomer'
import BuildAddress from '#/components/buildAddress'
import BuildContact from '#/components/buildContact'
import BuildRequesterId from '#/components/buildRequesterId'
import BuildItemEdit from '#/components/buildItemEdit'
import BuildItemList from '#/components/buildItemList'
import BuildBreakdownEdit from '#/components/buildBreakdownEdit'
import BuildBreakdownList from '#/components/buildBreakdownList'
import DatePicker from '#/components/datePicker'
export default {
data () {
return {
editItemNumber: null,
editBreakdownNumber: null
}
},
components: {
'build-customer': BuildCustomer,
'build-address': BuildAddress,
'build-contact': BuildContact,
'build-requester-id': BuildRequesterId,
'build-item-edit': BuildItemEdit,
'build-item-list': BuildItemList,
'build-breakdown-edit': BuildBreakdownEdit,
'build-breakdown-list': BuildBreakdownList,
'date-picker': DatePicker
},
computed: {
// nextItemNumber () {
// const itemNumbers = this.$store.getters['build/item/numbers'](this.buildNumber)
// return Math.min.apply(null, itemNumbers) - 1
// },
editId () {
return this.idGen('edit-item-collapse')
},
dueDate: {
get () {
return this.build.dueDate
},
set (value) {
this.$store.commit('build/setDueDate', { buildNumber: this.buildNumber, dueDate: value })
}
},
requestDate: {
get () {
return this.build.requestDate
},
set (value) {
this.$store.commit('build/setRequestDate', { buildNumber: this.buildNumber, requestDate: value })
}
},
internal: {
get () {
return this.build.internal
},
set (value) {
this.$store.commit('build/setInternal', { buildNumber: this.buildNumber, internal: !!value })
}
},
update: {
get () {
return this.build.update
},
set (value) {
this.$store.commit('build/setUpdate', { buildNumber: this.buildNumber, update: !!value })
}
},
correctiveAction: {
get () {
return this.build.correctiveAction
},
set (value) {
this.$store.commit('build/setCorrectiveAction', { buildNumber: this.buildNumber, correctiveAction: !!value })
}
},
requesterId: {
get () {
return this.build.requesterId
},
set (value) {
if (value === null || this.$store.getters.employees.hasOwnProperty(value)) {
this.$store.commit('build/setRequesterId', { buildNumber: this.buildNumber, requesterId: value })
}
}
},
rfqNumber: {
get () {
return this.build.rfqNumber
},
set (value) {
this.$store.commit('build/setRfqNumber', {buildNumber: this.buildNumber, rfqNumber: value })
}
},
employees () {
const res = [{ value: null, text: 'Select requested by ...' }];
for (var empId in this.$store.getters['employee/employees']) {
res.push({ value: empId, text: this.$store.getters.employees[empId] });
}
return res;
},
buildNumber () {
return parseInt(this.$route.params.buildNumber, 10);
},
build () {
return this.$store.getters['build/build'](this.buildNumber);
},
buildBadgeVariant () {
if (this.isNewBuild) { return 'primary'; }
return 'info';
},
buildBadgeText () {
if (this.isNewBuild) { return 'New'; }
return this.buildNumber;
},
isNewBuild () {
return this.buildNumber < 0;
},
buildTotal () {
return this.$store.getters['build/total'](this.buildNumber);
}
},
methods: {
fetchData () {
if (!this.isNewBuild) {
// TODO - waiting on schema changes
console.log('Fetching build data for ' + this.$route.params.buildNumber);
}
},
handleNewItem () {
this.$store.commit('setError', 'Adding items not supported');
},
newEditItem () {
this.editItemNumber = this.nextItemNumber
},
edit(eventPayload) {
this.editItemNumber = eventPayload
},
expand() {
console.log("TEST")
this.idGen('edit-item-collapse')
}
},
fetch (context) {
const buildNumber = parseInt(context.params.buildNumber, 10)
const build = context.store.getters['build/build'](buildNumber)
if (build === null && buildNumber >= 0) {
console.log('load build')
} else if (build === null && buildNumber < 0) {
// if the build doesn't exist and it is a temp build
// number, then just redirect to new
context.app.router.replace('/new')
}
}
}
</script>
buildItemEdit
<template>
<b-container>
<b-row>
<b-col>
<h3>Item</h3>
<p></p>
<b-row></b-row>
<p></p>
</b-col>
</b-row>
<b-row>
<b-col>
<b-row>
<b-col>
<label>Item No.</label>
<b-form-input v-model='itemNum' type="text" :state="itemNoState" onkeypress='return event.charCode >= 48 && event.charCode <= 57'
/>
</b-col>
<b-col>
<label>Item Type</label>
<b-form-select v-model="type" :options="itemTypes" class="mb-3" :state="itemTypeState" />
</b-col>
<b-col>
<label>Part No.</label>
<b-form-input v-model='partNumber' type="text" :state="partNoState" onkeypress='return event.charCode >= 48 && event.charCode <= 57'
/>
</b-col>
<b-col>
<label>Piece Amount</label>
<b-form-input v-model='pieceCount' type="number" :state="pieceAmountState" onkeypress='return event.charCode >= 48 && event.charCode <= 57'
/>
</b-col>
</b-row>
<b-row>
<b-col>
<label>Comments</label>
<b-form-textarea id="comments" v-model="comments" placeholder="Enter comments here" :rows="3" :max-rows="6"></b-form-textarea>
</b-col>
</b-row>
<p></p>
<b-row>
<b-col>
<b-card-group deck class="mb-3">
<b-card bg-variant="primary" text-variant="white" class="text-center">
<p class="card-text">Breakdown 1</p>
</b-card>
<b-card bg-variant="secondary" text-variant="white" class="text-center">
<p class="card-text">Breakdown 2</p>
</b-card>
<b-card bg-variant="success" text-variant="white" class="text-center">
<p class="card-text">Breakdown 3</p>
</b-card>
</b-card-group>
</b-col>
</b-row>
</b-col>
</b-row>
<b-row>
<p></p>
</b-row>
<b-row>
<p></p>
</b-row>
<b-row>
<b-col>
<div v-if="editmsg" class="col-md text-left">
<b-btn size="" #click="editUpdate" variant='success'>
<i class='mr-1 fa fa-plus' aria-hidden="true"></i> Save Edit</b-btn>
</div>
<p></p>
</b-col>
<b-col>
<div class="col-md text-center">
<b-btn size="" #click="addItem" variant='primary'>
<i class='mr-1 fa fa-plus' aria-hidden="true"></i> Break Downs</b-btn>
</div>
</b-col>
<b-col>
<div class="col-md text-right">
<b-btn size="" #click="addItem" variant='primary' v-bind:disabled="!canSave">
<i class='mr-1 fa fa-plus' aria-hidden="true"></i> Save Item</b-btn>
</div>
</b-col>
</b-row>
<div v-if="existmsg">
<p></p>
<b-alert show variant="danger">{{ existmsg }}</b-alert>
</div>
<div v-if="editmsg">
<p></p>
<b-alert show variant="warning">{{ editmsg }}</b-alert>
</div>
</b-container>
</template>
<script>
import Util from '#/lib/util'
export default {
props: ['buildNumber', 'itemNumber'],
data() {
return {
itemNum: "",
type: "",
partNumber: "",
pieceCount: "",
comments: "",
selected: "A",
}
},
watch: {
itemNumber: function (editItemNumber) {
if (editItemNumber == null) {
this.update({})
} else {
const item = this.item(editItemNumber)
this.update(item)
this.itemNum = editItemNumber
}
}
},
computed: {
itemNoState() {
return !isNaN(parseFloat(this.itemNum)) && isFinite(this.itemNum) ? null : false;
},
itemTypeState() {
return (this.type) ? null : false;
},
partNoState() {
return !isNaN(parseFloat(this.partNumber)) && isFinite(this.partNumber) ? null : false;
},
pieceAmountState() {
return !isNaN(parseFloat(this.pieceCount)) && isFinite(this.pieceCount) ? null : false;
},
canSave() {
return this.itemNumber != '' && this.type != '' && this.partNumber != '' && this.pieceCount != ''
},
editmsg: {
get() {
return this.$store.getters["build/item/editmsg"];
},
set(value) {
this.$store.commit("build/item/seteditmsg", value);
}
},
existmsg: {
get() {
return this.$store.getters["build/item/existmsg"];
},
set(value) {
this.$store.commit("build/item/setexistmsg", value);
}
},
itemTypes() {
const iTypes = []
const b = this.$store.getters['itemType/all']
for (var itemValue in b) {
iTypes.push({
value: itemValue,
text: b[itemValue]
})
}
return iTypes
}
},
methods: {
item(itemNumber) {
return this.$store.getters["build/item/item"](
this.buildNumber,
itemNumber
);
},
addItem() {
if (this.item(this.itemNum) == null)
{
this.$store.commit('build/item/add', {
buildNumber: this.buildNumber,
itemNumber: this.itemNum,
item: {
type: this.type,
partNumber: this.partNumber,
pieceCount: this.pieceCount,
comments: this.comments
}
})
this.update({})
}
else
{
this.existmsg = "Item number " + this.itemNum + " already exists on this quote"
}
},
update(item) {
this.itemNum = Util.field(item, 'itemNumber', '')
this.type = Util.field(item, 'type', '')
this.partNumber = Util.field(item, 'partNumber', '')
this.pieceCount = Util.field(item, 'pieceCount', '')
this.comments = Util.field(item, 'comments', '')
this.existmsg = ""
},
editUpdate(item) {
this.$store.commit('build/item/update', {
buildNumber: this.buildNumber,
itemNumber: this.itemNum,
item: {
type: this.type,
partNumber: this.partNumber,
pieceCount: this.pieceCount,
comments: this.comments
}
})
this.update({})
this.editmsg = ""
}
}
}
</script>
Now on the child I already have a button that emits an item number to the parent (editItemNumber) above. But I always want that same button on the child to expand this collapse on the parent only if its not collapsed.
Below is the existing child.
edit(item) {
const payload = {
item
};
this.$emit('edit', item.itemNumber);
this.editmsg = "Edit your item above and then click 'Save Edit'"
}
buildItemList
<template>
<b-container>
<div>
<p></p>
<h5>Items</h5>
<p></p>
<b-table show-empty bordered striped hover :items="itemTableList" :fields="fields">
<template slot="actions" scope="row">
<b-btn variant='success' size="sm" v-on:click="edit(row.item,$event.target)">Edit</b-btn>
<b-btn variant='danger' size="sm" #click.stop="delRow(row.item,row.index,$event.target)">Delete</b-btn>
</template>
</b-table>
</div>
</b-container>
</template>
<script>
import Util from "#/lib/util";
export default {
data() {
return {
fields: [
{ key: "itemNumber", label: "Item No.", sortable: true },
{ key: "type", label: "Item Type", sortable: false },
{ key: "partNumber", label: "Part No.", sortable: false },
{ key: "pieceCount", label: "Piece Amount", sortable: false },
{ key: "comments", label: "Comments", sortable: false },
{ actions: { label: "Actions" } }
]
};
},
props: ["buildNumber"],
computed: {
itemNumbers() {
console.log("DEVELOPER")
console.log(this.buildNumber)
const items = this.$store.getters["build/item/items"](this.buildNumber);
return Util.numSortedKeys(items);
},
itemTableList() {
const itemList = [];
for (var i of this.itemNumbers) {
const item = this.item(i);
itemList.push({
itemNumber: i,
type: item.type,
partNumber: item.partNumber,
pieceCount: item.pieceCount,
comments: item.comments
});
}
return itemList;
},
editmsg: {
get() {
return this.$store.getters["build/item/editmsg"];
},
set(value) {
this.$store.commit("build/item/seteditmsg", value);
}
}
},
methods: {
item(itemNumber) {
return this.$store.getters["build/item/item"](
this.buildNumber,
itemNumber
);
},
edit(item) {
const payload = {
item
};
this.$emit('doOnEmit')
this.$emit('edit', item.itemNumber);
// this.editmsg = "Edit your item above and then click 'Save Edit'"
}
}
};
</script>
So to reiterate, when the button edit is clicked, beyond what it's currently doing I want to expand that toggle collapse if not expanded on the parent component.
Is that possible?
I assume <build-item-edit> is your own component so just add a callback event to it i.e
<build-item-edit #doOnEmit="someFunctionOnTheParent" :buildNumber="buildNumber" :itemNumber="editItemNumber"/>
Then on the parent component, define the method someFunctionOnTheParent and run the code that does your UI stuff.
Then in the build-item-edit component, before you emit the value, call this.$emit('doOnEmit')

Categories

Resources