As the title says, how to make this in VueJS
There is a start point https://jsbin.com/tomevukisa/edit?html,js,output
I guess it's something about index matching because I did something similar with jQuery in this way
$('.Colors > li').on('mouseenter', function() {
var i = $(this).index();
$('.Items > li.active').fadeOut(200, function() {
$(this).removeClass('active').parent('ul').children('li').eq(i).fadeIn(100).addClass('active');
});
});
But now it's about VueJS only.
Thanks.
You need to specify a value for the radio buttons. Since you want to compare based on $index, that's the value to set.
<input type="radio" name="color" value="{{$index}}" v-model="picker">
To control whether something displays, use the v-show binding:
v-show="+$index === +picker"
I use unary + to ensure that both are numeric.
new Vue({
el: 'body',
data: {
picker: 1,
images: [
{img_src: 'http://cl.jroo.me/z3/q/R/R/d/a.aaa-Unique-Nature-Beautiful-smal.jpg'},
{img_src: 'http://www.nature.com/nature/journal/v477/n7365/images/477415a-f1.2.jpg'},
{img_src: 'http://scr.templatemonster.com/35100/35151_gall_nature_small_3.jpg'}
],
colors: [
{id: 1, name: 'Black'},
{id: 2, name: 'Red'},
{id: 3, name: 'Green'}
]
}
});
ul {
list-style: none;
}
ul li img {
width: 110px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.16/vue.js"></script>
<ul class="Items">
<li v-for="image in images">
<img v-show="+$index === +picker" :src="image.img_src" >
</li>
</ul>
<ul class="Colors">
<li v-for="color in colors">
<input type="radio" name="color" value="{{$index}}" v-model="picker">
<span>{{ color.name }}</span>
</li>
</ul>
Related
I have a code in Vue that creates the elements of a menu using a v-for, and each element must have a different method when it's clicked.
So far I have this:
<span v-for="(menuItem, index) in menuItems" :key="index">
<li>
<a id="listItem">
<i class="bx" :class="menuItem.icon || 'bx-square-rounded'" />
<span class="links_name" v-on:click=menuItem.click>{{ menuItem.name }}</span>
</a>
<span class="tooltip">{{
menuItem.tooltip || menuItem.name
}}</span>
</li>
</span>
How can I assign different funcions on the v-on?
You can make the listener function as a node in the object list.
Sample Implementation
const app = new Vue({
el: '#app',
data() {
return {
list: [{
name: 'lg',
age: 27,
onClick: function() {
console.log("First Item Clicked");
}
}, {
name: 'camile',
age: 27,
onClick: function() {
console.log("Second Item Clicked");
}
}]
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.0/vue.js"></script>
<body>
<div id="app">
<ul>
<li v-for="(item, index) in list" :key="item.name">
{{item.name}} - {{item.age}}
<button #click="item.onClick()">
Click Me
</button>
</li>
</ul>
<input type="text" v-model="list[0].name">
</div>
</body>
Background: I have a list of checkboxes that is bound to a names array. I am trying to change the class of the specific name once the checkbox is clicked.
Problem: Once a checkbox is clicked it changes the class of all the names instead of the specific name attached to the checkbox.
JSFiddle of the issue:
JSFiddle
HTML
<div id="app">
<ul>
<li v-for="name in names" :key="index">
<input #click="available = !available" type="checkbox">
<label :class="{available:available}" >{{name.name}}</label>
</li>
</ul>
</div>
Vue instance
var app = new Vue({
el: '#app',
data: {
available: false,
names: [{'name':'Jerry'},{'name':'Eddie'},{'name':'Kerry'},{'name':'Jane'}]
}
})
Css
.available{
text-decoration: line-through;
}
Ad the available variable to each name object and use a method to update the available property:
var app = new Vue({
el: '#app',
data: {
names: [
{'name':'Jerry', 'available': false},
{'name':'Eddie', 'available': false},
{'name':'Kerry', 'available': false},
{'name':'Jane', 'available': false}
]
},
methods: {
updateAvailable(index) {
// Update the available property on the specific object with its index
this.names[index].available = !this.names[index].available
}
}
})
Then in your template, call the method updateAvailable:
<div id="app">
<ul>
<li v-for="(name, index) in names" :key="index">
<input #click="updateAvailable(index)" type="checkbox">
<label :class="{available: name.available}" >{{name.name}}</label>
</li>
</ul>
</div>
Move the available property in to each name element and toggle name.available in your template. You can even use v-model on your checkboxes.
const names = [{'name':'Jerry'},{'name':'Eddie'},{'name':'Kerry'},{'name':'Jane'}]
const app = new Vue({
el: '#app',
data: () => ({
names: names.map(name => ({ ...name, available: false }))
})
})
.available {
text-decoration: line-through;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<div id="app">
<ul>
<li v-for="(name, i) in names">
<input :id="`name_${i}`" v-model="name.available" type="checkbox">
<label :for="`name_${i}`" :class="{ available: name.available }">
{{name.name}}
</label>
</li>
</ul>
</div>
In my Angular app I have the following menu:
As you can see I have items (that are a elements) and a checkbox and a label in each of them:
<span class="caption">RAM</span>
<a class="item">
<div class="item-checkbox">
<input type="checkbox" tabindex="0" class="hidden">
<label>4 GB</label>
</div>
</a>
<a class="item">
<div class="item-checkbox">
<input type="checkbox" tabindex="0" class="hidden">
<label>8 GB</label>
</div>
</a>
<a class="item">
<div class="item-checkbox">
<input type="checkbox" tabindex="0" class="hidden">
<label>16 GB</label>
</div>
</a>
How should I add (click) to every item to correctly handle event capturing so if user click on label or on whole item I get the related checkbox selected?
...Or do you know a better way to reach what I mean?
To make sure that clicking on the label toggles the checkbox, include the input element inside of the label (as explained in MDN):
<a class="sub-item item">
<div class="item-checkbox">
<label><input type="checkbox" tabindex="0" class="hidden">4 GB</label>
</div>
</a>
If you also want the label to fill the anchor element, define the CSS as shown below. With this styling in place, clicking on the anchor will toggle the checkbox.
.ui.secondary.menu a.item {
padding: 0px;
}
div.item-checkbox {
width: 100%;
height: 100%;
}
div.item-checkbox > label {
display: block;
padding: .78571429em .92857143em;
}
div.item-checkbox > label > input {
margin-right: 0.25rem;
}
See this stackblitz for a demo.
If you can place all the checkboxes in a container, you can set a single click event listener on the container, and event.target will give you the clicked element and previousElementSibling will select the sibling input.
function doSomething() {
const selectedInput = event.target.previousElementSibling;
selectedInput.checked = selectedInput.checked? false : true;
}
But in case there is a probability that you document structure changes in the future, say for example, if other elements get in between the input and the label, or their order changes, then the sibling selector will fail. To solve this you can use a parent selector instead and select the chechbox input element inside of it.
document.getElementById('container').addEventListener('click', doSomething);
function doSomething() {
const selectedElement = event.target.parentElement.querySelector('input[type="checkbox"]');
selectedElement.checked = selectedElement.checked? false:true;
}
<div id= 'container'>
<span class="caption">RAM</span>
<a class="item">
<div class="item-checkbox">
<input type="checkbox" tabindex="0" class="hidden" value="4 GB">
<label>4 GB</label>
</div>
</a>
<a class="item">
<div class="item-checkbox">
<input type="checkbox" tabindex="0" class="hidden" value="8 GB">
<label>8 GB</label>
</div>
</a>
<a class="item">
<div class="item-checkbox">
<input type="checkbox" tabindex="0" class="hidden" value="16 GB">
<label>16 GB</label>
</div>
</a>
</div>
First of all you should use *ngFor to list all your options:
html:
<a class="item" *ngFor="let choice of checks; let i=index">
<div class="item-checkbox">
<input type="checkbox" tabindex="0" class="hidden" [value]="choice.value" (change)="onCheckChange($event)">
<label>{{choice.title}}</label>
</div>
</a>
component:
public checks: Array<choices> = [
{title: '4 GB', value: '4'},
{title: "8 GB", value: '8'},
{title: "16 GB", value: '16'}
];
public onCheckChange(event) {
// do some things here
}
Further, you should use Reactive Forms to validate your choices:
https://angular.io/guide/reactive-forms
You have to create a boolean array and bind this to your checkboxes.
.ts file
myArray: any[] = [
{
"size": "2GB",
"value":false
},
{
"size": "4GB",
"value":false
},
{
"size": "8GB",
"value":false
}
]
.html file
<div *ngFor="let data of myArray">
<a class="item">
<div class="item-checkbox">
<input type="checkbox" tabindex="0" class="hidden" [(ngModel)]="data.value" (ngModelChange)="changeHandler()">
<label>{{data.size}}</label>
</div>
</a>
</div>
Working demo : link
You could do something like that:
const ramOptions = [
{
id: 1,
size: '4 GB'
},
{
id: 2,
size: '8 GB'
},
{
id: 3,
size: '16 GB'
}
]
And in html:
<a class="item" *ngFor="let option of ramOptions">
<div class="item-checkbox">
<input type="checkbox" tabindex="0" class="hidden" (change)="onSelect(option.id)">
<label>{{option.size}}</label>
</div>
</a>
If in the .js/.ts file, you can create an interface to define the handler. Just as:
onSelect(id: string) {
...
}
I want to change image and that trigger an image update.
This is for example
http://jsbin.com/kuluyike/3/edit?html,js,output
<div id="colorPicker">
<img v-attr="src:color" alt="{{color}}">
<ul>
<li v-repeat="colors">
<label>
<input type="radio" id="{{name}}" name="color" v-model="color" value="{{image}}">
{{name}}
</label>
</li>
</ul>
</div>
var cp = new Vue({
el: '#colorPicker',
data: {
colors: [
{
name: 'red',
image: 'red.jpg'
},
{
name: 'pink',
image: 'pink.jpg'
},
{
name: 'blue',
image: 'blue.jpg'
}
]
}
});
But this is not working on Vue.js version 2.x
How do I change the code so working based on version 2.x
In Vue 2.0, the syntax has changed for attributes, this means, you now have to declare your attributed as the following:
<img :src="color" :alt="color">
<input type="radio" :id="name" :name="color" v-model="color" :value="image">
In Vue 2.0, the syntax for loops has changed from v-repeat to v-for::
<li v-for="(colorInfo, index) in colors">
<input type="radio" :id="colorInfo.name" name="color" v-model="color" :value="colorInfo.image">
In Vue 2.0 development mode, a warning is emitted when you access an undeclared property
data: {
// ...
color: undefined,
},
var cp = new Vue({
el: '#colorPicker',
data: {
color: undefined,
colors: [
{
name: 'red',
image: 'red.jpg'
},
{
name: 'pink',
image: 'pink.jpg'
},
{
name: 'blue',
image: 'blue.jpg'
}
]
}
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
<div id="colorPicker">
<img :src="color" :alt="color">
<ul>
<li v-for="(colorInfo, index) in colors">
<label>
<input type="radio" :id="colorInfo.name" name="color" v-model="color" :value="colorInfo.image">
{{colorInfo.name}}
</label>
</li>
</ul>
</div>
See also: Migration from Vue 1.x - Vuejs
You can use v-for here for looping in Vue 2.x like:
new Vue({
el: '#colorPicker',
data: {
color: null,
colors: [{
name: 'red',
image: 'red.jpg'
},
{
name: 'pink',
image: 'pink.jpg'
},
{
name: 'blue',
image: 'blue.jpg'
}
]
}
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
<div id="colorPicker">
<img :src="color" :alt="color" v-if="color" />
<ul>
<li v-for="c in colors">
<label>
<input type="radio" name="color" v-model="color" :value="c.image"/>
{{c.name}}
</label>
</li>
</ul>
<p v-if="color"><b>Selected image name: </b> {{color}}</p>
</div>
I am a bit stuck at the moment trying to figure out how to active the current clicked element inside a loop. Basically I just want to change some CSS to that item, for example opacity, and know where I actually clicking inside the loop (this one I can handle with onclick I think).
So basically I tried this:
<div class="panel panel-default">
<ul class="list-group">
<li :style="panel.color" v-for="(panel,key,index)in getPanels"
:class="{active: panel === activeItem}" class="list-group-item"
>
A section {{panel.section}} was {{panel.action}}
</li>
</ul>
</div>
data() {
return {
activeItem: null
}
},
.active {
opacity: 0.7;
}
The active class is not getting applied to the specific clicked item. What is wrong – can anyone help?
Your code has a couple problems:
instead of :style="panel.color", you should put in an object, so it should be :style="{ color: panel.color }"
you forgot to add a click handler, i.e., you should add v-on:click="..."
Note: To simplify things, I didn't use your getPanels but use an array instead, it shouldn't affect how you understand how everything works.
const app = new Vue({
el: '#app',
data: {
panels: [
{section: 'One', action: 'Action 1', color: 'red' },
{section: 'Two', action: 'Action 2', color: 'blue' },
{section: 'Three', action: 'Action 3', color: 'green' },
{section: 'Four', action: 'Action 4', color: 'orange' },
{section: 'Five', action: 'Action 5', color: 'purple' }
],
activeItem: -1
},
methods: {
clickHandler(idx) {
this.activeItem = idx
}
}
});
.active {
opacity: 0.7;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<div id="app">
<div class="panel panel-default">
<ul class="list-group">
<li
class="list-group-item"
v-for="(panel, index) in panels"
:class="{active: index === activeItem}"
:style="{ color: panel.color }"
v-on:click="clickHandler(index)"
>
A section {{panel.section}} was {{panel.action}}
</li>
</ul>
</div>
</div>