Reputation: 3
I created a "box" component that I re-use several times. Each element has a @mouseenter event that the parent listens to. My goal is to change the border-color of the child element. Because I declared the from the parent with a loop I can't change only one of the childs properties but they all change
<template>
<div>
<div id="container">
<div id="row" v-for="i in 11" :key="i">
<div>
<box-component v-for="j in 7" :key="j" :color="getColor(i, j)" v-bind:borderColor="getBorder(i, j)" :row="i" :col="j" v-on:changeBorder="highlightBorder($event)"></box-component>
</div>
</div>
</div>
</div>
</template>
The problem is with this part:
v-bind:borderColor="getBorder(i, j)"
Because i and j have changed I don't know how to only affect one child.
I know that I could remove the loop and copy paste the same code but there must be another solution to this. I also know that this particular example could be implemented directly on the child component but I need to be able to do it from the parent.
Upvotes: 0
Views: 3720
Reputation: 25634
You can do it this way:
<box-component v-on:change-border="highlightBorder(i, j)"></box-component>
From the docs:
Unlike components and props, event names will never be used as variable or property names in JavaScript, so there’s no reason to use camelCase or PascalCase. Additionally,
v-on
event listeners inside DOM templates will be automatically transformed to lowercase (due to HTML’s case-insensitivity), sov-on:myEvent
would becomev-on:myevent
– makingmyEvent
impossible to listen to.For these reasons, we recommend you always use kebab-case for event names.
Vue.component('parent-component', {
template: '#parent-component',
data() {
return {
defaultStyles: {
color: '#555',
borderColor: '#bbb'
},
highlightedStyles: {
color: '#f50',
borderColor: 'orange'
},
highlighted: {x: null, y: null}
};
},
methods: {
isHighlighted(x, y) {
return x === this.highlighted.x && y === this.highlighted.y;
},
getStyles(x, y) {
return this.isHighlighted(x, y) ? this.highlightedStyles : this.defaultStyles;
},
getColor(x, y) {
return this.getStyles(x, y).color;
},
getBorder(x, y) {
return this.getStyles(x, y).borderColor;
},
highlightBorder(x, y) {
this.highlighted = {x, y};
}
}
});
Vue.component('box-component', {
template: '#box-component',
props: ['color', 'borderColor']
});
var vm = new Vue({
el: '#app'
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.row:after {
content: '';
display: block;
clear: both;
}
.box {
float: left;
padding: .5em;
border-width: 4px;
border-style: solid;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.21/vue.min.js"></script>
<div id="app">
<parent-component></parent-component>
</div>
<template id="parent-component">
<div>
<div id="container">
<div class="row" v-for="y in 11" :key="`row-${y}`">
<div>
<box-component
v-for="x in 7"
:key="`cell-${x}`"
:color="getColor(x, y)"
:border-color="getBorder(x, y)"
:col="x" :row="y"
@change-border="highlightBorder(x, y)"
></box-component>
</div>
</div>
</div>
</div>
</template>
<template id="box-component">
<div
class="box"
:style="{background: color, borderColor: borderColor}"
@mouseenter="$emit('change-border')"
></div>
</template>
Upvotes: 2