I am trying to upload the branch tests, but I can't get through an if of a computed one.
this is my widget code and my test code
but it doesn't happen to me because of this if:
if (!debit?.dueDate && !debit?.rDate) {
return '';
nor this way: return situation;
widget::
<script>
export default {
name: 'w-movement-detail-debit',
components: {
CListIconItem,
},
props: {
debit: { type: Object },
movement: { type: Object },
},
computed: {
debitType({ debit }) {
const situation = debit?.situation?.toUpperCase();
const types = ['CHARGED', 'RETURNED'];
if (!types.includes(situation)) {
return situation;
}
return this.$t(`DEBIT.TYPE.${situation}`);
},
itemDate({ debit }) {
if (!debit?.dueDate && !debit?.rDate) {
return '';
}
const str = debit?.dueDate || debit?.rDate;
const day = str.slice(nthIndex(str, '-', 2) + 1, nthIndex(str, '-', 2) + 5);
const month = str.slice(nthIndex(str, '-', 2) - 2, nthIndex(str, '-', 2));
const year = str.slice(nthIndex(str, '-', 1) - 4, nthIndex(str, '-', 1));
return `${day} - ${month} - ${year}`;
},
},
};
</script>
test::
import { shallowMount } from '#vue/test-utils';
import Component from '#widgets/products/debit/w-movement-detail-debit.vue';
const newInstance = createPristineVue();
const { localVue } = newInstance;
describe('w-movement-detail-debit.vue', () => {
let wp;
beforeEach(() => {
wp = shallowMount(Component, {
localVue,
propsData: {
debit: {
avoidable: true,
concept: '',
creditorName: 'JAVIER NEW PROCESS',
debtorAccount: '********************7324',
debtorName: 'RECIBO DE PRUEBA',
dueDate: '2022-07-04',
externalCreditorReference: 'RECIBO PRUEBA',
id: '2685500001',
internalCreditorReference: 'ES4451308912157W',
operationDate: '2022-07-04',
situation: 'charged',
typeId: 'RZ',
},
movement: {
id: '1234',
operationDate: '2020-01-05',
valueDate: '2020-01-06',
type: { name: 'RECIBO DOMICILIADO' },
},
},
});
});
it('has a name equal to w-movement-detail-debit', () => {
expect(wp.vm.$options.name).toBe('w-movement-detail-debit');
});
});
Related
This is probably just a basic vue question, but I am using Vue Apollo.
I have this component that is setup like this:
export default defineComponent({
name: "Products",
components: { Product },
props: {
categorySlug: {
type: String,
required: true,
},
},
setup(props) {
const { categorySlug } = toRefs(props);
const page = ref(1);
const skip = ref(0);
const result = reactive({ search: null, laoding: null, error: null });
Object.assign(result, useListProducts(categorySlug.value, page.value));
const more = () => {
skip.value += 12;
page.value += 1;
Object.assign(result, useListProducts(categorySlug.value, page.value));
};
return { ...toRefs(result), ...{ skip, more } };
},
});
As you can see I have a reactive object setup which is assigned to when the component setup method is invoked:
const result = reactive({ search: null, laoding: null, error: null });
Object.assign(result, useListProducts(categorySlug.value, page.value));
In my template, I iterate over the results like this:
<base-fade-up class="row" :duration="0.1" tag="div">
<v-col
cols="12"
xl="2"
v-for="(product, index) in products"
:key="product.id"
:data-index="index"
:data-skip="skip"
>
<product class="product" :product="product"></product>
</v-col>
</base-fade-up>
The problem I have, is that I want to add a more button:
<v-btn color="primary" #click="more()" v-if="search.hasMoreResults"
>Show more</v-btn
>
When pressed, it executes the more() method:
const more = () => {
skip.value += 12;
page.value += 1;
Object.assign(result, useListProducts(categorySlug.value, page.value));
};
As you can see, I am now getting page 2, so page one products are no longer in the search object.
What I would like to do is get a copy of the products from the first query and then add to them every time the more button is pressed.
I tried this:
setup(props) {
const { categorySlug } = toRefs(props);
const page = ref(1);
const skip = ref(0);
const products = ref([]);
const result = reactive({ search: null, laoding: null, error: null });
Object.assign(result, useListProducts(categorySlug.value, page.value));
const more = () => {
skip.value += 12;
page.value += 1;
Object.assign(result, useListProducts(categorySlug.value, page.value));
};
products.value.push(result.search.value.items);
return { ...toRefs(result), ...{ products, skip, more } };
},
but when I run this code, I get an error:
[Vue warn]: Error in data(): "TypeError: Cannot read property 'value' of null"
which is complaining about result.search.value in this line:
products.value.push(result.search.value.items);
I believe it's because the promise has not been resolved.
I am using Apollo's useResult method inside my useListProducts which looks like this:
import { useQuery, useResult } from "#vue/apollo-composable";
import * as listProducts from "#/graphql/api/query.products.gql";
export function useListProducts(slug: string, page = 1, itemsToShow = 12) {
const request: {
identifier?: string;
searchTerm: string;
itemsToShow: number;
page: number;
filters: any;
facets: string[];
} = {
searchTerm: "*",
itemsToShow,
page,
filters: [
{
key: "CategorySlug",
value: `'${slug}'`,
},
],
facets: ["Criteria/Attribute,count:100"],
};
const { result, loading, error } = useQuery(listProducts, {
search: request,
});
const search = useResult(result, null, (data) => data.search);
return { search, loading, error };
}
Can anyone tell me what I am doing wrong?
After some digging around, I found something in the documentation about pagination (which is essentially what I am doing), so because of that I managed to adjust my code to this:
export default defineComponent({
name: "Products",
components: { Product },
props: {
categorySlug: {
type: String,
required: true,
},
},
setup(props) {
const { categorySlug } = toRefs(props);
const page = ref(1);
const skip = ref(0);
const { search, loading, error, fetchMore } = useListProducts(
categorySlug.value,
page.value
);
const more = () => {
skip.value += 12;
page.value += 1;
const request = {
...params,
...{
page: page.value,
filters: [
{
key: "CategorySlug",
value: `'${categorySlug.value}'`,
},
],
},
};
fetchMore({
variables: { search: request },
updateQuery: (prev, { fetchMoreResult }) => {
if (!fetchMoreResult) return prev;
//return fetchMoreResult;
console.log(fetchMoreResult);
return Object.assign({}, prev, {
search: {
hasMoreResults: fetchMoreResult.search.hasMoreResults,
total: fetchMoreResult.search.total,
facets: [...prev.search.facets, ...fetchMoreResult.search.facets],
items: [...prev.search.items, ...fetchMoreResult.search.items],
__typename: prev["__typename"],
},
});
},
});
};
return { search, loading, error, skip, more };
},
});
Which satisfies everything Estus mentioned in the comments, but it does throw an error, which I will create a new post about :D
I'm trying to filter table of movies by director ID. The structure of a movie is:
{
id: 1,
title: "They All Lie",
releaseYear: 1989,
director: {
id: 18,
firstName: "Darci",
lastName: "Overill",
nationality: "China",
birthdate: "07/13/1973",
},
},
I want to filter the table using the $route.params.id. I have the following code:
<script>
import axios from "axios";
export default {
data: function () {
return {
directorId: this.$route.params.id,
director: {},
movies: [],
};
},
mounted: function () {
this.getDirector();
this.getMovies();
},
methods: {
getMovies: function () {
let url = "http://localhost:8080/movies/movies";
axios.get(url).then((response) => {
this.movies = response.data;
});
},
getDirector: function () {
let url = "http://localhost:8080/movies/directors/" + this.directorId;
axios.get(url).then((response) => {
this.director = response.data;
});
},
},
computed: {
filteredMovies: function () {
var v = this.$route.params.id;
alert(v);
return this.movies.filter(movie => movie.director.id === v);
},
}
};
</script>
I'm trying to access this.$route.params.id in the filteredMovies function. It works in the .alert function but I can't get the return this.movies.filter(movie => movie.director.id === v); to work. The filtering doesn't work. Any ideas please?
If you want a more elegant solution for parsing the router param id check tis out:
index.js(router file)
{
path: '/directors/:id',
name: 'Directors',
component: myComponentName,
props: (route) => {
const id = Number.parseInt(route.params.id);
return { id }
}
}
Component.vue
props: {
id: {
required: true,
type: Number,
}
With the above implementation you can remove the parsing in the component and also instead of doing this:
this.$route.params.id;
Now you can do:
this.id
And you have the parsed id with best practises ;)
Cheers
This is a very basic question but I'm not getting anywhere...
Doing a simple shopping cart with Vue and Vuex. I had the products hard-coded in the state but now I'm trying to do an axios call and add that result to the state. I have the axios function and I'm trying to load the function and have the JSON result appended to the array all.
How do I put the result of loadItems() into the all array? Thank you
EDIT: I have updated with my entire vuex file.
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
import * as types from './mutation-types'
Vue.use(Vuex)
const debug = process.env.NODE_ENV !== 'production'
// axios call
const api = {
loadItems() {
// Init variables
var self = this
var app_id = "asdfasf";
var app_key = "asdfasfaf";
this.items = []
axios.get(
"https://api.airtable.com/v0/"+app_id+"/Products",
{
headers: { Authorization: "Bearer "+app_key }
}
).then(function(response){
self.items = response.data.records.map((item)=>{
return {
id: item.id,
...item.fields
}
})
}).catch(function(error){
console.log(error)
})
}
}
// initial state
const state = {
added: [],
all: []
}
// getters
const getters = {
allProducts: state => state.all, // would need action/mutation if data fetched async
getNumberOfProducts: state => (state.all) ? state.all.length : 0,
cartProducts: state => {
return state.added.map(({ id, quantity }) => {
const product = state.all.find(p => p.id === id)
return {
name: product.name,
price: product.price,
quantity
}
})
}
}
// actions
const actions = {
addToCart({ commit }, product){
commit(types.ADD_TO_CART, {
id: product.id
})
},
removeFromCart({ commit }, product){
commit(types.REMOVE_FROM_CART, {
id: product.id
})
}
}
// mutations
const mutations = {
[types.ADD_TO_CART] (state, { id }) {
const record = state.added.find(p => p.id === id)
if (!record) {
state.added.push({
id,
quantity: 1
})
} else {
record.quantity++
}
},
[types.REMOVE_FROM_CART] (state, { id }) {
const record = state.added.find(p => p.id === id)
if (!record) {
state.added.pop({
id,
quantity: 1
})
} else {
record.quantity--
}
},
}
// one store for entire application
export default new Vuex.Store({
state,
strict: debug,
getters,
actions,
mutations
})
This is a little approach to your goal:
You can access with state.yourStateNameVariable or better make a getter and commit to get/set value from that state.
Observations:
[types.ADD_TO_CART] is not a good name for commit, maybe addToCart and removeFromCart?
You dont need to save in items your response from axios, you can directly after resolve send to all state with state.all = yourdata or better, add mutation
setAllData({ state }, data){
state.all = data
}
I do not fixed all your code but here you are an approach:
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
import * as types from './mutation-types'
Vue.use(Vuex)
const debug = process.env.NODE_ENV !== 'production'
export default new Vuex.Store({
state:{
added: [],
all: [
{
id: 'cc919e21-ae5b-5e1f-d023-c40ee669520c',
name: 'COBOL 101 vintage',
description: 'Learn COBOL with this vintage programming book',
price: 399
},
{
id: 'bcd755a6-9a19-94e1-0a5d-426c0303454f',
name: 'Sharp C2719 curved TV',
description: 'Watch TV like never before with the brand new curved screen technology',
price: 1995
},
{
id: '727026b7-7f2f-c5a0-ace9-cc227e686b8e',
name: 'Remmington X mechanical keyboard',
description: 'Excellent for gaming and typing, this Remmington X keyboard ' +
'features tactile, clicky switches for speed and accuracy',
price: 595
}
]
},
getters: {
allProducts: state => state.all, // would need action/mutation if data fetched async
getNumberOfProducts: state => (state.all) ? state.all.length : 0,
cartProducts: state => {
return state.added.map(({ id, quantity }) => {
const product = state.all.find(p => p.id === id)
return {
name: product.name,
price: product.price,
quantity
}
})
}
},
mutations: {
setAllData({ state }, data){
state.all = data
},
[types.ADD_TO_CART] ({ state }, id) {
const record = state.added.find(p => p.id === id)
if (!record) {
state.added.push({
id,
quantity: 1
})
} else {
record.quantity++
}
},
[types.REMOVE_FROM_CART] ({ state }, id) {
const record = state.added.find(p => p.id === id)
if (!record) {
state.added.pop({
id,
quantity: 1
})
} else {
record.quantity--
}
}
},
actions:{
loadItems({getters, commit}, somethingYouReceive) {
// Init variables
var self = this
var app_id = "adsfasfasgag";
var app_key = "agasdgagasgasg";
this.items = []
axios.get(
"https://api.airtable.com/v0/"+app_id+"/Products",
{
headers: { Authorization: "Bearer "+app_key }
}
).then(function(response){
commit('setAllData',response.data.records.map((item)=>{
return {
id: item.id,
...item.fields
}
})
}).catch(function(error){
console.log(error)
})
},
addToCart({ commit }, product){
commit(types.ADD_TO_CART, {
id: product.id
})
},
removeFromCart({ commit }, product){
commit(types.REMOVE_FROM_CART, {
id: product.id
})
}
}
})
I'm using vue-cli#3 and vuex#3.0.1.
First step: I open the URL and the website is working. Second step: I refresh the website, then errors are thrown. So I can't get the data in store's getters by mapActions and I can't use the methods which I import by mapActions. Even if I can't access my data which is mounted on the Vue instance.
In vue-devtools, the state keeps being loaded when I got in trouble, as seen here. I've also tried vue-cli#2 to run the same code, again without success, so I've assumed that Vuex is the cause.
Store code:
import Vue from 'vue'
import Vuex from 'vuex'
import util from '../lib/util'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
locale: localStorage.getItem('locale') || 'en',
langdrop: false,
loading: false,
langs: ['en', 'zh'],
modal: {
notice: false,
rule: false,
about: false
},
phonelink: false,
bet: 1,
myinfo: {
star: 0,
amount: 0,
staticEarn: 0,
staticEarnd: 0,
inviteEarn: 0,
inviteEarnd: 0
},
bonusPot: 0,
myInviteCode: 0,
inviteCode: util.getParams().code || 0
},
getters: {
myinfo: state => state.myinfo,
langdrop (state) {
return state ? state.langdrop : false
},
loading (state) {
return state ? state.loading : false
},
langs (state) {
return state.langs.filter(item => {
return item !== state.locale
})
},
locale (state) {
return state.locale
},
notice (state) {
return state.modal.notice
},
rule (state) {
return state.modal.rule
},
about (state) {
return state.modal.about
},
phonelink (state) {
return state.phonelink
},
bet (state) {
return state.bet
},
myInviteCode (state) {
return state.myInviteCode
},
inviteCode (state) {
return state.inviteCode
},
bonusPot (state) {
return state.bonusPot
}
},
actions: {
toggleLang (context) {
context.commit('ToggleLang')
},
setlocale (context, lang) {
localStorage.setItem('locale', lang)
context.commit('SetLocale', lang)
},
UpdateHubLoading (context) {
context.commit('UpdateHubLoading')
},
settingModal (context, type) {
context.commit('SettingModal', type)
},
togglePhoneLink (context) {
context.commit('TogglePhoneLink')
},
setBetValue (context, value) {
if (value > 30 || value < 1) {
return
}
value = Math.floor(value)
context.commit('SetBetValue', value)
},
setMyinfo (context, value) {
let target = {}
target.addr = value.addr
context.commit('SetMyinfo', target)
},
setMyInviteCode (context, code) {
context.commit('SetMyInviteCode', code)
},
setBonusPot (context, bonus) {
context.commit('SetBonusPot', util.bigNumbertoNumber(bonus, 18, 4))
}
},
mutations: {
ToggleLang (state) {
state.langdrop = !state.langdrop
if (state.langdrop === true) {
state.pendingdrop = false
}
},
SetLocale (state, lang) {
state.locale = lang
},
UpdateHubLoading (state) {
state.loading = !state.loading
},
SettingModal (state, type) {
let status = !state.modal[type]
if (status === true) {
state.modal = {
notice: false,
rule: false,
about: false
}
}
state.modal[type] = status
},
TogglePhoneLink (state) {
state.phonelink = !state.phonelink
},
SetBetValue (state, value) {
state.bet = value > 30 ? 30 : value
},
SetMyinfo (state, value) {
if (state) {
state.myinfo = value || {
star: 0,
amount: 0,
staticEarn: 0,
staticEarnd: 0,
inviteEarn: 0,
inviteEarnd: 0
}
}
},
SetMyInviteCode (state, code) {
state.myInviteCode = code || 0
},
SetBonusPot (state, bonus) {
state.bonusPot = bonus || 0
}
}
})
Components Code:
created () {
this.getMyinfo()
},
methods: {
...mapActions(['setMyinfo', 'setBonusPot', 'setAddress']),
getMyinfo () {
if (!this.address) return
this.hasAddr = true
this.$Contract.methods.addrPly(this.address).call().then(res => {
this.setMyinfo(res)
})
},
getBonus () {
if (this.$Contract) {
this.$Contract.methods.bonusPot().call().then(res => {
this.setBonusPot(res)
})
}
}
}
I am trying to make an axios call and it works fine but when I call the function from the scope it returns me
loadData is undefined.
import vSelect from 'vue-select';
export default {
props : [],
data : () => {
return {
assets : [],
folders : [],
parent_id : 0,
moveParentId : null,
selectedAsset: {},
parentStack : [],
searchTerm : '',
};
},
components: {
vSelect,
},
created() {
this.loadData(this.parent_id);
this.createFolder();
},
methods : {
loadData(parentId) {
axios
.get(
'/api/assets',
{
params: {
parent_id: parentId,
},
},
)
.then((response) => {
this.parentStack.push(parentId);
this.assets = response.data;
})
.catch((error) => {
if (error.response.status === vue.$options.HTTP_STATUS.UNPROCESSABLE_ENTITY) {
}
});
},
createFolder() {
$('#create-folder-button').on('click', function (e) {
let form = $('#create-folder').find('form'),
namefield = form.find('input#name'),
name = namefield.val(),
action = '/assets',
errorelem = form.find('#create-error');
axios
.post(action, {
name: name,
type: 1,
})
.then(() => {
$('#create-folder').modal('hide');
loadData(this.parent_id); //ERROR OCCURS HERE.
}, function (error) {
if (error.response != null) {
if (error.response.status == vue.$options.HTTP_STATUS.UNPROCESSABLE_ENTITY) {
errorelem.html(error.response.status).show();
}
}
});
});
}
this is my code.