how to display 2 lists filtered by another field from one model - vue.js

Model: Article.
id.
name.
type: ['code', 'design']
API gets all articles
How can I display two lists:
all articles with type ='Code',
all articles with type = 'Design'
In other words, is it possible to filter the API query
Or is it better to do it on the API side?
Extra: same as above but in a nested environment (ie Articles belong to Category. How to do it on the category detail page.

You can use computed properties. I built a sample component:
EDIT: Took some time to DRY it up.
Parent.vue
<template>
<div class="parent">
<div class="row">
<div class="col-md-6">
<article-list title="Code Articles" :articles="codeArticles" />
</div>
<div class="col-md-6">
<article-list title="Design Articles" :articles="designArticles" />
</div>
</div>
</div>
</template>
<script>
import ArticleList from './ArticleList.vue'
export default {
components: {
ArticleList
},
data() {
return {
articles: [
{
id: 1,
name: 'Article1',
type: 'Code'
},
{
id: 2,
name: 'Article2',
type: 'Design'
},
{
id: 3,
name: 'Article3',
type: 'Code'
},
{
id: 4,
name: 'Article4',
type: 'Design'
},
]
}
},
computed: {
codeArticles() {
return this.articles.filter(article => article.type === 'Code');
},
designArticles() {
return this.articles.filter(article => article.type === 'Design');
}
}
}
</script>
ArticleList.vue
<template>
<div class="two-filtered-lists">
<h5>{{ title }}</h5>
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>NAME</th>
<th>TYPE</th>
</tr>
</thead>
<tbody>
<tr v-for="article in articles" :key="article.id">
<td>{{ article.id }}</td>
<td>{{ article.name }}</td>
<td>{{ article.type }}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
required: true
},
articles: {
type: Array,
required: true
}
}
}
</script>

Related

How to fix the warning "The data property is already declared as a prop. Use prop default value instead" in Vue JS

Company Profile
<dashboard-card
title="Company Profile"
titleColor="primary"
#click.native="componentClicked"
id="company-profile" class="vs-con-loading__container"
:isData= "isData"
>
<div class="w-full text-xl md:text-2xl font-bold">
{{ profile.companyName }}
</div>
<div class="md:text-md">
<div class="py-2">
{{ profile.description }}
</div>
<table class="table-auto border-collapse">
<tr>
<td class="py-1 pr-2 md:pr-4 font-bold">CEO:</td>
<td>{{ profile.ceo }}</td>
</tr>
<tr>
<td class="py-1 pr-2 md:pr-4 font-bold">Exchange:</td>
<td>{{ profile.exchange }}</td>
</tr>
<tr>
<td class="py-1 pr-2 md:pr-4 font-bold">Ticker:</td>
<td class="uppercase text-primary font-semibold">
{{ profile.symbol }}
</td>
</tr>
<tr>
<td class="py-1 pr-2 md:pr-4 font-bold">Industry:</td>
<td>{{ profile.industry }}</td>
</tr>
<tr>
<td class="py-1 pr-2 font-bold">Sector:</td>
<td>{{ profile.sector }}</td>
</tr>
</table>
<div class="pt-2">
<vs-icon
:icon="'icon-globe'"
icon-pack="feather"
class="text-primary pr-2"
></vs-icon>
<a class="text-primary" :href="profile.website" target="blank">
{{ profile.website }}
</a>
</div>
</div>
</dashboard-card>
</template>
<script>
import DashboardCard from "../dashboard-card";
export default {
name: "CompanyProfile",
extends: DashboardCard,
components: { DashboardCard },
props: {
ticker: {
type: String,
default: "",
},
},
data() {
return {
profile: {},
isData: "",
};
},
watch: {
ticker(value) {
this.isData = "";
this.getProfile(value);
},
},
mounted() {
this.isData = "";
this.getProfile(this.ticker);
},
methods: {
getProfile(ticker) {
this.$vs.loading({
container: "#company-profile",
type: "point",
scale: 0.8,
});
this.$api.ticker.profile(ticker).then((response) => {
if (Object.keys(response).length == 0) {
console.log("response is empty");
this.isData = "404";
this.$vs.loading.close("#company-profile > .con-vs-loading");
return;
}
this.profile = response;
this.$vs.loading.close("#company-profile > .con-vs-loading");
}).catch(error => {
console.log("error is in company Profile ", error);
if(error.response) {
this.isData = error.response.status.toString();
} else {
this.isData = "Network Error";
}
this.$vs.loading.close("#company-profile > .con-vs-loading");
});
},
},
};
</script>
Dashboard Card (where I'm applying the Blur effect)
<template>
<BaseTHCard
:title="title"
:titleColor="titleColor"
:actionable="actionable"
:fixed-height="fixedHeight"
#click.native="componentClicked"
>
<blur :isData="isData">
<!-- DEFAULT TRADEHAT CARD HEADER SLOT -->
<div slot="header">
<slot name="header"> </slot>
</div>
<!-- DEFAULT TRADEHAT CARD MEDIA SLOT -->
<div slot="media">
<slot name="media"> </slot>
</div>
<!-- DEFAULT TRADEHAT CARD BODY SLOT -->
<slot></slot>
<!-- DEFAULT TRADEHAT CARD EXTRA CONTENT SLOT -->
<div slot="extra-content">
<slot name="extra-content"> </slot>
</div>
<!-- DEFAULT TRADEHAT CARD FOOTER SLOT -->
<div slot="footer">
<slot name="footer"> </slot>
</div>
</blur>
</BaseTHCard>
</template>
<script>
import BaseTHCard from "#/components/common/base-th-card";
import blur from "../../ticker-dashboard/shared/Blur";
export default {
name: "DashboardCard",
extends: BaseTHCard,
components: {
BaseTHCard,
blur
},
props: {
isData: {
type: String,
},
title: {
type: String,
default: null,
},
titleColor: {
type: String,
default: "white",
},
fixedHeight: {
type: Boolean,
default: false,
},
actionable: {
type: Boolean,
default: false,
},
},
};
</script>
I'm getting two following warnings from vue:-
I am setting the isData data option in the CompanyProfile component and passing it as a prop to DashboardCard component and sending that isData prop value to the blurr component. The functionality works fine but I'm getting the above mentioned warnings from vue. What should be the approach to fix them.

How to store array to Vuex in VueJs

Can someone tell me how to write an array of objects in Vuex
I will explain the essence
In this situation, I need to create an order management system
I have an array of products with different data
This array I get from the server using axios request
Via v-for, I displayed this array in the select option html tag
Next, by clicking on the html option tag, I need to add the product to the data table
Also, with the addition of a specific product to the table, it is necessary that the product for which a click is made is recorded in the Vuex store, but not with rewriting, but with addition to existing data
Next, in synchronization with the addition to the Vuex store, information is output from the Vuex store to the table
this is my code in Vue Component
<div class="row">
<div class="col-md-8">
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th>QTY</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-4">
<form>
<div class="form-group">
<label for="products">Select Products</label>
<select v-model="orderData" #change="addOrderData" id="products" class="form-control">
<option v-for="product in products" multiple v-bind:value="{productId: product.id, name: product.name, price: product.price}">{{product.name}}</option>
</select>
<pre>{{orderData}}</pre>
</div>
</form>
</div>
</div>
data() {
return {
selected: '',
formData: {
userId: ''
},
orderData: {
productId: [],
price: [],
total: [],
quantity: []
}
}
},
methods: {
addOrderData()
{
let data = {
productId: this.orderData.productId,
name: this.orderData.name,
price: this.orderData.price,
}
this.$store.commit('orders/setOrderProduct', data)
}
},
this is my code in Vuex store
function initialState () {
const orderProducts = [];
return {
orderProducts
}}
const getters = {
orderProducts(state)
{
return state.orderProduct;
},};
const mutations = {
setOrderProduct(state, orderProduct)
{
state.orderProduct = orderProduct;
}};
If I understand you correctly, please check the following:
template:
<select v-model="orderData" #change="addOrderData">
<option v-for="(product) in products" :key="product.productId" :value="{productId: product.productId, name: product.name, price: product.price}">
{{product.productId}} - {{product.name}}</option>
</select>
<br /><br />
<table>
<thead>
<tr>
<th>name</th>
<th>price</th>
</tr>
</thead>
<tbody v-if="orderProducts.length > 0">
<tr v-for="(item, index) in orderProducts" :key="index">
<td>{{item.name}}</td>
<td>{{item.price}}</td>
</tr>
</tbody>
<tbody v-else>
<tr>
<td colspan="2">No products to display</td>
</tr>
</tbody>
</table>
code:
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
orderProducts: []
},
mutations: {
addProduct(state, payload) {
state.orderProducts.push(payload);
}
}
})
new Vue({
store,
el: '#app',
data() {
return {
products: [{
productId: 1,
name: 'Product One',
price: 10
},
{
productId: 2,
name: 'Product Two',
price: 15
}
],
orderData: {
productId: [],
price: [],
total: [],
quantity: []
}
};
},
computed: {
orderProducts() {
return this.$store.state.orderProducts;
}
},
methods: {
addOrderData() {
this.$store.commit('addProduct', this.orderData);
}
}
});
The idea is when change event is triggered by selecting an option, you commit mutation to the store with the selected product as payload. The orderProducts computed property will refresh, and the table will get the latest data. You can check this jsfiddle.

Vue data passed from parent to child not accessing

I have an app.vue file in which i have the parent codes.
<template>
<div id="app" class="small-container">
<h1>Employees</h1>
<employee-form #add:employee="addNewEmployee" />
<employee-table :employees="employees" />
</div>
</template>
<script>
import EmployeeTable from '#/components/EmployeeTable.vue'
import EmployeeForm from '#/components/EmployeeForm.vue'
export default {
name: 'app',
components: {
EmployeeTable,
EmployeeForm,
},
data() {
return {
employees: [
{
id: 1,
name: 'Richard Hendricks',
email: 'richard#piedpiper.com',
},
{
id: 2,
name: 'Bertram Gilfoyle',
email: 'gilfoyle#piedpiper.com',
},
{
id: 3,
name: 'Dinesh Chugtai',
email: 'dinesh#piedpiper.com',
},
],
misc:'testbro',
}
},
methods:{
addNewEmployee: function( new_employee){
var length = Object.keys(this.employees).length;
length = length+1;
this.employees.push({id:length,name:new_employee.name,email:new_employee.email});
}
}
}
</script>
I am passing two parameters in data() method to child EmployeeTable.
<template>
<div id="employee-table">
<table>
<thead>
<tr>
<th>Employee name</th>
<th>Employee email</th>
</tr>
</thead>
<tbody>
<tr v-for="employee in employees" :key="employee.id">
<td>{{ employee.name }}</td>
<td>{{ employee.email }}</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>Misc Label</td>
<td>{{misc}}</td>
</tr>
</tfoot>
</table>
</div>
</template>
<script>
export default {
name: 'employee-table',
inheritAttrs: false,
props: {
employees: Array,
misc: String,
},
}
</script>
The Employee name and email is displayed, but the misc {{misc}} is not displayed. Am i accessing the prop incorrectly ?
You're not passing misc to the child component, you have:
<employee-table :employees="employees" />
But you need:
<employee-table :employees="employees" :misc="misc" />
It is not that you are accessing the prop incorrectly, you are actually not passing the misc to the child component at all. You are only passing employees as a prop if you read carefully:
<employee-table :employees="employees" />
Correct code would look like this (in parent):
<employee-table :employees="employees" :misc="misc" />

Update Table Item Quantity

Guys I'm starting with Vue and I'm having a little difficulty. In the image below I have a table with some items and when I will increase the amount of the item Orange for example is increased all other items, how to fix it?
enter image description here
My code
new Vue({
el: '#app',
data() {
return {
quantity: 1,
fruits: [
{ Code: 1, Name: 'Abacaxi', Price: "50.00" },
{ Code: 2, Name: 'Abacate', Price: "50.00" },
{ Code: 3, Name: 'Morango', Price: "60.00" },
{ Code: 4, Name: 'Maçã', Price: "17.00" },
{ Code: 5, Name: 'Laranja', Price: "30.00" }
]
}
},
methods: {
add() {
this.quantity++
},
remove() {
if(this.quantity === 0) {
this.quantity = 0
} else {
this.quantity--
}
}
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<template>
<div class="user-list">
<table>
<thead>
<tr>
<th>#Code</th>
<th>Name</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr v-for="fruit in fruits" :key="fruit.Code">
<td>
<button #click="remove">-</button>
<input type="text" :value="quantity">
<button #click="add">+</button>
</td>
<td>{{ fruit.Name }}</td>
<td>{{ fruit.Price }}</td>
</tr>
</tbody>
</table>
</div>
</template>
</div>
You should just need to have a quantity on each item in your list. You'd then pass the relevant item to add or remove.
new Vue({
el: '#app',
data() {
return {
fruits: [
{ Code: 1, Name: 'Abacaxi', Price: "50.00", quantity: 1 },
{ Code: 2, Name: 'Abacate', Price: "50.00", quantity: 1 },
{ Code: 3, Name: 'Morango', Price: "60.00", quantity: 1 },
{ Code: 4, Name: 'Maçã', Price: "17.00", quantity: 1 },
{ Code: 5, Name: 'Laranja', Price: "30.00", quantity: 1 }
]
}
},
methods: {
add(fruit) {
fruit.quantity++
},
remove(fruit) {
if(fruit.quantity !== 0) {
fruit.quantity--
}
}
}
})
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<div id="app">
<template>
<div class="user-list">
<table>
<thead>
<tr>
<th>#Code</th>
<th>Name</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr v-for="fruit in fruits" :key="fruit.Code">
<td>
<button #click="remove(fruit)">-</button>
<input type="text" v-model.number="fruit.quantity">
<button #click="add(fruit)">+</button>
</td>
<td>{{ fruit.Name }}</td>
<td>{{ fruit.Price }}</td>
</tr>
</tbody>
</table>
</div>
</template>
</div>
I've also switched :value to v-model.number, which seems more likely to be what you'd want though it's not directly related to the problem mentioned in the question.

dynamically call an object property in a v-for loop

so i ran into a problem again,
i want to make a table component where you can send a array to the component, and it will render a table for you
we set it up like this
<template>
<section class="container">
<Apptable :search="true" :loader="true" title="User data" :data="users"/>
</section>
</template>
<script>
import Apptable from "~/components/table.vue";
export default {
components: {
Apptable
},
data() {
return {
users: [
{
id: 1,
name: "Lars",
Adres: "hondenstraat 21",
phone: "06555965"
},
{
id: 1,
name: "John",
Adres: "verwelstraat 35",
phone: "06555965"
}
]
};
}
};
</script>
i send data to the component and loop it from there like this
<template>
<section class="container">
<h2 v-if="title">{{title}}</h2>
<input v-if="search" class="search" placeholder="Search">
<button v-if="loader" class="update" #click="dialog = true">Update</button>
<table class="table">
<thead>
<tr class="tableheader">
<th v-for="(item, index) in Object.keys(data[0])" :key="index">{{item}}</th>
</tr>
</thead>
<tbody>
<tr class="userdata" v-for="(item, index) in data" :key="index">
<td v-for="(name, index) in Object.keys(data[index])" :key="index">{{//TODO: I WANT TO SELECT THE ITEM.DYNAMIC PROPERTY}}</td>
</tr>
</tbody>
</table>
<loader v-if="loader" :trigger="dialog"/>
</section>
</template>
<script>
import loader from "~/components/loader.vue";
export default {
components: {
loader
},
data() {
return {
dialog: false
};
},
watch: {
dialog(val) {
if (!val) return;
setTimeout(() => (this.dialog = false), 1500);
}
},
props: {
data: {
type: Array,
required: true
},
title: {
type: String,
required: false,
default: false
},
loader: {
type: Boolean,
required: false,
default: false
},
search: {
required: false,
type: Boolean,
default: true
}
}
};
</script>
so if you look at the table. were i left the todo, if i put in the {{item}} in the todo place. i will get this in my column
enter image description here
but i want to select the key of the object dynamically. but if i put {{item.name}} in the todo place it will not select the key dynamically.
so the point is that i want to dynamically call a property from the object in the v-for so the columns will get the data in the cells.
You should use item[name] instead of item.name
<tbody>
<tr class="userdata" v-for="(item, index) in data" :key="index">
<td v-for="(name, nIndex) in Object.keys(data[index])" :key="nIndex">
{{ item[name] }}
</td>
</tr>
</tbody>