Using VueUse composables with the component options api - vue.js

Is possible to use VueUse with the Options API style? All examples are using Composition one.
I try to use computedAsync. The stock function returns a Promise<VendorItem[]>.
Using Composition API as the example works fine :
const vendors = computedAsync(
async () => {
return await stock(db);
},
[],
);
But this does not work when I try to use it using the Options API style:
export default defineComponent({
name: "VendorsList",
computed: {
vendors() {
return computedAsync(
async () => {
return await stock(db);
},
[],
)
}
}
})
In the last case, vendors does not contain the array.
I try to debug it adding:
<div v-for="vendor in vendors" class="">
<pre>{{ JSON.stringify(vendor, null, 4)}}</pre>
---------------
</div>
and the output is something like this
false
---------------
---------------
true
---------------
[
{
"id": "00PIL9ljDrgRZrP8MOkl",
"language": "en"
},
{
"id": "00ZnoY0NXb1ZjQMFQJCC",
"language": "en"
},
{
"id": "01hO4DKjAprwP8zwUpZU",
"language": "en"
}
]
---------------
[
{
"id": "00PIL9ljDrgRZrP8MOkl",
"language": "en"
},
{
"id": "00ZnoY0NXb1ZjQMFQJCC",
"language": "en"
},
{
"id": "01hO4DKjAprwP8zwUpZU",
"language": "en"
}
]
---------------

Simple anwser is no, you can't use vue composables (including VueUse ones) in the option api except for the setup function. Source in the vue documentation.
The computedAsync composable already creates a computed, so here you are trying to create a computed of a computed. Just move it in the setup function and it will work.
export default defineComponent({
name: "VendorsList",
setup() {
const vendors = computedAsync(async () => await stock(db), [])
return { vendors }
},
})

Related

Empty API Response When Deleting Payment Method ID In Shopware 6 Administration

When I try deleting the paymentMethodId from sales_channel_payment_method table I get an empty response from the API and the payload object DELETE http://localhost/api/sales-channel-payment-method/[object Object] seems empty too.
Below is my Vue js method
const { Component} = Shopware;
import template from './pau-settings-page.html.twig';
Component.register('pau-settings-page', {
template,
inject: [
'repositoryFactory'
],
metaInfo() {
return {
title: this.$createTitle()
};
},
computed: {
salesChannelPaymentMethodRepository() {
return this.repositoryFactory.create('sales_channel_payment_method');
},
},
methods: {
deletePaymentMethodIdHeadless(){
const identity = {
fieldCount: 2,
fieldsString: "05cde2abfe744bffaf47ad71f8a49270, f6dd50230aa145adb6b73801d4bcf31b",
fields: ['salesChannelId', 'paymentMethodId']
};
this.salesChannelPaymentMethodRepository.delete(
identity, Shopware.Context.api
);
},
}
});
Image of The Response
You're trying to remove a many-to-many mapping. These feature two distinct primary keys, both foreign keys of the related tables. You already have the right idea. The regular delete endpoint only works with single primary keys, hence why you get the malformed url.
To delete the mappings you may use the syncService instead.
const { Component} = Shopware;
import template from './pau-settings-page.html.twig';
Component.register('pau-settings-page', {
template,
inject: [
'repositoryFactory',
'syncService',
],
metaInfo() {
return {
title: this.$createTitle()
};
},
computed: {
salesChannelPaymentMethodRepository() {
return this.repositoryFactory.create('sales_channel_payment_method');
},
},
methods: {
deletePaymentMethodIdHeadless() {
const payload = [{
action: 'delete',
entity: 'sales_channel_payment_method',
payload: [
{
salesChannelId: '05cde2abfe744bffaf47ad71f8a49270',
paymentMethodId: 'f6dd50230aa145adb6b73801d4bcf31b'
},
],
}];
this.syncService.sync(payload, {}, { 'single-operation': 1 });
},
},
});

Vue data fetched object not available in setup()

I am rendering a jspreadsheet component with data fetched from fastapi.
<template>
<h1>Synthèse évaluation fournisseur</h1>
<VueJSpreadsheet v-model="data.table" :options="myOption" />
{{ data.columns }}
</template>
<script>
import { reactive, onMounted, isProxy, toRaw, ref } from "vue";
import VueJSpreadsheet from "vue3_jspreadsheet";
import "vue3_jspreadsheet/dist/vue3_jspreadsheet.css";
export default {
components: {
VueJSpreadsheet,
},
setup() {
// var intervalID = setInterval(init, 3000);
var data = reactive({
table: [],
columns: [],
});
async function load_data() {
const response = await fetch("http://LOCALHOST:8080/supplier_overview");
return await response.json();
}
load_data().then((response)=>{
data.table=JSON.parse(response.result.data)
data.columns=(response.result.columns)
});
console.log(data.columns)
const myOption = ref({
columns: data.columns,
search: true,
filters: true,
includeHeadersOnDownload: true,
includeHeadersOnCopy: true,
defaultColAlign: "left",
tableOverflow: true,
tableHeight: "800px",
parseFormulas: true,
copyCompatibility: true,
});
return {
data,
myOption,
};
},
};
</script>
whereas data.columns is rendered correctly in the template, I cannot pass it to myOptions .
The proxy is empty with console.log(data.columns) whereas {{data.columns}} returns the correct array :
[ { "title": "period" }, { "title": "fournisseur" }, { "title": "Qualité" }, { "title": "Rques Qualité" }, { "title": "Logistique" }, { "title": "Rques Logistique" }, { "title": "Cout" }, { "title": "Rques Cout" }, { "title": "Système" }, { "title": "Rques Système" }, { "title": "Mot QLCS" }, { "title": "Note" }, { "title": "Rques" } ]
Any ideas why I cannot passed it correctly to myOptions ?
This problem has nothing to do with the variable myOptions
setup() {
async function load_data() {
const response = await fetch("http://LOCALHOST:8080/supplier_overview");
return await response.json();
}
//the function is async, 1 will be called after 2, so the result is empty
load_data().then((response)=>{
data.table=JSON.parse(response.result.data)
//1
data.columns=(response.result.columns)
});
//2
console.log(data.columns)
}

VueJS - How can i use the response of API in vue-select

I want to use the response coming from the API in v-select. Here is a scenario i want to use the API call from component A to component B, rather than calling it again in the component B.
Component A:
methods: {
forVselect (id) {
this.$http.get(`/type/${id}`)
.then((res) => {
this.icecream = res.data})
.catch((e) => {console.log(e)})
}
},
mounted (){
this.forVselect (this.$route.params.un_id)
}
Component B:
<template>
<div class="The V-select">
<vselect v-model="input1" :options="[{label: 'Vanilla' , value: 'vanilla'}]" :dir="$vs.rtl ? 'rtl' : 'ltr'" />
</div>
</template>
<script>
import vselect from 'vue-select'
...
input1: null,
icecream: null
...
methods: {
forVselect (id) {
this.$http.get(`/type/${id}`)
.then((res) => {
this.icecream = res.data})
.catch((e) => {console.log(e)})
}
},
mounted (){
this.forVselect (this.$route.params.un_id)
}
</script>
As you can see my Component B i have hard coded as 'vanilla' in v-select, rather i want to use the data coming from the API, i want to know how it can be done.
Here is my Api response:
[
{
"id": 3,
"flavor": "vanilla",
"price": "150",
"taste": "super",
"cream": "high",
"investments": null,
},
{
"id": 8,
"flavor": "chocolate",
"price": "250",
"taste": "super high",
"cream": "fantastic",
"investments": "too high",
}
...
]
Please do help me. I tried just by using label: type.flavor but nothing was displayed. And in order to make code effective i want to use the response coming from API call made in component A
use just have to add a variable at the place of option as shown below:
<template>
<div class="The V-select">
<vselect v-model="input1" :options="icecream" :dir="$vs.rtl ? 'rtl' : 'ltr'" />
</div>
</template>
<script>
import vselect from 'vue-select'
...
input1: null,
icecream: null
...
methods: {
forVselect (id) {
this.$http.get(`/type/${id}`)
.then((res) => {
this.icecream = res.data})
.catch((e) => {console.log(e)})
}
},
mounted (){
this.forVselect (this.$route.params.un_id)
}
</script>
and also you need modify your api response... response like:
[
{
"id": 3,
"flavor": "vanilla",
"price": "150",
"taste": "super",
"cream": "high",
"investments": null,
"label": "Vanilla" ,
"value": "vanilla"
},
{
"id": 8,
"flavor": "chocolate",
"price": "250",
"taste": "super high",
"cream": "fantastic",
"investments": "too high",
"label": "Chocolate" ,
"value": "chocolate"
}
...
]
you need to modify response like that from server side or client side when response received...
If you don't want to modify your json response so atleat you need to add 2 additional key which is label & value key so that you can use...
I tried to use :getOptionKey="getOptionKey" so I could change the default "id" vue-select was requesting but to me the only think that worked is to consider the object attribute "value" as the default.
So since I was working with array of objects being returned from API, what I did was:
// loading from API
dataUtils.find(this.$route.params.id).then((data) => {
this.mySelectObject = {
name: data.name,
value: data.id
}
and used the following within html:
<v-select
label="name"
:options="myOptions"
v-model="mySelectObject"
#input="setSelected" //created this method to change selection
/>

How to get the correct object in an nested array in Vue.js?

I use Axios to display a JSON data and I have succeeded. But I want to show an object based on date and time, it shows now all data and I need to filter it.
So I want to look at today's date and show the object based on that, so I want to show the next upcoming event. (24/05/2020)
What I currently have:
Json:
{
"doc": [
{
"data": {
"events": {
"18807612": {
"_dt": {
"_doc": "time",
"time": "18:45",
"date": "14/05/20",
"tz": "UTC",
"tzoffset": 0,
"uts": 1566067500
},
"week": 33,
"teams": {
"home": {
"name": "name 1",
"mediumname": "name1",
"uid": 3014
},
"away": {
"name": "name 2",
"mediumname": "name 2",
"uid": 3020
}
}
},
"18807618": {
"_dt": {
"_doc": "time",
"time": "18:45",
"date": "24/05/20",
"tz": "UTC",
"tzoffset": 0,
"uts": 1566067500
},
"week": 33,
"teams": {
"home": {
"name": "name 1",
"mediumname": "name1",
"uid": 3014
},
"away": {
"name": "name 2",
"mediumname": "name2",
"uid": 3020
}
}
}
}
}
}
]
}
Store:
async loadPosts({ commit }) {
// Define urls pages
const urlEvents = 'http://api.example.com/302020';
// Set pages
const [
responseEvents
] = await Promise.all([
// Responses pages
this.$axios.get(urlEvents)
]);
// variables pages
this.events = responseEvents.data.doc[0].data.events
// mutations pages
commit('SET_EVENTS', this.events)
}
},
mutations: {
SET_EVENTS (state, events) {
state.events = events;
}
}
And to show the data I use this:
import {mapState} from 'vuex';
export default {
name: 'NextMatch',
mounted() {
this.$store.dispatch('loadPosts')
},
computed: {
...mapState([
'events'
])
}
}
<h1>{{events}}</h1>
But this shows all data, and what I try to get is the first upcoming event for the object with the "uid": 3014.
So I want to show the date, time and names of the home and away team.
How can I get the correct data by filtering the data?
Something like this or similar to this should work:
In your Vue component's <template>:
`<h1>{{selectedEvent._dt.date}}</h1>`
In your Vue component's <script>:
props: {
eventID: {
type: Number,
default: 3014
},
},
computed: {
...mapState([
'events'
]),
eventsArr(){
if (!this.events) return {} //make sure Object.entries gets object.
return Object.entries(this.events)
},
selectedEvent(){
const selectedArr = this.eventsArr.find(([eID, e]) => e.teams.home.uid === this.eventID)
return selectedArr[1]
}
}

vue-table-2 with Vuex - not able to change the count property

I'm using the vue-table-2 component : https://github.com/matfish2/vue-tables-2 and I'm struggling to make it work as I want.
I have an API (using API Platform) which is already making all the pagination works. So when I fetch for the first time my list of companies it gives the first ten results + the total rows. I store all of this in my vuex store and I am able to display the list in my table (with useVuex false or true so I don't really understand how this parameter works). The issue is I cannot paginate because I only got ten results and can't get the total rows count to change so I do not get the pagination element at the bottom and can't bind something to it to fetch the other pages later.
Since I'm pretty new to VueJs I can't figure out how this should work with my API. Here is my code so far:
My DataTable element :
<v-client-table name="company" :columns="columns" :data="companies" :options="options" :theme="theme" id="dataTable">
<b-button slot="actions" slot-scope="props" variant="secondary" size="sm" class="btn-pill">Edit</b-button>
</v-client-table>
And my script :
<script>
import Vue from 'vue'
import { ClientTable, Event } from 'vue-tables-2'
import { mapGetters } from 'vuex'
Vue.use(ClientTable)
export default {
name: 'DataTable',
components: {
ClientTable,
Event,
},
data: function() {
return {
columns: ['name', 'actions'],
options: {
headings: {
name: 'Name',
actions: 'Actions',
},
sortable: ['name'],
filterable: ['name'],
sortIcon: {
base: 'fa',
up: 'fa-sort-asc',
down: 'fa-sort-desc',
is: 'fa-sort',
},
pagination: {
chunk: 5,
edge: false,
nav: 'scroll',
},
},
useVuex: true,
theme: 'bootstrap4',
template: 'default',
}
},
computed: {
...mapGetters({
companies: 'companyModule/companies',
totalCompanies: 'companyModule/totalCompanies',
}),
},
}
</script>
This is in my component loading the data where I specify how many items per page I want my api to send me and the page I want:
created() {
this.$store.dispatch('companyModule/FETCH_COMPANIES', {
page: 1,
nbItemPerPage: 10,
})
},
My store looks like this:
import ApiService from '#/services/APIService'
export const companyModule = {
strict: true,
namespaced: true,
state: {
companies: [],
totalCompanies: 0,
},
getters: {
companies: state => state.companies,
totalCompanies: state => state.totalCompanies,
},
mutations: {
SET_COMPANIES(state, data) {
state.companies = data.companies
state.totalCompanies = data.totalCompanies
},
},
actions: {
FETCH_COMPANIES(context, payload) {
payload.entity = 'companies'
return ApiService.get(payload).then(data => {
context.commit('SET_COMPANIES', data)
})
},
},
}
When I received my data, I stored everything in my companies state and for now I'm storing everything I'm getting from my API and this looks like this :
{
"#id": "/api/admin/companies/1",
"#type": "Company",
"id": 1,
"name": "Test Company",
}
Thanks in advance for your help !
watch: {
'companies': {
handler (newValue, oldValue) {
this.totalRows=this.companies.length;
},
deep: true
}
},
Vue “watch” is a powerful reactive option attribute to the vue framework that helps front-end developers listen to changes made on a value and then react to it.
So, once the totalRows is set, you can assign it to the table attributes and the table will change accordingly.
For my case, I used it for bootstrap table as follows:
<b-pagination
:total-rows="totalRows"
:per-page="perPage"
></b-pagination>