All buttons effect only the first button, but not themselves - javascript

card.vue is the template with the toggleLike method and the button tag
<template>
<div
class="p-24 grid grid-cols-1 sm:grid-cols-1 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-3 gap-12"
>
<div
v-for="movie in movies"
:key="movie.imdbID"
>
<card :movieData="movie" />
</div>
</div>
</template>
I have dynamically generated buttons, but whichever I click, every time the first one gets "selected" or diselected (depends on its previous state).
I want to toggle them independently.
<button #click="toggleLike()" class="mr-2">
<i id="but" class="fa-thumbs-up" :class="{ fas: isLiked, far: !isLiked }"></i>
toggleLike() {
if(this.movieData.likes == 0) {
$('#but').removeClass('far');
$('#but').addClass('fas');
this.movieData.likes+1;
}
else {
$('#but').removeClass('fas');
$('#but').addClass('far');}
return this.$store.dispatch("updateMovieLikes", {
imdbID: this.movie.imdbID,
});
},

You should put more code on how you structure your generated buttons, is that an array? If it is then your isLiked should be an array
<div v-for="movie in movies">
<button #click="toggleLike(movie)" class="mr-2">
<i id="but" class="fa-thumbs-up" :class="movie.likes === 0 ? 'fas' : 'far'"></i>
</button>
</div>
methods: {
toggleLike(movie) {
movie.likes = movie.likes === 0 ? 1 : 0;
this.$store.dispatch("updateMovieLikes", {
imdbID: this.movie.imdbID,
});
}
}
Edit: Just a tip you dont need jquery in vue

Welcome to SO, You could actually shift-away from jquery with vue. You already made a dynamic class binding on your but element therefore you can remove the jquery class handling on your method.
template:
<button #click="toggleLike()" class="mr-2">
<i class="fa-thumbs-up" :class="isLiked ? 'fas' : 'far'"></i>
</button>
method:
toggleLike() {
// Add here how you handle the toggling of isLiked data
if (this.movieData.likes === 0) this.movieData.likes++;
return this.$store.dispatch("updateMovieLikes", {
imdbID: this.movie.imdbID,
});
},
Note.
I'm not sure how you generate the buttons dynamically, can you show it on your question? (can't comment yet). You should also show how do you handle the toggling of your isLiked data.

Related

Only the first created button works in JS

Trying to make the "close-circle" button work. this function will create the button multiple times if there are multiple items, each of them is created with a specific id, and once it is clicked, will delete all the data based on that id. Somehow ONLY the first created button works, the rest just do nothing. I believe there is something wrong with the way of creating the addEventListener.
if (inCartItem) {
productsContainer.innerHTML = '';
// item means each item in the object which is the inCartItem
Object.values(inCartItem).map(item => {
productsContainer.innerHTML += `
<div class ="product-incart">
<ion-icon id ="${item.Id}CloseBtm" name="close-circle"></ion-icon>
<img src="${item.src}">
<span>${item.Productname}</span>
</div>
<div class="price-incart">$${item.Price}</div>
<div class="quantity">
<ion-icon name="caret-back-outline"></ion-icon>
<span>${item.inCart}</span>
<ion-icon name="caret-forward-outline"></ion-icon>
</div>
<div class="total">
$${item.inCart * item.Price},00
</div>
`
console.log(item.Id);
document.getElementById(item.Id + "CloseBtm").addEventListener("click", ("click", () => { removeAll(item); }));
})

Array Splice always delete an item from last?

I am facing a problem in deleting item from an array. Array splice supposed to work but its not working like I want. Its always delete the item from last. I am using Vue.js . I am pushing item dynamically to an array. But after click remove its delete from the last. why I am facing this. I am attaching the codes.
<template>
<div>
<span class="badge badge-pill mb-10 px-10 py-5 btn-add" :class="btnClass" #click="addBtn"><i class="fa fa-plus mr-5"></i>Button</span>
<div class="block-content block-content-full block-content-sm bg-body-light font-size-sm" v-if="buttons.length > 0">
<div v-for="(item, index) in buttons">
<div class="field-button">
<div class="delete_btn"><i #click="remove(index)" class="fa fa-trash-o"></i></div>
<flow-button v-model="item.title" :showLabel="false" className="btn btn-block min-width-125 mb-10 btn-border" mainWrapperClass="mb-0" wrapperClass="pt-0" placeholder="Button Title"></flow-button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import flowButton from '../assets/flow-button'
export default {
name: "textArea",
props:{
index : Number
},
data() {
return {
buttons : [],
btnClass : 'badge-primary',
}
}
components : {
flowButton
},
methods : {
addBtn () {
if(this.buttons.length >= 2) {
this.btnClass = 'btn-secondary'
}
if(this.buttons.length < 3) {
this.buttons.push({
title : ''
});
}
},
remove(index) {
this.buttons.splice(index, 1)
}
}
}
</script>
This must be because of your flow-button I have tried to replicate your error but endup to this code. I just replaced the flow-button with input and it works. Try the code below.
Use v-bind:key="index", When Vue is updating a list of elements rendered with v-for, by default it uses an “in-place patch” strategy. If the order of the data items has changed, instead of moving the DOM elements to match the order of the items, Vue will patch each element in-place and make sure it reflects what should be rendered at that particular index. This is similar to the behavior of track-by="$index"
You have missing comma between data and components, I remove the component here it won't cause any error now, and more tips don't mixed double quotes with single qoutes.
<template>
<div>
<span class="badge badge-pill mb-10 px-10 py-5 btn-add" :class="btnClass" #click="addBtn"><i class="fa fa-plus mr-5"></i>Button</span>
<div class="block-content block-content-full block-content-sm bg-body-light font-size-sm" v-if="buttons.length > 0">
<div v-for="(item, index) in buttons" v-bind:key="index">
<div class="field-button">
<div class="delete_btn"><i #click="remove(index)" class="fa fa-trash-o">sdfsdff</i></div>
<input type="text" v-model="item.title" :showLabel="false" className="btn btn-block min-width-125 mb-10 btn-border" mainWrapperClass="mb-0" wrapperClass="pt-0" placeholder="Button Title"/>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'textArea',
props: {
index: Number
},
data () {
return {
buttons: [],
btnClass: 'badge-primary'
}
},
methods: {
addBtn () {
if (this.buttons.length >= 2) {
this.btnClass = 'btn-secondary'
}
if (this.buttons.length < 3) {
this.buttons.push({
title: ''
})
}
},
remove (index) {
this.buttons.splice(index, 1)
}
}
}
</script>
I think that you may be facing a conflict with the index prop of your component. Try to use a different name for the index of your v-for loop:
<div v-for="(item, ind) in buttons">
<div class="field-button">
<div class="delete_btn"><i #click="remove(ind)" class="fa fa-trash-o"></i></div>
<flow-button v-model="item.title" :showLabel="false" className="btn btn-block min-width-125 mb-10 btn-border" mainWrapperClass="mb-0" wrapperClass="pt-0" placeholder="Button Title"></flow-button>
</div>
</div>
Try this. Removing an item correctly using this.
<div v-for="(item, ind) in buttons" :key="JSON.stringify(item)">

Ability to toggle True/False with ( v-if ) in the loop

I am asking about hiding and showing an element in Vue.js
I always use this
<ele v-if="value" />
and then set {value} in Vue Instance data object, then toggle True/False for toggle visible, but now in my situation , my v-if condition put in some element , then this element create with v-for directive
some thing like this
<div v-for="item in items" >
<ele v-if="value" :key="item.i" />
<ele v-if="value" :key="item.i" />
<ele v-if="value" :key="item.i" />
// this button fire a method for Change (toggle) value (used for v-if)
<button #click="ToggleValue" > update </button>
</div>
In my view i have a table contain some rows and each rows have some field ( all field have v-if directive ) and in each rows we have button for fire method
Now what is my question ?!!
At the end my table is doing this , when click on every button ToggleValue method execute and toggle value of (value) object , now all field in all rows change the value ( all thing doing right :D )
but I want click on every button in each row just change the value of that row
I have dummy way
< ele v-if="value(item.id)" />
.........
.........
<button #click="ToggleValue(itme.id)" >
if my index of loop is Const and static I use this way , but now items in loop are dynamic
all thing was in my pen at here , thanks for give me your time
https://codepen.io/hamidrezanikoonia/pen/OQGrPB?editors=1100
Instead of having a single value, turn value into an object (or array) and index it by item.id.
Updated codepen: https://codepen.io/acdcjunior/pen/MQRZmK?editors=1010
In your pen, the JavaScript:
...
],
update_:false
},
methods: {
set_update() {
this.update_ = !this.update_;
}
}
becomes:
...
]
update_: {1: false, 2: false, 3: false}
},
methods: {
set_update(id) {
this.update_[id] = !this.update_[id];
}
}
And the template:
<td :key="getValue.id+4" v-if="update_" mode="in-out" > {{ getValue.rate_curr }} </td>
...
<button #click="set_update()" type="button" class="btn btn-primary"> Update </button>
becomes:
<td :key="getValue.id+4" v-if="update_[getValue.id]" mode="in-out" > {{ getValue.rate_curr }} </td>
...
<button #click="set_update(getValue.id)" type="button" class="btn btn-primary"> Update </button>

How to trigger sibling method in Vue.js

Issue
I can't figure out how to trigger a sibling method in one component
Code
I have a methods like this
methods: {
closeModal: function(){
function closeM(){
$('.modal').css({opacity: 0 , 'visibility':'hidden'});
}
closeM();
},
closeOutside: function(){
$(document).mouseup(function (e){
var container1 = $('.modal__box');
if (!container1.is(e.target) &&
container1.has(e.target).length === 0)
{
this.$emit('closeModal',closeM());
}
});
}
}
my Template
<div class="modal" #click="closeOutside()">
<div class="modal__box z-depth-2 pr">
<div class="modal__header"> {{header}} </div>
<i class="modal__close pa fa fa-times" #click="closeModal() "> </i>
<div class="modal__content">
<slot> </slot>
</div>
</div>
</div>
Question
How to trigger closeModal from closeOutside? I'm new to Vue.js.
In Vue, all your methods will be bound to this, just like any data and computed.
So you can use this.closeModal()
Edit:
I created a fiddle which might help you getting started. Caution: It is a complete rework of your current solution, however it is doing it the 'vue' way.
I am also quite a newcomer to vue, so feel free to improve it.
https://jsfiddle.net/DarkFruits/gr0j9s6x/
this.$emit('closeModal',closeM());
replace with
this.$emit('closeModal',this.closeModal());

Rendering a dynamic input field in React

I have a quiz form here and would like to add input fields for questions when a user clicks the "Add a question" button.
I've been playing around with the code and have been able to populate the state object with some text. Obviously, the goal is to have this be an input component and then somehow rendering this to the screen.
What I'm struggling with is how to render an actual element to the page. I know it's done in the render method of the component just not exactly sure how.
I think I'm getting close. Any help would be appreciated. The code is below.
Thanks!
var QuizForm = React.createClass({
getInitialState : function() {
return { questions : [] }
},
createQuestion : function() {
this.state.questions.push("Test");
// Adds "Test" to state object.
this.setState({
questions : this.state.questions
});
},
render : function() {
return (
<div className="quiz-form well text-center">
<h1 className="header text-center">Quiz Form</h1>
<ul>
{/* Would like question inputs to show up here */}
</ul>
<button onClick={this.createQuestion} className="add-question-btn btn btn-primary" style={{ marginTop : 40 }}>Add Question</button>
</div>
);
}
Just map your this.state.questions array to the HTML element you want.
For instance, if you want to render <li> elements:
render : function() {
return (
<div className="quiz-form well text-center">
<h1 className="header text-center">Quiz Form</h1>
<ul> // magic happens now
{this.state.questions.map(function(state) {
return <li>{state}</li>
})}
</ul>
<button onClick={this.createQuestion}
className="add-question-btn btn btn-primary"
style={{ marginTop : 40 }}>Add Question</button>
</div>
);
}
See an example.
If you want to render <input> tags, you can use the same technique above, but be mindful of the fact that React treats it as a controlled component.
A React best practice would be to map your state.questions array to a dynamically generated HTML component such as:
render : function() {
return (
<div className="quiz-form well text-center">
<h1 className="header text-center">Quiz Form</h1>
<ul> // magic happens now
{this.state.questions.map(function(state) {
return <li key={state.someId}>{state.question}</li>
})}
</ul>
<button onClick={this.createQuestion}
className="add-question-btn btn btn-primary"
style={{ marginTop : 40 }}>Add Question</button>
</div>
);
}
Please keep in mind that when mapping and rendering dynamic objects in React it's always good to insert a key for each mapped object. So make sure to create that when you're creating the content.
Best Regards,

Categories

Resources