Filter with VueJS - javascript

I am very new with VueJS so my question is very simple. I cannot use vue filter. Please help me fix the problem.
My html file is shown as followed. When I try this code the item in v-for can't be shown and also the it has error Failed to resolve filter: uppercase.
Can any one tell me why?
<div id="pan" class="pan">
<div v-for="item in list|orderBy 'level'" >{{item.id}}</div>
<span>{{message | uppercase}}</span>
</div>
<script type="text/javascript" src="https://unpkg.com/vue/dist/vue.js"></script>
<script type="text/javascript">
var pan = new Vue({
el: '#pan',
data: {
list: [
{ name: '東京', id:"TOKYO",level:"2"},
{ name: '全国',id:"JAPAN",level:"1" },
{ name: '関東',id:"KANTO",level:"0" },
],
message:"hello"
}
});
</script>

If you are using vuejs2, with vuejs2 uppercase filter has been removed. You will have to use toUpperCase() for this, like following:
<span>{{message.toUpperCase()}}</span>
see demo.
Similarly orderBy filter also has been removed, vuejs2 suggests to use lodash’s orderBy (or possibly sortBy) in a computed property:
HTML
<p v-for="item in orderedList">{{ item.name }}</p>
vue
computed: {
orderedList: function () {
return _.orderBy(this.list, 'level')
}
}
Here is demo with orderBy.

You can use a computed property.
Markup:
<div id="pan" class="pan">
<div v-for="item in orderedList" >{{ item.id }}</div>
<span class="pan__title">{{ message }}</span>
</div>
Definition inside of Vue:
data(){
sortKey : 'level'
},
computed : {
orderedList(){ return this.list.sort(this.sorter) }
},
methods : {
sorter(a,b){ return a[this.sortKey] > b[this.sortKey] }
}
And then you can change order of the elements in orderedList by modifying sortKey (using v-model="sortKey" to any kind of input, like <select></select> or any other way).
Here is an example based on your code
And what about uppercase, I prefer to control a view with css, and text-transform property can solve this: .pan__title { text-transform: uppercase; }. But you can define a computed property for this one too or keep it inline with {{ message.toUpperCase() }}.

Related

Buefy field does not react on :message param change

I have a Nuxt project with Buefy components. There is a form with some field component which should react on error according the message parameter for this component. But does not. I can see the correct value in debuger but component does not show the message. :message property should work like the in first email example from documentation
The code looks like:
<template #company>
<h2 class="title">{{ $t('general.login.create_company') }}</h2>
<b-field
:type="loginErrors.company_name ? 'is-danger' : ''"
:message="loginErrors.company_name ? loginErrors.company_name : ''"
>
<b-input
v-model="companyName"
name="company_name"
type="text"
autocomplete="off"
:placeholder="$t('general.login.create_company')"
></b-input>
</b-field>
<div class="buttons is-centered">
<b-button type="is-primary is-light" #click="createCompany">Save</b-button>
</div>
</template>
...
data() {
return {
...
loginErrors: {},
error: 'aaaaaa',
};
},
...
async createCompany() {
const result = await this.$api.users.createCompany({company_name: this.companyName});
if( result.error ) {
this.loginErrors.company_name = result.error; // This does not work although the variable has correct value set
this.error = result.error; // This works fine
return false;
}
},
I use this pattern in other components and it works. I dont understand it. thaks for any help.
change detection of data objects in Vue is shallow (top level only)
In vue.js, Dynamically added property to an object is not reactive. Instead we can assign a whole object so that change detection happen.
For a better understanding please go through this official documentation of Vue.
Demo :
new Vue({
el: '#app',
data() {
return {
loginErrors: {}
}
},
mounted() {
this.loginErrors = {
company_name: 'some value'
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<p>{{ loginErrors.company_name ? 'is-danger' : 'no-danger' }}</p>
</div>
I don't think Vue components react to object property changed in a direct way, you could try this.$set(this.loginErrors, 'company_name', result.error); instead of this.loginErrors.company_name = result.error;
FYI: https://v2.vuejs.org/v2/guide/reactivity.html?redirect=true#Change-Detection-Caveats
The solution in this case was to update Buefy version from 0.4.11 to 0.4.21. This fix the issue. Another thing is that is causes new issue with :type in combination with grouped param.

Vue: why this simple v-for doesn't work: Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key error

I have this simple component that has a person with values that it should display:
TestFor.vue:
<template>
<div v-for = "(value, key) in this.person">
{{key}} : {{value}}
</div>
</template>
<script scoped>
export default {
props: {
person: {
firstName: 'Bob',
lastNmae: 'Andersen',
age: 27
}
}
}
</script>
However I get the Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key error. Which shouldn't occur, because according to documentation: https://v2.vuejs.org/v2/guide/list.html my syntax is valid:
This video tutorial also uses this syntax and it works fine for them. Why doesn't it work for me?
EDIT:
As people have said the require-v-for-key rule is a culprit. Is there any reason behind that rule or is it OK to just disable it?
I've added "vue/require-v-for-key": "off" to package.json and the original code seems to be working now. Am I good or should I enable that rule back? It just seems like an annoyance for no reason.
You need to define key per element of your list. in your case, it's quite trivial:
<div v-for = "(value, key) in this.person" :key='key'>
{{key}} : {{value}}
</div>
Without the key, Vue is unable to link data to components created with v-for. Lack of key means that any modification of the object you iterated would destroy and recreate all the child components, which would bring a number of undesired side effects. Once the key is defined, when collection changes, vue will calculate key for each element, compare it with keys of existing children and act accordingly.
The error is coming from your linter rule: require-v-for-key
You can fix it, with adding the key binding:
<div v-for = "(value, key) in this.person" :key="key">
{{key}} : {{value}}
</div>
The error means you need to bind the key property at your div.
<template>
<div v-for = "(value, key) in person" :key="key">
{{key}} : {{value}}
</div>
</template>
<script scoped>
export default {
props: {
person : {
type : Object,
default : function(){
return {
firstName: 'Bob',
lastNmae: 'Andersen',
age: 27
}
}
}
}
}
}
</script>

'v-bind' directives require an attribute value

I am trying to create some type of tree with vue.js and stuck on a problem with element props. Help me out plz.
I've tried :content="{{tempCont}}" and I've tried content="{{tempCont}}", but none of them worked.
Here's the place where I am using tree element:
<div id="tree">
<treeItem :title="Parent" :content="{{tempCont}}"></treeItem>
</div>
Here's the entire tree element:
<template>
<div>
<p v-on:click="openTree">{{title}}</p>
<div id="childs" v-if="childVisibility">
<treeItem v-for="item in content" :key="item" title=item>
</div>
</div>
</template>
<script>
export default {
data: {
childVisibility: false
},
methods: {
openTree: function(){
childVisibility = !childVisibility;
}
},
props: {
title: String,
content: Array,
}
}
</script>
<style scoped>
</style>
I am getting this error:
Use like this: :content="tempCont"
<div id="tree">
<treeItem :title="Parent" :content="tempCont"></treeItem>
</div>
Ok so first of all, when you v-bind something like v-bind:title or :title, what you bind is expressed as a javascript expression.
So if you want your title attribute to be the string Parent, you need either to write it like a native html attribute title="Parent" (notice the lack of :), or as a vue bound attribute v-bind:title="'Parent'" or :title="'Parent'" (notice the use of '' to express a string primitive type in javascript.
Now, the {{ variable }} syntax is used inside vuejs template but you do not need to use it inside v-bind attributes since they are already interpreted as javascript.
So you shouldn't write this:
<div id="tree">
<treeItem :title="Parent" :content="{{tempCont}}"></treeItem>
</div>
but this instead:
<div id="tree">
<treeItem title="Parent" :content="tempCont"></treeItem>
</div>
SincetempCont is already a valid javascript expression.
You don't really need {{}} for passing attributes.
<treeItem :title="Parent" :content="tempCont"></treeItem>
This shall be good enough to work. The puspose of {{}} is to print data and not pass attributes.
Also, in your tree component, it's a good practice to follow object notations in your props. For ex:
props: {
title: {
type: String
},
content: {
type: Array
},
}
Also you should make your components data reactive and making sure that childVisibility is set to this instance rather than a direct reference by setting it like this
export default {
data() {
return {
childVisibility: false
}
},
methods: {
openTree() {
this.childVisibility = !this.childVisibility;
}
},
props: {
title: String,
content: Array,
}
}

vue.js component inline style concatenation

I'm stuck with a vue.js component inline style concatenation.
My code is the following:
components: {
'twitter-item': {
props: ['procolors'],
template: '\
<div class="color-quadrat" v-bind:data-id="procolors.id" v-bind:style="background-color: #{procolors.user.profile_background_color}">\
<p>{{procolors.user.profile_background_color}}</p>\
</div>\
'
}
}
I'm trying to get procolors.user.profile_background_color as inline background color. Special is that the value from procolors.user.profile_background_color has no #. So I have to add this in the template.
I tried all kinds of recommendations from the web, but none worked for me.
Any help appreciated!
Use this, which utilizes vue's style object syntax:
:style="{backgroundColor: '#' + procolors.user.profile_background_color}"
You have several choices in how to add styling. If you use v-bind:style="...", or it shorthand :style="...", you need to pass either a valid string, valid variable or a valid object.
Currently you are trying to parse background-color: #{procolors.user.profile_background_color} as javascript, which is not going to work.
You can use a javascript template to create a string:
components: {
'twitter-item': {
props: ['procolors'],
template: '\
<div class="color-quadrat" v-bind:data-id="procolors.id" v-bind:style="`background-color: #${procolors.user.profile_background_color}`">\
<p>{{procolors.user.profile_background_color}}</p>\
</div>\
'
}
}
It is often more readable to refactor it to use a variable or function instead:
components: {
'twitter-item': {
props: ['procolors'],
template: '\
<div class="color-quadrat" v-bind:data-id="procolors.id" v-bind:style="rowColor">\
<p>{{procolors.user.profile_background_color}}</p>\
</div>\
',
computed: {
rowColor () {
return {
"background-color": `#${this.procolors.user.profile_background_color}`
}
}
}
}
}
Accoding to Binding inline styles documentation there are to ways to pass inline styles - as an object or as an array.
In your example, background-color: #{procolors.user.profile_background_color} is neither object or an array.
For sake of readability and maintainability (and good practice in general), I'd suggest to create a computed property that will return an object with inline styles. This way it will more clear where is the issue with concatenation:
Template will look as follows:
<div
class="color-quadrat"
:data-id="procolors.id"
:style="itemStyles">
<p>{{ procolors.user.profile_background_color }}</p>
</div>
And computed property should be added to the same component:
props: ['procolors'],
template: `...`,
computed: {
itemStyles () {
return {
backgroundColor: `#${this.procolors.user.profile_background_color}`
}
}
}
If you still prefer to keep it inline, then style binding should be changed to following:
v-bind:style="{ backgroundColor: `#${procolors.user.profile_background_color}` }"
For those who want to use style binding with vue3. This is the solution:
<script setup lang="ts">
import {ref} from 'vue'
const color = ref("red")
</script>
<template>
<div class="parti-color"
:style="{backgroundColor: color, width: '20px', height: '30px'}"
/>
</template>

VueJS - Component inside of v-for

I am trying to render a list of objects from my Vue-Instance. Each object should use a component, so I put the component into the v-for-loop. But all I get is list.title and list.text instead of the correct values.
Is there a special way to use components in v-for-loops?
I found this thread in the Vue-Forum, but don't know how to use it or if it's the right way.
App:
<div id="app">
<div v-for="list in lists">
<listcard title="list.title" text="list.text"></listcard>
</div>
</div>
Template:
<template id="listcard-template">
<div class="card">
<h2>{{ title }}</h2>
<p>{{ text }}</p>
</div>
</template>
My component:
Vue.component('listcard', {
template: '#listcard-template',
props: ['title', 'text']
})
Vue-Instance:
new Vue({
el: "#app",
data: {
lists: [
{title: "title1", text: "text1"},
{title: "title2", text: "text2"},
...
]
}
})
Thanks!
You should pass then as dynamic prop using : in front of parameters:
<listcard :title=list.title :text=list.text></listcard>
From documentation:
A common mistake beginners tend to make is attempting to pass down a number using the literal syntax:
<!-- this passes down a plain string "1" -->
<comp some-prop="1"></comp>
However, since this is a literal prop, its value is passed down as a plain string "1", instead of an actual number. If we want to pass down an actual JavaScript number, we need to use the dynamic syntax to make its value be evaluated as a JavaScript expression:
<!-- this passes down an actual number -->
<comp :some-prop="1"></comp>
https://vuejs.org/guide/components.html#Literal-vs-Dynamic

Categories