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>
Related
I've an array of objects (items) that can be incremented with other items, I show them by looping into the array.
see:
and I would like to high-light an item when I click on it (e.g. : another border-top-color), but I'm failing at targeting one specific element and applying a style without applying the style to the whole array. Any idea?
Template, I'm using vuedraggable, don't mind it:
<template #item="{ element }">
<div
class="item"
:key="element"
#click="
messageItemTitle(element.title);
messageItemID(element.id);
"
>
<div class="item-title">
{{ element.title }}
</div>
<div class="item-subType">
{{ element.type }}
</div>
</div>
</template>
The script : Well, none of what I've coded previously worked, so here's the data only :
data() {
return {
dragItems: dragItemsList, //15 items that I can clone into dropItems
dropItems: [], //Array where I can add the items from dragItems
};
},
You can conditionally apply class:
const app = Vue.createApp({
data() {
return {
items: [{id:1, title: 'aaa', type: 'type1'}, {id:2, title: 'bbb', type: 'type2'}, {id:3, title: 'ccc', type: 'type3'}],
selected: null
};
},
methods: {
message(el) {
this.selected = el.id
}
}
})
app.mount('#demo')
.item {
border: 3px solid transparent;
border-top-color: black;
}
.selected {
border-top-color: green;
}
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>
<div id="demo">
<div v-for="(element, i) in items" :key="i">
<!--<template #item="{ element }">-->
<div
class="item"
:class="selected === element.id && 'selected'"
:key="element"
#click="message(element)"
>
<div class="item-title">
{{ element.title }}
</div>
<div class="item-subType">
{{ element.type }}
</div>
</div>
<!--</template>-->
</div>
</div>
I'm trying to teach myself javascript and Vue.js. I was following the documentation on Vue's site and modifying their demonstrations as an exercise. I wanted to change their looping directive example to dynamically add images to the list from a specified url. I can't seem to get the image to show despite setting the image properties src field. I have verified that everything runs and the field is in fact getting set. I assume I must be misunderstanding something related to the DOM or ordering of events.
Thanks in advance.
HTML
<script src="https://unpkg.com/vue#next"></script>
<div id="list-rendering" class="demo">
<input v-model="imgsrc"></input>
<button v-on:click="setImage"> Set</button>
<ol>
<li v-for="todo in todos">
{{ todo.text }} {{todo.image}}
</li>
</ol>
</div>
CSS
.demo {
font-family: sans-serif;
border: 1px solid #eee;
border-radius: 2px;
padding: 20px 30px;
margin-top: 1em;
margin-bottom: 40px;
user-select: none;
overflow-x: auto;
}
Javascript
const ListRenderingApp = {
data() {
return {
todos: [
{ text: 'Learn JavaScript',
image: new Image(16,16)},
{ text: 'Learn Vue',
image: new Image(16, 16)},
{ text: 'Build something awesome',
image: new Image(16, 16)}
],
imgsrc: ""
}
},
methods:{
setImage(){
this.todos.map(todo => todo.image.src = this.imgsrc)
}
}
}
Vue.createApp(ListRenderingApp).mount('#list-rendering')
When using v-for make sure to add :key. Docs
Also pay attention to your html elements. <img> & <input>.
Also return the result of .map() to this.todos. Docs
new Vue({
el: "#app",
data: {
imgSrc: 'https://via.placeholder.com/150/FF0000',
todos: [
{ text: "Learn JavaScript", image: 'https://via.placeholder.com/150/0000FF' },
{ text: "Learn Vue", image: 'https://via.placeholder.com/150/0000FF' },
{ text: "Play around in JSFiddle", image: 'https://via.placeholder.com/150/0000FF' },
{ text: "Build something awesome", image: 'https://via.placeholder.com/150/0000FF' }
]
},
methods: {
setImage: function(todo){
this.todos = this.todos.map(todo => ({ ...todo, image: this.imgSrc }))
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div>
<small>image url</small>
<input v-model="imgSrc" />
</div>
<br />
<div>
<button #click="setImage()">
Click to set Image
</button>
</div>
<ol>
<li v-for="(todo, i) in todos" :key="i">
<label>
{{ todo.text }}
</label>
<img :src="todo.image" alt="img" width="100" height="100">
</li>
</ol>
</div>
try running this snippet & click the "Click to set Image"
try this.
<div id="list-rendering" class="demo">
<input v-model="imgsrc"></input>
<button v-on:click="setImage"> Set</button>
<ol>
<li v-for="(todo, index) in todos :key="index"">
{{ todo.text }}
<img :src="todo.image"/>
</li>
</ol>
</div>
In my sample, I have three parent divs (colored red) ... First, Second and Third.
Initially I want to put my child div (colored yellow) in the "Second" div.
After this, I want to move the child div between parent divs just by changing columnID.
Here's my test code that does not work...
var dataColumns = [{
id: 1,
text: "First"
},
{
id: 2,
text: "Second"
},
{
id: 3,
text: "Third"
}
]
var viewModel = {
data: ko.observableArray([]),
columns: ko.observableArray([]),
};
dataColumns.forEach(function(c) {
let column = {
id: c.id,
text: c.text,
items: ko.computed(function() {
return ko.utils.arrayFilter(viewModel.data(), function(d) {
return d.columnID() === c.id;
});
}, this)
};
viewModel.columns.push(column);
});
ko.applyBindings(viewModel);
let item = {
columnID: ko.observable(2),
caption: "I am the moving item"
};
viewModel.data.push(item);
function MoveTo(index) {
item.columnID(index);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div data-bind="template: { name: 'columnTemplate', foreach: columns, as: 'column' }"></div>
<script type="text/html" id="columnTemplate">
<div style="background-color: red;">
<div data-bind="text: text"></div>
<div data-bind="template: { name: 'itemTemplate', foreach: column.items, as: 'item' }"></div>
</div>
</script>
<script type="text/html" id="itemTemplate">
<div style="background-color: yellow;">
<div data-bind="text: caption"></div>
</div>
</script>
<button onclick="MoveTo(1)">Move to column 1</button>
<button onclick="MoveTo(2)">Move to column 2</button>
<button onclick="MoveTo(3)">Move to column 3</button>
Fiddle: https://jsfiddle.net/MojoDK/at8grkwe/3/
Is my goal impossible to do with Knockuot?
My reallife project is a kanban system, where the id of the task specify which kanban column the task should be in - and then just by changeing then tasks columnID, the task should be moved to another kanban column.
UPDATE:
I updated snippet and Fiddle to correct the error HeyJude pointed out - but it still doesn't move between columns when clicking the buttons.
It's only a small mistake you've got there.
Change this:
viewModel.columns.push(c);
... into this:
viewModel.columns.push(column);
My JSON looks like this:
users: [
{ 'name': 'User 1'},
{ 'name': 'User 2'},
{ 'name': 'User 3'},
{ 'name': 'User 4'},
{ 'name': 'User 5'},
{ 'name': 'User 6'},
]
Now i am looping this and i am displaying in the same div, But i need to diaplay the data by these conditions:
Up to length 3 should display in one div and rest things should display in another div(Ex another div right to that div). Here the JSON will be dynamic, The length may be <3 or >3. My requirement looks like this:
JSFiddle link
Vue is convenient to accomplish such tasks.
You need another two computed properties based on users.
template:
<div>{{left}}</div>
<div>{{right}}</div>
computed: {
left: function(){
return this.users.slice(0, 3);
},
reight: function() {
return this.users.slice(3);
}
}
Another option: https://jsfiddle.net/kth61cLu/1/
<div id="app">
<h3>Users</h3>
<div class="users1">
<div v-for="(user, index) in users" v-if="index < 3">
<p>{{user.name}}</p>
</div>
</div>
<div v-if="users.length > 3" class="users2">
<div v-for="(user, index) in users" v-if="index > 3">
<p>{{user.name}}</p>
</div>
</div>
</div>
Create a computed property that splits your array into two with the first having three elements and the second having the rest.
Then loop over the splitUsers array to display.
new Vue({
el: '#app',
data: {
users: [{"name":"User 1"},{"name":"User 2"},{"name":"User 3"},{"name":"User 4"},{"name":"User 5"},{"name":"User 6"}]
},
computed: {
splitUsers () {
const split = [ this.users.slice(0, 3) ]
if (this.users.length > 3) {
split.push(this.users.slice(3))
}
return split
}
}
})
#app { display: flex; }
#app div { padding: 1rem; border: 1px solid black; }
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<div id="app">
<div v-for="chunk in splitUsers">
<p v-for="user in chunk">{{ user.name }}</p>
</div>
</div>
OK, here is what you can try.
<h3>Users</h3>
<div v-for="(user) in users.slice(0,3)">
<p>{{user.name}}</p>
</div>
<div v-for="(user) in users.slice(3)">
<p>{{user.name}}</p>
</div>
Hope it helps!
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>