How to write unordered list in vue.js? - vue.js

I am trying to create and unordered list for an array of errors I am printing from my console. I am using vue.js and am struggling to understand how to write this. My relevant code is below.
Script for printing errors:
export default {
name: 'post',
data () {
return {
validationErrors: []
}
},
methods: {
getPost () {
//irrelevant code
.then(({data}) => {
this.validationErrors = data.validationErrors
})
},
postUpdate () {
//more irrelevant code
.catch(error => {
console.log(error);
this.validationErrors = error.response.data.validationErrors;
})
}
}
}
How I am displaying the errors:
<p v-show="(this.validationErrors || '').length > 0">{{this.validationErrors != null && validationErrors.length > 0 ? validationErrors[0].msg : ""}}</p>
Any help would be appreciated!

Not quite sure what result you want, but it's easier to reason about if you make sure validationError is always an array - even if empty- and not null. Then you don't have to check for length or if it's null, you can simply do this
<p v-for="error in validationErrors" :key="error.msg">
{{ error.msg }}
</p>
If there are no errors, than nothing renders.

Related

Vuex passing different arrays

Making a filter:
Mutations
export default {
state: {
filteredBrands: []
},
mutations: {
showFilteredList(state, payload) {
state.filteredBrands.push(payload);
}
}
};
Methods
loadProducts(item) {
axios.get('/api', {
params: {
per_page: 20,
filter_machinery_brands: [ item ]
}
})
.then((response) => {
this.$store.commit(
'showFilteredList',
response.data
);
});
},
item this is an input with a checkbox, when clicked, a request is made to the server for this category
For some reason, the push does not work, why?
And I would like there to be a check, if the array is the same, then delete, otherwise add. Is it possible?
If you can se an array comes in as payload. Then you are trying to push an array into an array. Which cant be done in either js or ts.
You can try set the value:
state.filteredBrands = payload;
otherwise you would have to do something like this:
state.filteredBrands.push(payload[0]);
If you wanna control for existing items in array, and assuming your are not always setting value, but pushing new values into your array. You can do something like this:
if (state.filteredBrands.indexOf(payload[0]) === -1) {
// Not in array
state.filteredBrands.push(payload[0])
} else {
// is allready in array
state.filteredBrands.forEach((item, index) => {
if (item === payload[0]) {
state.filteredBrands.splice(index, 1)
}
})
}
EDIT:
My assumption was right.
Your payload is an array
Your state is an array
-------> You are trying to push payload(array) into state(array) - which cant be done i js - This solution would after my suggestion be more clean:
payload.forEach((value, index) => { // Looping payload
if (state.filteredBrands.indexOf(value) === -1) {
state.filteredBrands.push(value) // push if value not allready in array
} else {
state.filteredBrands.splice(index, 1) // if value is in array -> remove
}
})
Yes, you can push an array into an array.
I guess the problem here is your vuex config.
Vuex state is a function, so it needs to be:
state () {
return {
filteredBrands: []
}
}
And if you are using Nuxt:
export const state = () => ({
filteredBrands: []
})

How can I put a data inside the <template> in a component with Vue

I am trying to do a pagination but I can not put the dynamic total I am doing like this:
<v-pagination v-model="currentPage"
:page-count="total"
:classes="bootstrapPaginationClasses"
:labels="paginationAnchorTexts"
></v-pagination>
How you can see the total os in the :page-count, it is a dynamic total because I am getting data from database, my vue code is this one:
<script>
import vPagination from 'vue-plain-pagination';
export default {
created() {
this.getPosts();
},
methods: {
getPosts() {
fetch('/api/bank')
.then(response => response.json() )
.then(json => {
this.posts = json.data.data;
this.total = json.data.last_page;
this.current_page = json.data.current_page;
});
}
},
components: { vPagination },
data: function() {
return {
postsSelected: "",
posts: [],
currentPage: 1,
total: this.total,
bootstrapPaginationClasses: {
ul: 'pagination',
li: 'page-item',
liActive: 'active',
liDisable: 'disabled',
button: 'page-link'
},
paginationAnchorTexts: {
first: 'Primera',
prev: '«',
next: '»',
last: 'Última'
}
}
}
}
</script>
How you can see I am using fetch to get the data from database and then I am split it in different information like total and the I am using this information inside the data: function() {}.
How you can tell total it's like this: total: this.total because I want to get the total number but when I do that I am getting this error:
[Vue warn]: Invalid prop: type check failed for prop "pageCount". Expected Number with value NaN, got Undefined
and I think that it is because:
total: this.total in the data function() {} is bad or:
how can I put the dynamic variable total inside the
How could I fix it?
Thanks!
If you want to know the data retrieved from the API, you can console log the data returned like this:
getPosts() {
fetch('/api/bank')
.then(response => response.json() )
.then(json => {
console.log(json.data)
this.posts = json.data.data;
this.total = json.data.last_page;
this.current_page = json.data.current_page;
});
}
Also, you should not have data attribute and props attribute with the same name! So change the total data attribute to another name and initialize it with a value of 0 instead.
In fact, you don't need to care about passing the Prop total at all as your method getPosts is not dependent on the Prop! So you may just have total: 0 in data and that should fix your issues

Able to display the result of a promise but length of the result appears as undefined

I'm new to vue/promise and I am struggling to understand why when I try to display the result of a promise I end up with the expected data but when I try to find out its length, it says undefined
When I try to display the alerts from displayAlerts() , I can see a list of alerts, 2 in total. However in computed within the title function ${this.displayAlerts.length} appears as undefined, I was expecting to see 2.
Does it have something to do with displayAlerts() resulting in a promise? How do I fix the code such that I get 2 instead of undefined?
The code is below:
<template>
<div>
{{displayAlerts}}
<li v-for="alert in alerts" class="alert">
{{alert['name']}}
</li>
</div>
</template>
export default {
data () {
return {
alerts: null,
alert: new Alert(),
updatedAlert: new Alert(),
deletedAlert: new Alert(),
};
},
computed: {
...mapGetters("authentication",['token']),
...mapGetters("user",['profile']),
displayAlerts() {
return getUserAlert({
user_id: this.profile.user_id,
token: this.token
}).then(response => (this.alerts = response.data)).catch(
error => console.log(error)
)
},
title () {
return `My Alerts (${this.displayAlerts.length})`
},
test2() {
return [1,2,3]
},
}
};
</script>
Something like this should work:
<template>
<div v-if="alerts">
<h4>{{ title }}</h4>
<li v-for="alert in alerts" class="alert">
{{ alert.name }}
</li>
</div>
</template>
export default {
data () {
return {
alerts: null
}
},
computed: {
...mapGetters('authentication', ['token']),
...mapGetters('user', ['profile']),
title () {
// Handle the null case
const alerts = this.alerts || []
return `My Alerts (${alerts.length})`
}
},
methods: {
// This needs to be in the methods, not a computed property
displayAlerts () {
return getUserAlert({
user_id: this.profile.user_id,
token: this.token
}).then(response => (this.alerts = response.data)).catch(
error => console.log(error)
)
}
},
// Initiate loading in a hook, not via the template
created () {
this.displayAlerts()
}
}
</script>
Notes:
Computed properties shouldn't have side-effects. Anything asynchronous falls into that category. I've moved displayAlerts to a method instead.
Templates shouldn't have side-effects. The call to load the data should be in a hook such as created or mounted instead.
title needs to access this.alerts rather than trying to manipulate the promise.
While the data is loading the value of alerts will be null. You need to handle that in some way. I've included a v-if in the template and some extra handling in title. You may choose to handle it differently.
I've added title to the template but that's just for demonstration purposes. You can, of course, do whatever you want with it.
I've assumed that your original displayAlerts function was working correctly and successfully populates alerts. You may want to rename it to something more appropriate, like loadAlerts.

NuxtJs where to declare a computed property

How can i declare a computed property using Nuxt ? or the equivalent ?
I am using NuxtJs and trying to use a category filter.
I want to filter by unique categories, and i am getting this error message:
Cannot read property 'filter' of undefined
I trying to adapt to Nuxtjs the exemple i found in this pen : https://codepen.io/blakewatson/pen/xEXApK
I declare this computed property below, first at pages/index.vue and after into .nuxt/App.js
filteredStore: function() {
var vm = this;
var category = vm.selectedCategory;
if(category=== "All") {
return vm.stores;
} else {
return vm.stores.filter(function(stores) {
return stores.category === category;
});
}
}
And i try to apply the filter into this list of checkboxes :
<div class="columns is-multiline is-mobile">
<div class="column is-one-quarter" v-for="store in filteredStore" :key="store.id" :store="store">
<label class="checkbox">
<input type="checkbox" v-model="selectedCategory" :value="''+store.category">
{{store.category}}
</label>
</div>
</div>
I'm going to do some guessing at your code situation (based on the example you noted), so just let me know where I make an incorrect assumption. I would guess that something like the following could work for you... maybe you could provide additional details where I'm missing them.
With regards to your error Cannot read property 'filter' of undefined, that probably means your array of stores is undefined. I believe if you create the stores array as empty in the data section, you should at least have it available before your async call returns any results.
One possible thing to you can do to test if your filtering logic is working... is to uncomment the manually created data array that I've created below. It's like an inline test for your data structure and logic, removing the asynchronous retrieval of your data. This basically can check if the filter works without your API call. It would narrow down your issue at least.
export default {
data() {
return {
stores: [
// Let's assume you don't have any static stores to start on page load
// I've commented out what I'm guessing a possible data structure is
//
// Example possible stores in pre-created array
// { name: 'Zales', category: 'Jewelry', id: 1 },
// { name: 'Petco', category: 'Pet Shop', id: 2 },
// { name: 'Trip Advisor', category: 'Tourism', id: 3 },
// { name: 'Old Navy', category: 'Clothes', id: 4 }
],
selectedCategory: 'All'
}
},
computed: {
// Going to make some small js tweaks
filteredStores: () {
const vm = this;
const category = vm.selectedCategory;
if (category === "All") {
return vm.stores;
} else {
return vm.stores.filter(store => {
return store.category === category;
});
}
}
},
async asyncData({ $axios }) {
$axios
.$get('https://yourdomain.com/api/stores/some-criteria')
.then(response => {
this.stores = response.data;
})
.catch(err => {
// eslint-disable-next-line no-console
console.error('ERROR', err);
});
}
};
And then your HTML
<div class="columns is-multiline is-mobile">
<div class="column is-one-quarter" v-for="store in filteredStores" :key="store.id" :store="store">
<label class="checkbox">
<input type="checkbox" v-model="selectedCategory" :value="`${store.category || ''}`">
{{store.category}}
</label>
</div>
</div>
ANYWAY This is all just a big guess and what your scenario is, but I figured I'd try to help shape your question some so that you could get a more meaningful response. In general, I'd suggest trying to provide as much detail as you can about your question so that people really can see the bits and pieces where things might have gone astray.
Don't touch anything in .nuxt Someone noted that above in a comment, and it's very important. Essentially that whole directory is generated and any changes you make in it can be easily overwritten.

cypress custom find command

I have a custom command that gets me my elements with the data-cy attribute.
Cypress.Commands.add("getById", (id) => {
cy.get(`[data-cy=${id}]`)
})
everything's working fine.
Now it would be nice if I had the same with find. It would be looking like this:
Cypress.Commands.add("findById", { prevSubject: true }, (subject, id) => {
cy.wrap(subject).find(`[data-cy=${id}]`)
})
The problem there is that cypress throws an error with this code:
cy.root().then((root) => {
if(root.findById("...").length) {
...
}
})
The error is "root.findById" is not a function.
Can you help me write that custom command correctly?
The basic problem is that subject passed in to the command is already wrapped, so just chain the find() from it. Also you need to return the result to use it in the test.
Custom command
Cypress.Commands.add("findById", { prevSubject: true }, (subject, id) => {
return subject.find(`[data-cy=${id}]`)
})
The next problem is you can't mix 'ordinary' js code with Cypress commands, so the returned value must be accessed from a .then().
Spec
describe('...', () => {
it('...', () => {
cy.visit('app/find-by-id.html')
cy.root().findById('2').then(el => {
console.log('found', el, el.length)
expect(el.length).to.eq(2)
})
})
})
Html used to test the test (app/find-by-id.html)
<div>
<div data-cy="1"></div>
<div data-cy="2"></div>
<div data-cy="2"></div>
<div data-cy="3"></div>
</div>
Adding to #Richard Matsen's answer, you might want to add some log into your command, so that it appears well in your cypress log, just as if you had used .find(...) directly:
Cypress.Commands.add(
"findByTestId",
{
prevSubject: ["element"],
},
(
subject: Cypress.Chainable<HTMLElement>,
testId: string,
options?: Partial<
Cypress.Loggable &
Cypress.Timeoutable &
Cypress.Withinable &
Cypress.Shadow
>
) => {
const $el = subject.find(`[data-testid=${testId}]`, options);
Cypress.log({
$el: $el as any,
name: "findByTestId",
message: testId,
});
return $el;
}
);