Hiding Popover on internal click - javascript

I'm currently using Vue-PopperJS, and have pretty much set it up as they have on the attached link with some slight changes:
<template>
<Popper
ref="popover"
trigger="clickToToggle"
:options="{
placement: position,
}"
>
<slot
slot="reference"
name="activator"
/>
<div class="base-dropdown--dropdown popper">
<slot name="popover" />
</div>
</Popper>
</template>
<script>
import Popper from 'vue-popperjs'
import 'vue-popperjs/dist/vue-popper.css'
export default {
name: 'BaseDropdown',
components: {
Popper
},
props: {
position: {
type: String,
default: 'bottom'
}
}
}
</script>
<style scoped lang="sass">
.base-dropdown
&--dropdown
min-width: 180px
#apply rounded-large shadow-sm
</style>
And for the items inside the popover we created another component like so:
<template>
<div
class="base-dropdown-item"
:class="getDropdownItemClass"
#click="$emit('click')"
>
<slot />
</div>
</template>
<script>
export default {
name: 'BaseDropdownItem',
props: {
hoverable: {
type: Boolean,
required: false
}
},
computed: {
getDropdownItemClass () {
if (this.hoverable) return ['hover:bg-blue']
return []
}
}
}
</script>
<style scoped lang="sass">
.base-dropdown-item
text-overflow: ellipsis
padding: 12px 0 12px 12px
#apply cursor-pointer body-3 flex items-center overflow-hidden text-grey-800 transition-all whitespace-nowrap
&:hover
#apply text-black
</style>
My question is, say I click on the popover content (ie, a button that does something), how can I trigger it to close the popover too?
I know there is an event to hide it but I'm not sure how to use it.
Should you need more information please don't hesitate to ask!

Not sure how 'efficient' this solution is. However, Chase DeAnda's comment gave me an idea for an elegant solution.
I ended up using the EventBus that would $emit('close-popver'). This emit would be from whatever (in this case a <BaseDropDownItem /> component) that calls this method on a #click.
methods: {
handleClick() {
this.$emit('click')
EventBus.$emit('close-popover')
}
}
And to close the popover:
closePopover(){
const { popover } = this.$refs
popover.doClose()
}

Related

Nuxt & Vue Social Chat

I installed the Vue Social Chat module into my Nuxt app and having trouble to understand how the props and color setting work. At present everything works fine, although the whatsapp Icon displayed is black as well as the top bar situated inside the speech bubble. How would I go about changing this in Nuxt. The author says to use css variables, but I have no idea where to put these and how to use them in my code.
Nuxt also does not have an App.vue so i just imported the module directly which seems to work but I am not sure I am doing it correctly.
This is what my current default.vue page looks like. I do not import the module any place else.
<template>
<v-app dark>
<v-main>
<Nuxt />
</v-main>
<div>
<SocialChat
icon
:attendants="attendants"
>
<p slot="header" >Chat to us on whatsapp for any question, or sales related topics.</p>
<template v-slot:button>
<img
src="https://raw.githubusercontent.com/ktquez/vue-social-chat/master/src/icons/whatsapp.svg"
alt="icon whatsapp"
aria-hidden="true"
>
</template>
<small slot="footer">Opening hours: 8am to 6pm</small>
</SocialChat>
</div>
</v-app>
</template>
<script>
import { SocialChat } from 'vue-social-chat'
export default {
name: 'DefaultLayout',
components: {
SocialChat
},
data() {
return {
attendants: [
{
app: 'whatsapp',
label: '',
name: '',
number: '',
avatar: {
src: '',
alt: ''
}
},
// ...
],
}
},
}
</script>
<style>
.container {
max-width: 1200px;
}
</style>
This is mainly what is needed overall
<template>
<div class="layout">
<nuxt />
<social-chat id="social-button" icon :attendants="attendants">
<p slot="header">
Click on one of our attendants below to chat on WhatsApp.
</p>
<template #button>
<img
src="https://raw.githubusercontent.com/ktquez/vue-social-chat/master/src/icons/whatsapp.svg"
alt="icon whatsapp"
aria-hidden="true"
/>
</template>
<small slot="footer">Opening hours: 8am to 6pm</small>
</social-chat>
</div>
</template>
<script>
import { SocialChat } from 'vue-social-chat'
export default {
name: 'DefaultLayout',
components: {
SocialChat,
},
data() {
return {
attendants: [
{
app: 'whatsapp',
label: 'Technical support',
name: 'Alan Ktquez',
number: '5581983383532',
avatar: {
src: 'https://avatars0.githubusercontent.com/u/8084606?s=460&u=20b6499a416cf7129a18e5c168cf387e159edb1a&v=4',
alt: 'Alan Ktquez avatar',
},
},
],
}
},
}
</script>
<style>
:root #social-button {
--vsc-bg-header: orange;
--vsc-bg-footer: #fafafa;
--vsc-text-color-header: yellow;
--vsc-text-color-footer: green;
--vsc-bg-button: pink;
--vsc-text-color-button: purple;
--vsc-outline-color: #333;
--vsc-border-color-bottom-header: teal;
--vsc-border-color-top-footer: #f3f3f3;
}
</style>
Instead of :root #social-button CSS selector, we may have used --vsc-bg-button: pink !important; too but I don't like to nuke CSS specificity.
Also, the style can be scoped but there is no really implication here anyway because you will not get any scoping issue here.
A github repo can be found here: https://github.com/kissu/vue-social
And a hosted working example available here: https://so-vue-social.netlify.app/

How to pass styles to child component and use it as scoped style in Vue?

I have a parent component:
<template>
<ChildComponent :styles="styles" />
</template>
<script>
export default {
data: () => ({
styles: `
p {
color: red
}
`
})
}
</script>
And this is the child component:
<template>
<p>Hello World</p>
</template>
<script>
export default {
props: {
styles: {
type: String,
required: true
}
}
}
</script>
<style scoped>
</style>
Now I want to use those styles provided by the parent component in child as scoped styles. Like for example:
<!-- ChildComponent.vue -->
<style scoped>
p {
color: red
}
</style>
Is there any way to do so?
If you want to target the child elements with scoped styling you have to use the deep selector.
Which can be done with
a >>> b { color : red; }
/deep/ a b { color : red; }
a::v-deep b { color : red; }
Here is the full explanation: https://vue-loader.vuejs.org/guide/scoped-css.html#child-component-root-elements
If you wanna add the style in your child component, based on the parent component which is calling it, you can pass an attribute as a prop and use it as a class into the child component. Following your example:
Parent component:
<template>
<ChildComponent styles="parent-style" />
</template>
Child component:
<template>
<section :class="styles">
<p>Hello World</p>
</section>
</template>
<script>
export default {
props: {
styles: {
type: String,
required: true
}
}
}
</script>
<style lang="scss" scoped>
.parent-style {
p {
color: red;
}
}
</style>
Please note that it does not answer scoped CSS.
I am using CSS modules, still might help or just to improve following approach.
Send class names to child component from parent, such as:
Parent Template
<template>
<header :class="$style.Header">
<!-- send class names to **Child-Component** using `v-bind` through the className attribute -->
<HeaderLogo :className="$style.Header__logo" />
</header>
</template>
Child-Template
<template>
<div :class="className">Blah</div>
</template>
CSS Module
<style lang="scss" module>
.Header {
white-space: nowrap;
&__logo {
width: 100%;
}
}
</style>

Binding a Component property in Vue

Good day everyone! I'm currently learning vue and I'm following a youtube tutorial on building an image carousel from scratch. Here's the code for the Image Carousel parent component:
<template>
<div class = "slides">
<div class = "slides-inner">
<div v-for= "slide in slides">
<Slide v-bind:slide= "slide"></Slide>
</div>
</div>
</div>
<script>
import Slide from './Slide';
export default{
data(){
return{
slides:[
{ src:'src/assets/slide1.jpg' },
{ src:'src/assets/slide2.jpg' },
{ src:'src/assets/slide3.jpg' },
{ src:'src/assets/slide4.jpg' },
{ src:'src/assets/slide5.jpg' }
]
}
},
components: {
Slide
}
}
</script>
<style scoped>
.slides {
align-items: center;
background-color: #666;
color: #999;
display: flex;
font-size: 1.5rem;
justify-content: center;
min-height: 10rem;
}
</style>
and here's the code for the individual image slides:
<template>
<div class="slide">
{{slide.src}}
</div>
</template>
<script>
export default {
data(){
return{}
},
props: {
slide: ['slide']
}
}
</script>
<style scoped>
</style>
The v-bind on the v-for loop on the parent Image Carousel component is supposed to bind the slide.src property to the current slide being looped so that it will display the image in the browser but what I'm getting is a blank browser screen and an error that says the right value of the operator at v-bind is not an object although the tutorial I'm following works exactly as it should with this same code so I'm wondering what I'm doing wrong.
In your slide component, it should be
export default {
data(){
return{}
},
props: {
slide: Object
}
}
You can check valid props type in Vue document
Please also see the Vue Style Guide as prop definitions should be as detailed as possible. An Essential Requirement by the creators of Vue. See Vue Style Guide.

Why height: 0 can not work in css definition

In my project, I use vue.js 2, and i have an img component.
Here is code of it:
<template>
<div class="banner">
<img class="banner-img" :src="bannerImg"/>
</div>
</template>
<script>
export default {
name: 'DetailBanner',
props: {
sightName: String,
bannerImg: String,
gallaryImgs: Array
}
}
</script>
<style lang="stylus" scoped>
.banner
position: relative
overflow: hidden
height: 0
padding-bottom: 55%
.banner-img
width: 100%
The url of img is :
http://img1.qunarzz.com/sight/p0/201404/23/04b92c99462687fa1ba45c1b5ba4ad77.jpg_600x330_bf9c4904.jpg
Here i don't want to display this img, so i set height:0 in CSS.
But unlucky, It fails. I have tested for removing height: 0, and it shows all the same.
why height: 0 can not work, who can help me?
You could take advantage of Vue.js and use v-if to show/hide your image as follow :
<template>
<div class="banner" v-if="showImg">
<img class="banner-img" :src="bannerImg"/>
</div>
</template>
<script>
export default {
name: 'DetailBanner',
props: {
sightName: String,
bannerImg: String,
gallaryImgs: Array
},
data(){
return{
showImg:false
}
}
}
</script>
you could put showImg in your props, by this way you could change the image state using only Vue.js and avoid struggling with CSS

tooltip div with ReactJS

objective
I have a div that I want to make act like a tooltip with reactjs.
HTML
<div>on hover here we will show the tooltip</div>
<div>
<div class="tooltip_custom">this is the tooltip!!</div>
</div>
I am used to angularjs using the ng-show with a condition on the <div> , I was wondering if there is such binding in reactjs , or else how can I do this functionality ?
Thanks
You can make your component to return the following markup
return (
<div>
<div onMouseOver={this.handleMouseIn.bind(this)} onMouseOut={this.handleMouseOut.bind(this)}>on hover here we will show the tooltip</div>
<div>
<div style={tooltipStyle}>this is the tooltip!!</div>
</div>
</div>
);
Where tooltipStyle is assigned like this:
const tooltipStyle = {
display: this.state.hover ? 'block' : 'none'
}
So tooltip depends on component state, now in handleMouseIn and handleMouseOut you need to change component state to make tooltip visible.
handleMouseIn() {
this.setState({ hover: true })
}
handleMouseOut() {
this.setState({ hover: false })
}
Here is working example.
You can start diving in React with this article: Thinking in React.
One option is just to do it in CSS. It's not quite as flexible, but with markup like:
<div className="tooltip-on-hover">Hover here</div>
<div className="tooltip">This is the tooltip</div>
You could do:
.tooltip {
...
visibility: hidden; /* Or display: none, depending on how you want it to behave */
}
.tooltip-on-hover:hover + .tooltip { /* Uses the adjacent sibling selector */
visibility: visible; /* Or display: block */
}
Example:
.tooltip { display: none; }
.tooltip-on-hover:hover + .tooltip { display: block; }
<div class="tooltip-on-hover">Hover here</div>
<div class="tooltip">This is the tooltip</div>
You could also nest the tooltip inside the element so you could use a normal descendant selector like .tooltip-on-hover:hover .tooltip. You could even use a ::before or ::after pseudo-element, there are guides around on how to do this.
I think whatever you want to show as tooltip, just add that to the "title" of the div where you want to show it.
Eg:
<div title="I am the tooltip text">I am the div where you should hover</div>
But if its a custom designed div then go as the answers given before.
Install npm package:
npm install react-tooltip
Usage:
import ReactTooltip from "react-tooltip";
<div data-tip="msg to show" data-for='toolTip1' data-place='top'>Tooltip</div>
<ReactTooltip id="toolTip1" />
You can also use React Mapple ToolTip which is easy to use and customize and also comes with predefined themes.
Disclaimer: I am the author of this library
reactjs-mappletooltip
You can use react-tooltip package. Super easy to use and handy also.
Installation: npm i react-tootip.
Example:
1. import it :
import ReactTooltip from "react-tooltip"
Include it in your component:
<div className="createContent">
**<ReactTooltip />**
<div className="contentPlaceholder">
add tool tip to your button/div or any element: data-tip="add tooltip message"
<button className="addSection" data-tip="add tooltip message" onClick={() => this.onAddChild()}>+</button>
package url: https://www.npmjs.com/package/react-tooltip
import Tooltip from "#material-ui/core/Tooltip";
const HtmlTooltip = withStyles((theme) => ({
tooltip: {
backgroundColor: 'rgba(255,250,228)',
color: 'rgba(0, 0, 0, 0.87)',
maxWidth: 400,
fontSize: theme.typography.pxToRem(12),
border: '1px solid #dadde9',
},
}))(Tooltip);
headerName: 'FEEDBACK',
field: "remarks",
flex: 0.30,
renderCell: (params: GridCellParams) => (
<Grid>
<HtmlTooltip title={params.value} placement="bottom">
<Typography style={{ color: "inherit", cursor: "pointer" }}>{params.value}</Typography>
</HtmlTooltip>
</Grid>
)
In case, if you are using react-bootstrap in your project, then use https://react-bootstrap.github.io/components/overlays/ Overlay with the tooltip.
MouseEnter and MoverLeave need to be used though.
<OverlayTrigger
placement="right"
delay={{ show: 250, hide: 400 }}
overlay={renderTooltip}>
<div>on hover here we will show the tooltip</div>
</OverlayTrigger>

Categories