Getting rest api data into bootstrap Vue table and pagination - javascript

I am using the Itunes rest api to get data into my application, I am having problem getting the data into the table, the rest api structure is as follows:
{resultCount: 4, results: Array(4)}
So far I have tried the following:
<div class="overflow-auto">
<b-pagination
v-model="currentPage"
:total-rows="rows"
:per-page="perPage"
aria-controls="my-table"
></b-pagination>
<p class="mt-3">Current Page: {{ currentPage }}</p>
<b-table
id="my-table"
v-for="(result, index) in result"
:key="index"
:fields="fields"
:per-page="perPage"
:current-page="currentPage"
small
></b-table>
</div>
<script>
import List from "../components/myList.vue";
export default {
name: "Hero",
components: {
List
},
data: function() {
return {
fields: [
{
key: "artistName",
label: "Artist"
},
{
key: "collectionName",
label: "Song title"
}
],
title: "Simple Search",
isActive: true,
intro: "This is a simple hero unit, a simple jumbotron-style.",
subintro:
"It uses utility classes for typography and spacing to space content out.",
result: [],
errors: [],
List: [],
search: "",
loading: "",
message: false,
isValidationAllowed: false,
loadingClass: "loading",
errorTextClass: "error-text",
disableButton: false,
perPage: 3,
currentPage: 1
};
},
watch: {
search: function(val) {
if (!val) {
this.result = [];
}
}
},
computed: {
validated() {
return this.isValidationAllowed && !this.search;
},
isDisabled: function() {
return !this.terms;
},
rows() {
return this.result.length;
}
},
methods: {
getData: function() {
this.isValidationAllowed = true;
this.loading = true;
fetch(`https://itunes.apple.com/search?term=${this.search}&entity=album`)
.then(response => response.json())
.then(data => {
this.result = data.results;
this.loading = false;
/* eslint-disable no-console */
console.log(data);
/* eslint-disable no-console */
});
},
toggleClass: function() {
// Check value
if (this.isActive) {
this.isActive = false;
} else {
this.isActive = true;
}
},
refreshPage: function() {
this.search = "";
},
addItem: function(result) {
result.disableButton = true; // Or result['disableButton'] = true;
this.List.push(result);
/* eslint-disable no-console */
console.log(result);
/* eslint-disable no-console */
},
resizeArtworkUrl(result) {
return result.artworkUrl100.replace("100x100", "160x160");
}
},
mounted() {
if (localStorage.getItem("List")) {
try {
this.List = JSON.parse(localStorage.getItem("List"));
} catch (err) {
console.err(err);
}
}
}
};
</script>
I get just [Object Object] when looking into the rendered page, so either I am not targeting the correct element, or it is not coming in right: the following code works outside of the bootstrap vue pagination and table.
<div v-for="(result, index) in result" :key="index">
<div class="media mb-4">
<img
:src="resizeArtworkUrl(result)"
alt="Album Cover"
class="album-cover align-self-start mr-3"
>
<div class="media-body">
<h4 class="mt-0">
<button
type="button"
class="btn btn-primary btn-lg mb-3 float-right"
v-on:click="addItem(result)"
:disabled="result.disableButton"
>
<font-awesome-icon icon="plus"/>
</button>
<b>{{result.collectionName}}</b>
</h4>
<h6 class="mt-0">{{result.artistName}}</h6>
<p class="mt-0">{{result.primaryGenreName}}</p>
</div>
</div>
</div>
Any help would be good.

In your template has two variables with same name:
<div v-for="(result, index) in result" :key="index">
try change the result name like this:
<div v-for="(item, index) in result" :key="index">
<div class="media mb-4">
<img
:src="resizeArtworkUrl(item)"
alt="Album Cover"
class="album-cover align-self-start mr-3"
>
<div class="media-body">
<h4 class="mt-0">
<button
type="button"
class="btn btn-primary btn-lg mb-3 float-right"
v-on:click="addItem(item)"
:disabled="item.disableButton"
>
<font-awesome-icon icon="plus"/>
</button>
<b>{{item.collectionName}}</b>
</h4>
<h6 class="mt-0">{{item.artistName}}</h6>
<p class="mt-0">{{item.primaryGenreName}}</p>
</div>
</div>
</div>

Related

How to filter checkbox by query api in vuejs?

I'm making a website that has a filter function before pouring data out... Currently, I'm doing the pretty stupid way of dumping all the data out and putting it in an object and then filtering. I want when I click on it, it will call the api to return according to the params that I pass, but the initial default is that the checkbox is in the all box, it still returns all. Here is my code part....
Template:
<template>
<div class="job">
<div class="container recruit flex-wrap">
<div class="job-filter">
<h3>
Ngành nghề
<img
id="icon-filter"
#click="showfilter"
:style="{ display: display.btn_show_filter }"
src="../assets/recruit/angle-down-svgrepo-com.svg"
alt=""
/>
<img
id="icon-close-filter"
:style="{ display: display.btn_close_filter }"
#click="closefilter"
src="../assets/recruit/close-svgrepo-com.svg"
alt=""
/>
</h3>
//Handle Filter
<div
class="radio-group"
id="group-filter"
:style="{ display: display.group_filter }"
>
<div
class="radio-check"
v-for="(check, index) in checks"
#click="selectFilter(check)"
:key="index"
>
<input
type="radio"
:id="index"
name="fav_language"
:value="check"
v-model="selected"
/>
<label :for="check">{{ check }}</label
><br />
</div>
</div>
</div>
//End Handle filter
<div class="search">
<div class="search-top flex-wrap">
<h5>{{ totalJobs }} {{ localised("countRecruit") }}</h5>
<div class="search-input">
<input
type="search"
placeholder="Nhập tên vị trí công việc"
v-model="search"
/>
<button #click="searchJob">
<img src="../assets/recruit/search.svg" alt="" />
</button>
</div>
</div>
<div
id="jobs"
class="job-item"
v-for="(item, index) in jobs"
:key="index"
:per-page="perPage"
:current-page="currentPage"
>
<router-link
tag="a"
:to="{ name: 'Detail', params: { id: item.id } }"
>
<h3 class="mleft-27">{{ item.Name }}</h3>
</router-link>
<div class="job-info flex-wrap">
<div class="job-info-left pleft-27 flex-wrap">
<div>
<img src="../assets/recruit/years.svg" alt="" />
<b>{{ item.Exprerience }}</b>
</div>
<div>
<img src="../assets/recruit/luong.svg" alt="" />
<b>{{ item.Salary }}</b>
</div>
<div>
<img src="../assets/recruit/diadiem.svg" alt="" />
<b>{{ item.Headequarters }}</b>
</div>
</div>
<div>
<h6>{{ momentTime(item.updatedAt) }}</h6>
</div>
</div>
<div class="info-job flex-wrap">
<div class="list-info-job">
<li>{{ item.Content }}</li>
</div>
<router-link
tag="a"
:to="{ name: 'Detail', params: { id: item.id } }"
>
<button class="btn-detail">Xem chi tiết</button>
</router-link>
</div>
</div>
<h3 class="not-found" v-show="showNoData">Not Found</h3>
</div>
</div>
</div>
</template>
And here is the js logic I'm dealing with:
<script>
import "../assets/style.css";
import "../assets/job.css";
import job from "../locales/lang";
import request from "#/utils/request";
import moment from "moment";
export default {
name: "jobs",
components: {},
data() {
return {
totalJobs: null,
tickTime: "",
currentPage: 1,
showPag: true,
showNoData: false,
perPage: 4,
search: "",
page: "",
noData: [],
checks: [
"All",
"Developer",
"Tester",
"Designer",
"Support",
"Marketing",
"Other",
],
jobinfos: [],
showJobs: [],
selected: "All",
};
},
computed: {
},
watch: {
// selected(newVal) {
// if (newVal === "All") {
// return this.jobinfos;
// } else {
// return this.jobinfos.filter((i) => i.Genres === newVal);
// }
// },
},
async mounted() {
//API
this.getJobs();
// event enter
var self = this;
window.addEventListener("keyup", function (event) {
if (event.keyCode === 13) {
self.searchJob();
}
});
},
methods: {
//Call api job information by locale
async getJobs() {
await request
.get(`jobs?_locale=${this.$route.params.locale}`)
.then((response) => {
this.jobinfos = response.data;
this.showJobs = response.data;
this.totalJobs = response.data.length;
})
.catch((e) => {});
},
//Filter item jobs
selectFilter(item) {
this.selected = item;
if (this.selected == "All") {
this.showJobs = this.jobinfos;
} else {
this.showJobs = this.jobinfos.filter((i) => i.Genres === this.selected);
if (this.showJobs.length > 0) {
this.showPag = true;
this.showNoData = false;
} else {
this.showPag = false;
this.showNoData = true;
}
}
},
// method search by filter
},
};
</script>
As for the backend, I'm using 3rd party cms, it probably already provides enough query params for me, please give me some pseudocode or a way so that when I click on the checkbox, it will call the api to return the records according to the check box ^^ thanks

Adding item to cart and removing from cart

I have a + button to add item to cart,it works. But at the same time when number increments in cart I need number that says in stock will decrement number in stock that displays it doesn't work …
I need to do the same with - button
I really need the displayed inStock number to change when I add or remove items from cart
Can someone please help me? I'm new at this
Vue.component('product', {
template:
`
<div class="product">
<div class="product-image">
<img :src="image" />
</div>
<div class="product-info">
<h1>{{ product }}</h1>
<p v-if="inStock">In Stock {{inStock}}</p>
<p v-else>Out of Stock</p>
<button #click="addToCart"
:disabled="!inStock"
:class="{ disabledButton: !inStock }"> + </button>
<button #click="removeFromCart"> - </button>
</div>
</div>
`,
data() {
return {
product: 'Hoodie',
image: 'hoodie.jpeg',
inStock: 10,
cart: 0
}
},
methods: {
addToCart: function() {
this.$emit('add-to-cart')
},
removeFromCart: function() {
this.$emit('remove-from-cart')
}
}
})
var app = new Vue({
el: '#app',
data: {
cart: 0,
inStock: 10
},
methods: {
updateCart() {
this.cart += 1,
this.inStock -= 1,
},
removeItem() {
this.cart -= 1,
this.inStock += 1
}
}
})
HTML:
<div class="nav-bar"></div>
<div id="app">
<div class="cart">
<p>Cart({{ cart }})</p>
</div>
<product #add-to-cart="updateCart" #remove-from-cart="removeItem"></product>
</div>
Inside your component, remove the data attributes inStock and cart and props section.
Vue.component('product', {
template:
`
<div class="product">
<div class="product-image">
<img :src="image" />
</div>
<div class="product-info">
<h1>{{ product }}</h1>
<p v-if="inStock">In Stock {{inStock}}</p>
<p v-else>Out of Stock</p>
<button #click="addToCart"
:disabled="!inStock"
:class="{ disabledButton: !inStock }"> + </button>
<button #click="removeFromCart"> - </button>
</div>
</div>
`,
data() {
return {
product: 'Hoodie',
image: 'hoodie.jpeg',
}
},
props: {
inStock: {
type: Number,
default: 0
},
cart : {
type: Number,
default: 0
}
},
methods: {
addToCart: function() {
this.$emit('add-to-cart')
},
removeFromCart: function() {
this.$emit('remove-from-cart')
}
}
})
var app = new Vue({
el: '#app',
data: {
cart: 0,
inStock: 10
},
methods: {
updateCart() {
this.cart += 1,
this.inStock -= 1,
},
removeItem() {
this.cart -= 1,
this.inStock += 1
}
}
})
Then in your parent component, pass the props.
Parent Component (HTML)
<div class="nav-bar"></div>
<div id="app">
<div class="cart">
<p>Cart({{ cart }})</p>
</div>
<!-- changes for props added below -->
<product :cart="cart" :inStock="inStock" #add-to-cart="updateCart" #remove-from-cart="removeItem"></product>
</div>

How to render dynamic content "component" with custom tabs VueJs

i have a costume made Tabs and Tab from Laracasts Tabs Tutorial , and it work fine, but i need to load data when the tab is changed and i did that but when the data is loaded,
i need to render another component which have accordion and inside each accordion tab their some charts components need to be render also
so how can i render the accordion with the charts components when the Tabs tab is changed
Tabs Component:
<template>
<div class="tab-container -mt-px w-full">
<div class="tabs">
<ul class="list-reset flex border-b">
<li class="" v-for="(tab, index) in tabs" role="tab">
<a class="bg-white inline-block font-semibold hover:no-underline"
:class="[
{
'active-tab-link text-blue-dark border-l border-r active-tab-link-p': tab.isActive,
'text-blue hover:text-blue-darker non-active-tab-link-p': !tab.isActive
},
]"
:href="tab.href" #click="selectedTab(tab)">
{{tab.name}}
</a>
</li>
</ul>
</div>
<div class="tabs-details px-4 w-full">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: "Tabs",
data() {
return {
tabs: []
};
},
created() {
this.tabs = this.$children;
// this.selectFirstTab();
},
methods: {
selectedTab(selectedTab) {
this.$emit('onTabChange', selectedTab);
this.tabs.map((tab, index) => {
tab.isActive = (tab.name === selectedTab.name)
});
},
}
}
</script>
Tab Component:
<template>
<div class="w-full" role="tabpanel" v-show="isActive">
<slot></slot>
</div>
</template>
<script>
import {isEmpty} from "../helpers/Helper";
export default {
name: "Tab",
props: {
name: {
type: String,
required: true
},
selected: {
type: Boolean,
default: false,
},
isFirst: {
type: Boolean,
default: false,
},
},
data() {
return {
// isActive: false,
isActive: true,
// isFirst: this.isFirst
};
},
computed: {
href() {
return this.formatHref(this.name);
},
},
mounted() {
this.selectTabFromURL();
},
methods: {
selectTabFromURL() {
let hash = this.$route.hash;
if (this.selected) {
this.isActive = this.selected;
} else if (!isEmpty(hash)) {
this.isActive = (this.formatHref(this.name) === hash);
} else if (this.isFirst) {
this.isActive = this.isFirst;
} else if (!this.isFirst && this.isActive) {
this.isActive = !this.isActive;
}
},
formatHref(id) {
return `#${id.toLowerCase().replace(/ /g, '-')}`;
}
}
}
</script>
the main component:
<template>
<!--components tabs start-->
<div class="flex flex-col">
<div class="mt-3 border-t-4 border-primary-color border-6 bg-white">
<div class=" border border-gray-400 lg:border-l-0 lg:border-t lg:border-gray-400 rounded-b lg:rounded-b-none lg:rounded-r leading-normal">
<Tabs #onTabChange="handleTabChange">
<!--:name="`${tab.name} - ${tab.component.type}`"-->
<Tab v-for="(tab, index) in page.tabs"
:key="tab.id"
:id="tab.slug"
:name="tab.name"
:slug="tab.slug"
:isFirst="index === 0"
>
<div>
How to render the dynamic accordion with the charts one time only no need to re-render
</div>
</Tab>
</Tabs>
</div>
</div>
</div>
<!--components tabs end-->
</template>
in normal HTML and JQuery, i can load the data and the render the result and append it to the wanted tab how can we do this with vue, dose the dynamic component help in this case ?
I searched for a solution and found and implement the "Creating Vue.js Component Instances Programmatically"

Defining a drag container inside another drag container

This is in relation to implementing drag and drop using vue. I have a draggable div container.
// BoardColumn Component Parent Container
<template>
<div
draggable
#dragover.prevent
#dragenter.prevent
#drop="dropColumn($event, columnIndex)"
#dragstart="setPickColumnInfo($event, columnIndex)"
>
<div class="column bg-grey-light m-4">
<div class="flex items-center mb-2 font-bold">
{{ getColumnName() }}
</div>
<div class="list-reset">
<TaskCard
class="task"
v-for="(task, $taskIndex) of columnData.tasks"
:key="$taskIndex"
v-bind:task="task"
v-bind:taskIndex="$taskIndex"
v-bind:columnIndex="columnIndex"
/>
</div>
<input
type="text"
class="block p-2 w-full bg-transparent"
placeholder="+Enter a new task"
#keyup.enter="createTask($event, columnData.tasks)"
/>
</div>
</div>
</template>
Inside this container is another draggable container TaskCard. i'm able to drag the parent container and the child container without any issues. However, the callback functions related to only parent container BoardColumn gets fired regardless of which container is being dragged.
The function definitions are below. Any help would be greatly appreciated.
// TaskCard.vue Child container
<template>
<div
draggable
#dragover.prevent
#dragenter.prevent
#dragstart="setPickupTaskInfo($event, taskIndex, columnIndex)"
#dragend="dropTask($event, taskIndex, columnIndex)"
#click="goToTask(task)"
v-if="isTaskOpen === false"
>
<span class="w-full flex-no-shrink font-bold">
{{ task.name }}
</span>
<p v-if="task.description" class="w-full flex-no-shrink mt-1 text-sm">
{{ task.description }}
</p>
</div>
<div class="task-bg" #click.self="close" v-else>
<router-view />
</div>
</template>
// BoardColumn JS
import TaskCard from "#/components/TaskCard/TaskCard.vue";
export default {
components: {
TaskCard
},
props: ["columnData", "columnIndex"],
methods: {
getColumnName() {
return this.columnData.name;
},
createTask(e, tasks) {
this.$store.commit("CREATE_TASK", {
tasks,
name: e.target.value
});
e.target.value = "";
},
setPickColumnInfo(e, fromColumnIndex) {
e.dataTransfer.effectAllowed = "move";
e.dataTransfer.dropEffect = "move";
e.dataTransfer.setData("from-column-index", fromColumnIndex);
e.dataTransfer.setData("type", "column");
},
moveColumn(fromColumnIndex, toColumnIndex) {
this.$store.commit("MOVE_COLUMN", {
fromColumnIndex,
toColumnIndex
});
},
dropColumn(e, toColumnIndex) {
if (e.dataTransfer.getData("type") === "column") {
this.moveColumn(
e.dataTransfer.getData("from-column-index"),
toColumnIndex
);
console.log(e.dataTransfer.getData("type"));
}
}
}
};
// TaskCard JS
export default {
props: ["task", "taskIndex", "columnIndex"],
data() {
return {
isTaskOpen: false
};
},
methods: {
goToTask(task) {
this.$router.push({ name: "task", params: { id: task.id } });
this.isTaskOpen = true;
},
close() {
this.$router.push({ name: "board" });
this.isTaskOpen = false;
},
setPickupTaskInfo(e, fromTaskIndex, fromColumnIndex) {
e.dataTransfer.effectAllowed = "move";
e.dataTransfer.dropEffect = "move";
e.dataTransfer.setData("from-task-index", fromTaskIndex);
e.dataTransfer.setData("from-column-index", fromColumnIndex);
e.dataTransfer.setData("type", "task");
console.log(e);
},
moveTask(e, toTaskIndex, toColumnIndex) {
const fromColumnIndex = e.dataTransfer.getData("from-column-index");
const fromTaskIndex = e.dataTransfer.getData("from-task-index");
this.$store.commit("MOVE_TASK", {
fromTaskIndex,
fromColumnIndex,
toTaskIndex,
toColumnIndex
});
},
dropTask(e, toTaskIndex, toColumnIndex) {
if (e.dataTransfer.getData("type") === "task") {
console.log(e.dataTransfer.getData("type"));
this.moveTask(e, toTaskIndex, toColumnIndex);
}
}
}
};

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