Vuetify on mouseover toggle data object within array list - javascript

I am trying to implement a functionality which will toggle a Vuetify badge element for each array object within the list when the containing div has been hovered over.
I am able to create a hover like functionality within v-for array list using css, which is fairly simple but how can I achieve similar outcome using vuetify components? As I have not found any questions discussing this or demonstrating it, assume it is possible. Have looked into
First Link
Second Link
Second Link
And much more but have not found similar enough example of what I desire.
I have added codepen example of what I currently have.
The badge should only appear on the element which is currently being hovered, however all badge elements are being executed when any element has been hovered on.
CodePen Link
Maybe I have missed out something obvious
HTML Part
<template>
<div id="app">
<div>My favourite fruit is <b>{{favouriteFruit}}</b></div> <br>
<div v-for="(dataArray, index) in testArray" #click="setCurrent(dataArray.name)">
<v-badge
:color="computedFavFruitColor[index]"
right
v-model="show"
>
<template v-slot:badge>
<span><v-icon color="#ECF0FF">{{computedFavFruit[index]}}</v-icon></span>
</template>
<div #mouseover="show = true" #mouseleave="show = false">
{{dataArray.name}}
</div>
</v-badge>
</div>
</div>
</template>
Any further help of suggestions regarding this manner would be appreciated.

While the show property is global, it counts for every item you hover. You want to target the element you hover. So I suggest to keep track of the index of the item you hover like this: https://codepen.io/reijnemans/pen/JjPrayp?editors=1010
<div v-for="(dataArray, index) in testArray" #click="setCurrent(dataArray.name)">
<v-badge
:color="computedFavFruitColor[index]"
right
>
<template v-slot:badge>
<span v-if="show == index"><v-icon color="#ECF0FF">{{computedFavFruit[index]}}</v-icon></span>
</template>
<div #mouseenter="show = index" #mouseleave="show = null">
{{dataArray.name}}
</div>
</v-badge>
</div>
And show = null ipv show = true in data block of vue

Related

Draggable not applied to nested component

In
https://codesandbox.io/s/vskdf
I have a template that is not rendered inside of my vuedraggable. Any ideas why?
InventorySectionGroup.vue:
<template>
<!-- this div renders -->
<div class="inventory-section-group">
<p>{{ itemSectionGroupProps.itemSectionCategoryName }}</p>
<div
v-for="group in itemSectionGroupProps.itemSectionCategoryItemList"
:key="group.itemSectionCategoryId"
>
<inventory-section-group-item :itemDataProps="group">
</inventory-section-group-item>
</div>
<!-- div doesn't render :-(
<draggable v-model="itemSectionGroupProps.itemSectionCategoryItemList">
<transition-group>
<div
v-for="group in itemSectionGroupProps.itemSectionCategoryItemList"
:key="group.itemSectionCategoryId"
>
<inventory-section-group-item :itemDataProps="group">
</inventory-section-group-item>
</div>
</transition-group>
</draggable> -->
</div>
</template>
Fixed errors related to comp. init:
https://codesandbox.io/s/y2cur?file=/src/components/InventorySectionDraggable.vue
Nested dnd can be replicated like:
https://codesandbox.io/s/priceless-perlman-n6psw?file=/src/components/MyContainer.vue
You have several errors in your code (browser console + ESlint), try fixing them, this will highlight several issues that may be blocking at some point.
As for your current issue, you do have some duplicated code: the block that is rendered and the one that is not. This is coming from the fact that the :key needs to be unique. Since your code is the same on the 2 blocks, the key is duplicated and only one is rendered I guess.
If you take the second block with it's
<div :key="group.itemSectionCategoryId">
And update it to some naive unique key like this
<div :key="`${group.itemSectionCategoryId + 1}`">
This will render the 2 blocks as expected I guess.
Here is the end result.
I've decided to go with nested draggable (build satellite data related to inventory groups and items):
https://codesandbox.io/s/x8ur4?file=/src/components/InventorySectionDraggable.vue
I still need to wrap the props around components.
Done:
https://codesandbox.io/s/rmh2n

VueJS: Do not show div if image doesn't exist

I am rendering some div and I have like to not show a div when an image is not there.
An example image is here: https://clips-media-assets2.twitch.tv/AT-cm%7C891283246-preview-480x272.jpg
I am thinking of something like this:
<div v-show="twItem.imageurl">{{twItem.title}}</div>
But it doesn't work. Any help would be appreciated.
This task is not primitive.
No matter if you use v-if or v-show, both compare the same thing, but the result is different. v-if="false" will not render the element at all, whilst v-show="false" will render it, but hidden. (display: none;)
The problem here is, that you simply check if the twItem.imageurl is set and NOT if the image was loaded.
What you might be able to do is using #load:
<template>
<div v-if="twItem.loaded">{{ twItem.title }}</div>
<image :src="twItem.imageurl" #load="twItem.loaded = true">
</template>
See here for a more detailed explanation: https://renatello.com/vue-js-image-loaded/
Use v-if instead of v-show.
<div v-if="twItem.imageurl">{{ twItem.title }}</div>

Card flip with Onclick with cards randered from Json Data

I have a json list which i used to populate a list of react cards which has two sides. I want to flip to the info side when a button is clicked but I can only get it to flip all the cards. i can achieve it with hover within the css then only card hovered over flips.
Below is my card code
<MDBRow class="row">
<ul className="ulWidth">
<li className="liWidth"> {this.state.infos.map(post => {
return (
<div key={post.id} id="menu">
<MDBCol lg="4" className=" mb-3 column flip-card" id="myEltId">
<MDBCard className="card colCardinfoHeightImg flip-card-inner">
<img className="img-fluid infoImage" src={require('../../images/infoImage.png')} />
<MDBCardBody>
<MDBCardTitle className="CardTitle text-uppercase text-bold">{post.infoName}</MDBCardTitle>
<MDBCardText>
<strong>Data Example 1:</strong> {post.jsonData1}<br/>
<strong>Data Example 2:</strong> {post.jsonData2}<br/>
<strong>Data Example 3:</strong> {post.jsonData3}<br/>
</MDBCardText>
</MDBCardBody>
<div class="flip-card-back">
<MDBCard className=" colCardinfoHeight">
<MDBCardBody>
<MDBCardTitle>{post.infoName}</MDBCardTitle>
<MDBCardText>
<p><strong>Data Example 3:</strong>{post.jsonData4}<br/>
<strong>Data Example 3:</strong> {post.jsonData5}
</p>
<hr/>
<p><strong>Data Example 3:</strong> {post.jsonData6}<br/>
</MDBCardText>
<MDBBtn className="infoButton" color="orange" size="lg" onClick={this.clickFlipFunction}>Switch Today</MDBBtn>
</MDBCardBody>
</MDBCard>
</div>
</MDBCard>
</MDBCol>
</div>
);
})}
</li>
</ul>
</MDBRow>
this is the flip function i have attempted at the minute but it flips all the cards that are rendered.
onFlipCard(){
$(document).ready(function(){
$(".flip-card").css("transform", " rotateY(180deg)");
$(".flip-card-inner").css("transform", " rotateY(180deg)");
});
}
it works when i input the above css in the css file with the hover tag used and when the user hovers over it flips only the right card but i need it to be a clickable function.
Create an onClick event handler for the card.
Track whether the card is flipped or not within the component using something like an isCardFlipped state variable.
Whenever onClick is called, toggle the isCardFlipped state value.
Assign dynamic classnames using classnames , to show either flip-card or flip-card-inner based on the value in isCardFlipped
Edit : I would advice against the use of jquery, or to perform direct DOM manipulation. The major benefit of using React, which you might have missed out on, is to be able to update the DOM indirectly via React's internal working : in a gist, this allows only those DOM elements to be updated which have changed versus redrawing the entire DOM altogether. Read more on this here
Right now your event handler is getting all elements with the class "flip-card". That's what this part is doing:
$(".flip-card")
What you'll need instead is to use a reference to the specific element that was clicked, something like:
$(".flip-card").click(function(e){
$(e.target).css("transform", " rotateY(180deg)");
});
Event.target reference

Is there a way to show a div inside a div that has a false v-if statement

I am using Laravel 6 and Vue.js 2.
I am using a for loop to loop through users and display their info in div's as seen below.
I have the Category names stored in user.pivot.demo2. The users are arranged by category via lodash
_.orderBy(this.category.users, ['pivot.demo2', 'pivot.demo3'])
I need the div with the class of row to only display once for each category. I have the category name set to only display if the category name is the first in the list or does not match the previous name. This separates all the users by category when displaying and puts a the category caption on top of their prospective divs and works just fine. But I need the outer div with a class of row to only be made once per category then filled with the users div that has a class of col-lg-4.
In Laravel's Blade I would just use something like
#if(category != the-same-category)
<div class="row">
#endif
if (category == the-same-category)
<div class="col-lg-4">{{ User.name }} </div>
#endif
#if(category != the-same-category)
</div>
#endif
That would allow for the div with a class of row to only show once per category but the inner divs with the class of col-lg-4 to repeat on every loop. It would also close the div at the end of the condition and each category would have their own divs with the user inside of a single row div. I don't seem to be able to find a Vue.js option that will allow this type of behavior. Can anyone suggest a JavaScript or Vue.js solution?
What I have so far is the code below
<div class="outer-div text-center" v-for="(user, index) in the_category.users" :key="user.id">
<div v-if="index === 0 || user.pivot.demo2 != the_category.users[index -1].pivot.demo2">
<div class="text-center header-one">
<h2>{{ user.pivot.demo2 }}</h2>
</div>
<hr />
</div>
<div class="row d-flex justify-content-center"> // display once per category
<div class="outer-profile-div col-md-4"> // display every loop
<div class="user-name text-center">{{ user.name }}</div>
<div class="user-title text-center">{{ user.title }}</div>
</div>
</div>
My overall goal is to display the (.outer-profile-div)'s next o each other and wrap like typical bootstrap divs inside a .row while maintaining the responsive nature of bootstrap. I don't mind using CSS, JavaScript, Vue.js or whatever will deliver the desired results.
I think you are probably looking for something like this. With this code you can keep a parent element while looping only the childs. It gives you the possibilty to use the conditional directives on the childs due to the template tag had became the parent.
-Example from vue-js docs-
Try it to your problem and tell me if it solves it
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>

Vue.js: Use aria-controls with conditional rendering in vue.js

I have two buttons which toggle some additional information on screen.
I added the buttons the aria-controls attribute und I render an id for the infobox.
Now I still get an error, when I validate the html, because I show this infobox only if a variable in the vuex store is true.
I render it with v-if.
So that means if the button was not clicked the element is not in the DOM and therefore the corresponding id is missing and I get an error.
I tried to use v-show because this would only hide it.
But this would still only render one infobox instead of 2.
Is the only way to get this right to make two infoboxes in the template and add the v-show to both? Or is there a nicer way to use aria-controls.
Thanks for any help
Best
m
Edit:
These are my buttons which have aria-controls.
<template>
<div>
<ul v-if="nav.items">
<li
v-for="(item, key) in nav.items"
#keyup.esc="closeInfoBox">
<button to="" aria-controls="item.name" aria-expanded="false">Designathon</button>
</li>
</ul>
</div>
</template>
And this is my infobox component:
<template>
<div class="Infobox" v-if="infoboxOpen" id="//should correspond to aria controls">
<span v-html="infoContent">Some content</span>
</div>
</template>
Which is only shown if infoboxOpen === true (from vuex store) and the content is replaced depending on which of the buttons is pressed.
(I left out some of this stuff, to make the code easier to understand and to focus on my question here).
This is where I could replace the v-if with the v-show but that would still render only one content. And I would like to have it as dynamic as possible, because users can add more infoboxes in the backend...
Hope this helps understanding my issue.
You're almost there, just make aria-controls a dynamic attribute using
:aria-controls="infoboxOpen ? item.name : ''":
<template>
<div>
<ul v-if="nav.items">
<li
v-for="(item, key) in nav.items"
#keyup.esc="closeInfoBox">
<button to="" :aria-controls="infoboxOpen ? item.name : ''" aria-expanded="false">Designathon</button>
</li>
</ul>
</div>
</template>

Categories