Here is the situation, I use v-for to display lots of data in JSON as seperate buttons. What I want to do is when i click single one of those buttons, the button's background color will change.
I want to use #click to bind function to each button, and in that function, do
as this
theButtonDOM.style.backgroundColor = 'black';
So, how can I get that DOM whose div element is generated by v-for?
OR any other solution to solve this 'background color change' problem?
Any time you trigger a click event in Vue template, you can access the event adding the special variable $event as argument to the function.
<button #click="my_method($event, other_argument)"></button>
and then access the target of the event inside the method:
methods: {
my_method(event, other_paramethers) {
let button = event.target
}
}
Even just with bind the method to the #click event without any argument, you can access the event as your first argument.
<button #click="my_method"></button>
...
methods: {
my_method($event) {
let button = $event.target
}
}
Then you can play with your button.
Look at this stackoverflow question and the Vue documentation for more details.
You can pass $event
<button #click="changeColor($event)"></button>
Then in your method
this.changeColor = function(evt){ evt.target.style.backgroundColor = 'red'; }
You can use #click and v-bind:class. When you click on an item, its index will be stored in selectedItem. Then v-bind:class automatically will add the class to the item that has an index equal to selectedItem.
new Vue({
el: '#app',
data: {
selectedItem: ""
},
computed:{},
methods: {}
}
)
.selectedItemClass {
background-color:green
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<div v-for="(item,index) in ['aa','bb','cc']"
v-bind:class="{ selectedItemClass : (selectedItem === index) }"
#click="selectedItem = index"
>{{item}}</div>
</div>
I am assuming you want the buttons to act as individual switches and not a radio group, as implemented in the answer by #eag845.
You could add a 'clicked' boolean attribute to your JSON Objects.
arrayOfJSONObjects.forEach(object => object.clicked = false); // Add 'clicked' attribute and init to false
Then use that attribute as a conditional to bind a CSS class using v-bind:class or :class, and then toggle the attribute within #click or whatever event handler function you put inside #click.
<button
v-for="btn in arrayOfJSONObjects"
:class="{ 'button--activated': btn.clicked }"
#click="btn.clicked = !btn.clicked"
>{{btn.foo}}</button>
Stylez
.button {
background-color: white;
}
.button--activated {
background-color: black;
}
Related
I am running a loop with each item that has a **button **that has a **class **that is **binded **to a method. i want to display a certain text for this button, depending on the value returned by the aforementioned method
HTML Template
<button v-for="(item, index) in items"
:key="index"
:class="isComplete(item.status)"
> {{ text_to_render_based_on_isComplete_result }}
</button>
Method
methods: {
isComplete(status) {
let className
// there is another set of code logic here to determine the value of className. below code is just simplified for this question
className = logic ? "btn-complete" : "btn-progress"
return className
}
}
what im hoping to achieve is that if the value of the binded class is equal to "btn-completed", the button text that will be displayed is "DONE". "ON-GOING" if the value is "btn-in-progress"
my first attempt was that i tried to access the button for every iteration by using event.target. this only returned undefined
another option is to make another method that will select all of the generated buttons, get the class and change the textContent based on the class.
newMethod() {
const completed = document.getElementsByClassName('btn-done')
const progress= document.getElementsByClassName('btn-progress')
Array.from(completed).forEach( item => {
item.textContent = "DONE"
})
Array.from(progress).forEach( item => {
item.textContent = "PROGRESS"
})
}
but this may open another set of issues such as this new method completing before isComplete()
i have solved this by returning an array from the isComplete method, and accessed the value by using the index.
<template>
<button v-for="(item, index) in items"
:key="index"
:class="isComplete(item.status)[0]"
:v-html="isComplete(item.status)[1]"
>
</button>
</template>
<script>
export default {
methods: {
isComplete(status) {
let className, buttonText
// there is another set of code logic here to determine the value of className. below code is just simplified for this question
if (className == code logic) {
className = "btn-complete"
buttonText = "DONE"
}
else if (className != code logic) {
className = "btn-progress"
buttonText = "ON-GOING"
}
return [ className, buttonText ]
}
}
}
</script>
I am trying to send the id of the respective object through an on-click event , yet I always end up being sent the synthetic onClick event , how can I change this ?
How my array of objects looks like :
[
{
id:uuidv4(),
data:[]
}
]
My onClick={(id)=>handleOpen(id)}
EDIT: It was recommended to change the renderig of the button in the following way :
<button onClick={(e)=>addPieChartGroup(e.target.id)}>Add</button>
Thank you very much !
you can also do like that so when ever your items got update the map function adjust all index automatically
const dataArray = [ { id:uuidv4(), data:[] } ]
handleClick = (dataObj) =>{ console.log(dataObj) }
In render
dataArray.map((obj, index) => <Button id={index} onClick={handleClick(obj)}> Click Me </Button> )
The first param inside the event handler is always the event itself. You are not changing anything by using id, except the argument name. That way you can access event by accessing id variable, but your id variable still refers to event.
You need to access the correct property to get the id.
onClick={(event)=>handleOpen(event.target.id)}
you can pass id of button tag like this
const handleClick = (id) =>{
console.log(id)
}
<Button id='myButton' onClick={(event) => handleClick(event.target.id)}
I want to change the class of dynamic element on click function for that I tried below solutions but none of these working
handleClick=(event,headerText)=>{
document.getElementsByClassName('sk-reset-filters')[0].className = 'jjjj';
}
handleClick=(event,headerText)=>{
var reset = document.querySelectorAll('.sk-reset-filters.is-disabled')[0];
console.log(reset)
if(reset){
reset.className = 'sk-reset-filters';
console.log(reset)
}
I just want to remove the is-disabled when click. I also tried using setTimout function but doesn't work. Is there anything wrong?
When I console.log(reset) I'm getting below html.
<div class="sk-reset-filters is-disabled">
<div class="sk-reset-filters__reset">Clear all</div>
</div>
You can handle disable or show dom elements with react state in this way:
state={isDisabled:true} // set a state property
handleClick=(e)=>{
e.preventDefault
this.setState({isDisabled:false}) //change !isDisabled to false when clicked
}
render() {
{isDisabled} = this.state
let disabledMarkup = isDisabled ? <div>something</div> : null}
return (<React.Fragment>{disabledMarkup}
<button onClick={this.handleClick}></button>
</React.Fragment>)}
js
I have a method to enable and disable print option which has element id printReport_AId, so the existence of element is dynamic based on selection.
I have a code to get
document.getElementById('printReport_AId')
this returning null everytime , i guess we need something like windows onload or interval method , not sure how to implement in vue.js
I have attached the code below
<template>
<div id = "intro" style = "text-align:center;">
<div class="printIconSection" v-for="report in reports" :key="report.property" >
<div class="Icon" id="printReport_AId" v-if="isOverview">
<font-awesome-icon :icon="report.icon" #click="printWindow()"/>
</div>
</div>
<div class="logo"v-bind:class="{ 'non-print-css' : noprint }">
</div>
</div>
</template>
<script type = "text/javascript">
var vue_det = new Vue({
el: '#intro',
data: {
timestamp: ''
},
created() {
},
methods: {
printWindow() { },
mounted() {
// window.addEventListener('print', this.noprint);
},
computed(){
noprint() {
const printicon = document.getElementById('printReport_AId');
if (printicon != 'null') {
return true;
}
return false;
},
},
}
}
});
</script>
<style>
#media print {
.non-print-css {
display: none;
}
}
</style>
i just tried window.addEventListener that didnt worked for computed .
I need to get the element id dynamically.
whenever i enable the print element , the element id should not be null. similarly,
whenever i dont enable the print element , the element id should be null
From your code, it seems that you're inserting the ID in each iteration of the v-for loop. This means that the ID will not be unique in the event that there is more than one entry in your reports array. Based on your code, this is what I understand that you want to achieve:
each report will contain an isOverview property. It is probably a boolean, so it has a value of true or false
when isOverview is true, the print icon will be shown
when isOverview is false, the print icon will not be shown
based on whether the print icon(s) are shown, you want to toggle the .logo class
This comes the tricky part, as you have multiple isOverview to evaluate. Do you want to toggle the .logo element when:
all reports has isOverview property set to true, or
one or more reports has isOverview property set to true?
If you want to show the .logo element when all reports has isOverview set to true, then you can do this:
computed() {
noprint() {
return this.reports.every(report => report.isOverview);
}
}
Otherwise, if you only want one or more report to have isOverview as true, you can do this instead:
computed() {
noprint() {
return this.reports.some(report => report.isOverview);
}
}
computed would not watch for document methods, because it is not wrapped with vue's setters and getters.
What you can do is mark your div with ref and then access it via this.$refs
<div class="printIconSection" v-for="(report, index) in reports" :key="report.property" >
<div class="Icon" :ref="'printReport_AId' + index" v-if="isOverview">
<font-awesome-icon :icon="report.icon" #click="printWindow()"/>
</div>
</div>
methods(){
noprint(index) {
const printicon = this.$refs['printReport_AId' + index];
if (printicon != null) {
return true;
}
return false;
},
}
When you need to achieve noprint you just call noprint(index)
For each element of array noprint would be different
I'm writing a function to update a custom checkbox when clicked (and I don't want to use native checkbox for some reasons).
The code for checkbox is
<div class="tick-box" :class="{ tick: isTicked }" #click="() => isTicked = !isTicked"></div>
which works find.
However, there are so many checkboxes, so I use object to keep track for each item. It looks like this
<!-- (inside v-for) -->
<div class="tick-box" :class="{ tick: isTicked['lyr'+layer.lyr_id] }" #click="() => {
isTicked['lyr'+layer.lyr_id] = !isTicked['lyr'+layer.lyr_id]
}"></div>
Now nothing happens, no error at all.
When I want to see isTicked value with {{ isTicked }}, it's just shows {}.
This is what I define in the <script></script> part.
export default {
data() {
return {
isTicked: {},
...
};
},
...
}
Could you help me where I get it wrong?
Thanks!
Edit:
I know that declaring as isTicked: {}, the first few clicks won't do anything because its proerty is undefined. However, it should be defined by the first/second click not something like this.
Objects does not reflect the changes when updated like this.
You should use $set to set object properties in order to make them reactive.
Try as below
<div class="tick-box" :class="{ tick: isTicked['lyr'+layer.lyr_id] }" #click="onChecked"></div>
Add below method:
onChecked() {
this.$set(this.isTicked,'lyr'+this.layer.lyr_id, !this.isTicked['lyr'+this.layer.lyr_id])
}
VueJS watches data by reference so to update object in state you need create new one.
onChecked(lyr_id) {
const key = 'lyr'+lyr_id;
this.isTicked = {...this.isTicked, [key]: !this.isTicked[key]};
}