Vue styling with a method - vue.js

I'm trying to style a card with a method called needsApprove
<v-card #click="displayAmendments(article)" :style="needsApprove(article)? 'background: black;' : ''">
<h5 class="text-center p-2"
v-text="article.num + '. ' + article.title">
</h5>
</v-card>
Tried compured property:
needsApprove(article) {
article.amendments.forEach(amendment => {
if(amendment.approved == 0) {
return true
}
else {
return false
}
})
},
Tried method:
needsApprove(article) {
article.amendments.forEach(amendment => {
if(amendment.approved == 0) {
return true
}
else {
return false
}
})
},
It doesn't seem to work, it does return true although the styling doesn't seem to work, is this kind of thing possible? What am i doing wrong?

Try out a computed property with parameter like :
needsApprove() {
return articel=>article.amendments.some(am=>am.approved==0)
}

Boussadjra Brahim answered how to fix it but did not explained why it does not work.
forEach returns nothing and is used only to make certain action with every element of collection. To return something you can also use 'every' instead of 'some' to make sure that every element of collection satisfies the condition.

Related

How do I prevent the same set of error messages from showing after form submission in Vue.js?

I am trying to display error messages when the form is submitted empty. However, the same error messages showed up based on the number of times I clicked the button. How do I show unique set of error messages instead of looping?
Here's how it looks:
Here's the code I have tried to check if form is empty:
checkForm(){
if (this.staffName && this.designation && this.staffId && this.skills) {
return true;
}
if (!this.staffName) {
this.errors.push('Staff Name required.');
}
if (!this.designation) {
this.errors.push('Designation required.');
}
// if (this.password = '') {
// alert('Password required.');
// }
if(!this.staffId){
this.errors.push('Staff ID required.')
}
if(this.skills === []){
this.errors.push('Select at least one.');
}
if(this.errors.length){
return this.errors
}
else{
for (var staff of this.info){
if(staff.staff_id == this.staffId){
this.errors.push('This Staff exist! Please try again.');
return this.errors
}
else{
this.addStaff()
}
}
}
},
Here's the code I used to display the errors if the form is empty:
<p v-if="errors.length">
<b>Please correct the following error(s):</b>
<ul>
<li v-for="(error, idx) in errors" :key="idx">{{ error }}</li>
</ul>
</p>
Easiest method I can think of:
Clear the array every time you fire the button
you can either do it on the template tag
<button
type="submit"
#click="errors = []"
>
or in the checkForm method
checkForm() {
this.errors = [] //make sure to place it at the top
}
Mentionables
also, not within your question but you cannot compare array with ===, or even ==, it will always return false
I am referring to this
if(this.skills === []){
this.errors.push('Select at least one.');
}
since you just want to know whether it is empty, use .length instead. But if you want to compare like
[1, 2] == [1, 2]
it will always return false, but you can google up the solution easily as it is very popular issue that JS developers face
Instead of pussing error messages to array you can use Object or even if you want to stick with error you can use array include function to check if that already in array or not. Like:
if (!this.errors.includes('Staff Name required.');
{
this.errors.push('Staff Name required.');
}
Or if you want to use Object you can do something like
data() {
return {
errors: {
staf_name: null,
}
}
}
then in your code you can update it like this.errors.staf_name = '';
Thanks

Vue2 : v-show and changind data dynamically

I have this code that works but outputs an error
this.hideButton is not a function
here a part of the code
<template>
<div>
<v-select
#open="openSelect"
#search="applySearch"
>
<b-button variant="none" class="selectAllButton"
v-on:click="clickSelectAll" v-show="hiddenBtn">Select All</b-button>
</div>
</template>
export default {
data() {
return {
hiddenBtn: false
}
},
methods: {
applySearch(search, loading) {
if (search.length > 0 && search.length < 3) {
this.hideBtn();
return;
}
this.showBtn();
this.retrieveEntities(search, loading)
},
showBtn() {
this.hiddenBtn = true;
},
hideBtn(){
this.hiddenBtn = false;
}
}
I think this is the wrong way to update my hiddenBtn property to show and hide the button, but It works even if I get an error, so I don't understand what happens
you are calling this.hideBtn() which is not a function
applySearch(search, loading) {
if (search.length > 0 && search.length < 3) {
this.hideBtn(); // <-- you are calling this.hideBtn() which isn't a function. just remove this and try
return;
}
this.showBtn();
this.retrieveEntities(search, loading)
}
This code should work properly, maybe you have somewhere else in code something that is trying to execute this.hideButton() while your method's name is this.hideBtn().

How to write unordered list in 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.

Vue.js 2: Highlight string occurrence

Is there a convenient way to highlight all string occurrences of a string in a text or an element?
Something like the filter method from vue.js 1?
The only problem with my solution is, that the whole v-html-text is now lowercase..
I defined the highlight-method in the methods-block:
methods: {
highlight(words, query) {
if(query === '') { return words }
if(typeof(words) === 'number') {
words = '' + words + ''
}
// when removing the .toLowerCase() your search becomes case-sensitive
return words.toLowerCase().replace(query, '<span style="background: yellow;">' + query + '</span>')
}
}
In my template it looks like this:
<span v-html="highlight('This is some sort of test', 'some')"> // should now highlight 'some'
There are filters in vuejs2 as well. You just create your own method to highlight.
<div>{{ 'some-text' | highlight }}
new Vue({
// ...
filters: {
highlight: function (value) {
// logic
}
}
})

Only null or Array instances can be bound to a multi-select

I'm building a multi-step form in Aurelia where each page shows one question.
I use the same view for every question, with if statements determining what type of form field to show.
When I try to bind my question data to a multiple select element however, Aurelia throws errors and says "Only null or Array instances can be bound to a multi-select.".
What's really strange is that if the first question is a multiple select I don't get the error until I come to a non-multiselect question and then go back to the multiselect question.
I can solve this entire problem by setting activationStrategy: 'replace' for this route, but I really don't want that.
The important code follows:
import {inject} from 'aurelia-framework';
import {Router} from 'aurelia-router';
#inject(Router)
export class Form {
constructor (router) {
this.router = router;
this.active = 0;
this.field = null;
this.fields = [
{
type: 'text',
value: null
},
{
type: 'select',
value: [],
options: [
'foo',
'bar'
]
},
{
type: 'select',
value: [],
options: [
'foo',
'bar'
]
},
{
type: 'text',
value: null
},
];
}
activate (routeParams) {
this.active = routeParams.fieldIndex || 0;
this.active = parseInt(this.active);
this.field = this.fields[this.active];
}
prev () {
if (typeof this.fields[this.active - 1] !== 'undefined') {
this.router.navigateToRoute('form', {
fieldIndex: this.active - 1
});
return true;
}
else {
return false;
}
}
next () {
if (typeof this.fields[this.active + 1] !== 'undefined') {
this.router.navigateToRoute('form', {
fieldIndex: this.active + 1
});
return true;
}
else {
return false;
}
}
}
And the template:
<template>
<div class="select" if.bind="field.type == 'select'">
<select value.bind="field.value" multiple="multiple">
<option repeat.for="option of field.options" value.bind="option">${option}</option>
</select>
</div>
<div class="text" if.bind="field.type == 'text'">
<input type="text" value.bind="field.value">
</div>
<a click.delegate="prev()">Previous</a> | <a click.delegate="next()">Next</a>
</template>
But you'll probably want to check out the GistRun: https://gist.run/?id=4d7a0842929dc4086153e29e03afbb7a to get a better understanding.
Try setting the first question to a multiselect and you'll notice the error disappears (until you go back to it). You can also try activationStrategy in app.js like mentioned above.
Why is this happening and how can I solve it?
Also note that in my real app I'm actually using compose instead of ifs but have tried with both and both produce the same error. It almost seems as if the select values are bound before the if is evaluated, causing the error to show up because the text field type lacks the options array.
A little late but I wanted to give a suggestion -- for SELECT multi-selects, you should decouple the bound variable from the multi-selector to prevent those errors.
For example, if you in your custom elements that bind to 'selected', they should bind to:
<select multiple value.two-way="selectedDecoupled">
Then when the actual variable 'selected' changes, it only changes in the custom element if the bound value is an array:
selectedChanged( newV, oldV ){
if( typeof newV =='object' )
this.selectedDecoupled = newV;
else
this.selectedDecoupled = [];
$(this.SELECT).val(this.selectedDecoupled ).trigger('change');
}
Example of it in use with a custom select2 element:
https://github.com/codefreeze8/aurelia-select2
Ok so it turns out swapping the order of the HTML, and putting the select after the input solves this issue.
Jeremy Danyow explains it like this:
When Form.field changes, the bindings subscribing to that property's changes evaluate sequentially. Which means there's a period of time when the select AND the input are both on the page. The html input element coaleses null values to empty string which in turn causes field.value to be empty string, which makes the multi-select throw.
Very tricky to track down imo but I'm glad the Aurelia devs are so helpful over on Github.
Working Gist: https://gist.run/?id=3f88b2c31f27f0f435afe14e89b13d56