Displaying text with different color based on result from a computed property? - vue.js

Currently I have something along the lines of:
data(){
return {
summonerMatches: '',
}
},
computed: {
highestMultikill(){
let highestMultikill = 0;
for (let match of this.summonerMatches.matches) {
if (highestMultikill < match.mainParticipant.stats.largestMultiKill) {
highestMultikill = match.mainParticipant.stats.largestMultiKill
}
}
return highestMultikill
},
}
When I use this computed property in my template like this:
<p>{{ highestMultikill }}</p>
I render a number that symbolizes the highest multi kill of a user. Now I would like to somehow add a class to that <p> element based on the highestMultiKill. If highestMultiKill = 1, set a class that changes the color to blue, if highestMultiKill = 5, set a class that changes the color to red, etc.
I'm not sure how to do that with my current setup. I was thinking about having the computed property return an entire different <p>element based on the highestMultikill variable like this:
if (highestMultiKill == 1) {
return <p class='blue'>highestMultiKill</p>
} else {
return a different `<p>` element with a different class
}
Is this the correct way to do this?

Here's an example with more complex logic and BEM-inspired class names:
<template>
<p :class="klass">{{ highestMultiKill }}</p>
</template>
<script>
export default {
data() {
return { highestMultiKill: 0 };
},
computed: {
klass() {
return {
score: true, // Always have a score class
'score--low': this.highestMultiKill <= 2,
'score--medium': this.highestMultiKill > 2 && this.highestMultiKill <= 5,
'score--high': this.highestMultiKill > 5 && this.highestMultiKill <= 10,
'score--blood-lust': this.highestMultiKill > 10,
};
},
},
};
</script>
<style scoped>
.score {
line-height: 2;
}
.score--low {
color: blue;
}
.score--medium {
color: pink;
}
.score--medium {
color: red;
}
.score--medium {
color: darkred;
}
</style>
The idea is that the p will have a class like: score score--medium

You can use a conditional class like this:
<p :class="highestMultiKill == 1 ? 'blue' : 'otherClass'">highestMultiKill</p>
See the full documentation on conditional classes in Vue.js here.
By the way you should not initialize summonerMatches with a string if it's actually an object with reactive properties.

The best way to do this, if you have complex logic involving many variables and or classes, is something like this:
<p :class="killClass"></div>
computed: {
killClass: function () {
return {
highestMultiKill >= 3 ? 'blue' : 'red'
}
}
}
If you have more classes/states then use an if statement instead.

This sample can be of use:
<html>
<head>
</head>
<body>
<div id="container">
<p v-if="this.computedValue==0" style="color:blue;" >content0</p>
<p v-if="this.computedValue==1" style="color:red;" >content1</p>
<p v-if="this.computedValue==2" style="color:green;" >content2</p>
<p v-if="this.computedValue==3" style="color:yellow;" >content3</p>
<p v-if="this.computedValue==4" style="color:pink;" >content4</p>
<p v-if="this.computedValue==5" style="color:aquamarine;" >content5</p>
<p v-if="this.computedValue==6" style="color:blueviolet;" >content6</p>
<p v-if="this.computedValue==7" style="color:brown;" >content7</p>
<p v-if="this.computedValue==8" style="color:chartreuse;" >content8</p>
<p v-else>content9</p>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/0.11.10/vue.min.js"></script>
<script>
new Vue({
el: '#container',
data: {
value: '',
},
computed: {
computedValue: function() {
var styleNumber = 0;/*return a number based on a logic*/
return styleNumber;
}
}
});
</script>
</body>
</html>

Related

In vue.js how can I filter products by size, color, category & by selecting each of these categories in step wise slider

In vue.js how can I filter products by size, color, category & by selecting each of these categories in step-wise slider where I have to select each filter one by one step-wise & at last I need to display the products which pass through the filter.
Please share code examples and ask specific questions about where you are stuck. This question is very broad and is difficult to answer.
I'll try to provide an answer as best as I can.
You might have a ProductList component that may look something like this:
<template>
<!-- your template -->
</template>
<script>
import RangeSlider from "./RangeSlider";
export default {
name: "ProductList",
components: {
RangeSlider
},
data() {
return {
products: [],
filters: {
color: null,
size: null,
category: null
},
options: {
color: ["Red", "Yellow", "Green"],
size: ["Small", "Medium", "Large"],
category: ["Men", "Women", "Boy", "Girl"]
}
};
}
};
</script>
The RangeSlider can use the native <input type="range" /> control to build the functionality you want.
In this example, it takes a label and an array of options to build the control, and will emit a change event when the user changes the value of the control by sliding, which is captured in ProductList to set the filters. You can then use the filters object and make an API call to fetch your products.
<template>
<div class="range-slider">
<label>
<strong>{{ label }}</strong>
</label>
<div>
<input type="range" min="0" :max="max" step="1" #change="onInputChange" :value="rangeValue">
</div>
<div>{{ options[rangeValue] }}</div>
</div>
</template>
<script>
export default {
name: "RangeSlider",
props: ["label", "options"],
data() {
return {
rangeValue: 0
};
},
mounted() {
this.onChange(0);
},
methods: {
onInputChange(e) {
this.onChange(e.target.value);
},
onChange(rangeValue) {
this.rangeValue = rangeValue;
let selectedOption = this.options[this.rangeValue];
this.$emit("change", selectedOption);
}
},
computed: {
max() {
return this.options.length - 1;
}
}
};
</script>
<style>
.range-slider {
padding: 1rem;
border-bottom: 1px solid;
}
</style>
Here is the working example on CodeSandbox: https://codesandbox.io/s/rangesliderwithoptionsexample-6pe10

Repeated data in vue

i`m having a problem with my vue, the problem is im trying to print 2 words, that is 'A.2' and 'B.3', but when im printing it, it just show 'B.3' and 'B.3'. here is my code
this is a simple quiz project, so everytime a user choose option a with true status it should be adding 1 point to the score, i haven`t made that yet.
<template>
<div class="hello">
<h1 v-if="show">hai</h1>
<h1 v-else>hehe</h1>
<p>{{ nama}}</p>
<input type="text" v-model="nama">
<button type="button" v-on:click="hideTitle">Click Me</button>
<h3> 1.Yang Dipakai Di sepatu adalah </h3>
<p>{{ nama}}</p>
<h3 v-for="j in jawaban">
<input type="radio">
{{j}}
</h3>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
},
data : function() {
return{
nama: 'Luthfi',
show: true
},
{
jawaban: 'A.2',
correct: true
},
{
jawaban: 'B.3',
correct: false
},
{
jawaban: 'C.4',
correct: false
}
},
methods: {
hideTitle() {
this.show = !this.show
}
},
mounted: function () {
this.nama = 'Fitra'
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
i expect there is 4 output from option A to D, but it kept showing me same option
In your code, data() returns only one object that contains
{
nama: 'Luthfi',
show: true
}
You must change this like:
data : function() {
return{
nama: 'Luthfi',
show: true,
jawaban: 'A.22',
correct: true,
jawabann: 'B.3'
}
}

What is the opposite of $set in Vue.js?

In a blog app, I'd like to show/hide comments of each post inside a loop of posts. I know how to show the div containing the comments by setting a showComments on the fly:
this.$set(post, 'showComments', true) ;
But I don't know how to hide the post's comments when the div is already open. What I tried is this:
if (this.$get(post, 'showComments')==true) {
this.$set(post, 'showComments', false) ;
return
}
The code above thoes not work and I get this error:
Uncaught TypeError: this.$get is not a function
So I'm wondering how can I acheive this functionaliry.
You should be able to simply read the dynamic property and reapply the value.
new Vue({
el: '#app',
data() {
return {
posts: [
{ content: 'Post #1' },
{ content: 'Post #2' },
{ content: 'Post #3' }
]
}
},
methods: {
toggleComment(post) {
if ('showComment' in post) {
post.showComment = !post.showComment;
}
else {
this.$set(post, 'showComment', true);
}
}
}
})
.post {
background-color: lightgreen;
margin: 10px 0;
padding: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="post" v-for="(post, index) in posts" :key="index">
{{post.content}}
<p v-if="post.showComment">
Hidden comments.
</p>
<button #click="toggleComment(post)">Toggle comment</button>
</div>
</div>
Use property name to get property value
if ( typeof this.post.showComments !== 'undefined' && this.post.showComments ) {
Vue.set(post, 'showComments', false);
return;
}
Also note that you should try to avoid using this.$set because it was deprecated due to conflicts with other libraries. Consider using Vue.set instead.
https://v2.vuejs.org/v2/api/#Vue-set

VueJS Not emit message to parent

I don't have much knowledge about child and parent component and i am just simply trying to change value in child then emit then value to parent so i can show somewhere, But it looks like not working, Not emiting the value.
This should change to : Hello from child
{{ message }} From Parent
Can anyone look this code and tell me what is mistake ?
Vue.component('child1', {
template: '<p #click="runMe">{{ display }}</p>',
props: ['display'],
data: {
display: ''
},
methods: {
runMe() {
this.display = "Hello from child"
this.$emit("changeMessage", this.display)
}
}
})
new Vue({
el: "#app",
data: {
message: "Hello 2"
},
methods: {
messageRun() {
this.message = "Change By"
}
}
})
.btnMain {
display: block;
background: #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.2/vue.min.js"></script>
<div id="app">
<button #click="messageRun" class="btnMain">Click Here</button>
<child1 :display="message" #changeMessage="message = $event"></child1>
<hr>
{{ message }} From Parent
</div>
In your code you have this where you emit:
this.$emit("changeMessage", this.display)
Change to :
this.$emit("newmessage", this.display)
I mean use lower case single word, if you use camelCase vue convert it to change-message but this is not acceptable by attribute, I tried this on your code.
After change this do this :
<child1 :display="message" #newmessage="message = $event"></child1>

How do you activate a class for individual elements within an array? [Vue.js]

I want to activate a class for each input individually. I have two inputs bound to the same v-model and class. I have a method that checks for something to be true, and if true enables the bound class. Currently it enables the class on all inputs. (The end goal is to search multiple inputs for an element within an array and if it matches, the class activates only for that element)
<input v-model="highlightTest" id="1" v-bind:class="{ active: active }" v-on:keyup="Highlighting"></input>
<input v-model="highlightTest" id="2" v-bind:class="{ active: active }" v-on:keyup="Highlighting"></input>
Highlighting: function() {
if (this.highlightTest != '') {
this.active = true;
}
else {
this.active = false;
}
How about this:
<template>
<input v-for="(hi,index) of highlights" v-model="highlights[]" v-bind:class="{ active: highlights[index] }" v-on:keyup="highlighting(index)"></input>
</template>
<script>
export default{
data() {
return {
highlights: []
};
},
created() {
this.$http.get('some/api').then(res => {
// map: convert 0,1 to false,true
this.highlights = res.json().map(h => h==1);
});
},
methods: {
highlighting(index) {
if (this.highlights[index]) {
// this.highlights[index] = false won't let vue detect the data change(thus no view change)
this.highlights.splice(index, 1, false);
} else {
this.highlights.splice(index, 1, true);
}
}
}
}
</script>
Here's one way to do it (sorry for the delay btw)
HTML:
<div id="app">
<p :class="{'active': activateWord(word)}" v-for="word in words">#{{ word }}</p>
<input type="text" v-model="inputText">
</div>
CSS:
.active {
color: red;
}
JS:
const app = new Vue({
el: '#app',
data: {
inputText: '',
words: [
'foo',
'bar'
]
},
methods: {
activateWord(word) {
return this.inputText === word
},
},
})
here's a fiddle