I am trying to add the info icon in AG Grid header for displaying the tooltip when I hover on the icon. I have created the custom tooltip component which shows the tooltip when hovered but when I add the icon the default sorting and filters get removed.
import Vue from "vue";
export default Vue.extend({
template: `
<div>
<div>
{{ params.headerName }}
<v-tooltip bottom max-width="200">
<template v-slot:activator="{ on }">
<i v-on="on" class="custom-info info circle icon"></i>
</template>
<span>{{params.toolTipText}}</span>
</v-tooltip>
</div>
</div>
`,
data: function() {
return {
};
},
beforeMount() {},
mounted() {
// console.log("header components",params.value);
},
methods: {
},
}, );
**
Column Defs Code: **
this is the code
for column defs.
field: "ndc11",
filter: "agNumberColumnFilter",
headerComponent: 'customTooltipIcon',
headerComponentParams: {
headerName: "NDC11",
toolTipText: "NDC11"
},
pinned: "left",
cellClass: params => {
if (
params.data &&
params.data.ion_dispute_code &&
params.data.ion_dispute_code.length &&
(params.data.ion_dispute_code.includes("O") ||
params.data.ion_dispute_code.includes("N") ||
params.data.ion_dispute_code.includes("U") ||
params.data.ion_dispute_code.includes("G"))) {
return "validation-grid-cell-red"
}
},
cellRenderer: "ndc11Render",
sort: "asc"
},
because you're rewriting ag-grid header with you'r custom one, and not adding the sorting and filtering in it
here is an example how it should look like:
export default Vue.extend({
template: `
<div>
<div
v-if="params.enableMenu"
ref="menuButton"
class="customHeaderMenuButton"
#click="onMenuClicked($event)"
>
<i class="fa" :class="params.menuIcon"></i>
</div>
<div class="customHeaderLabel">{{ params.headerName }}</div>
<v-tooltip bottom max-width="200">
<template v-slot:activator="{ on }">
<i v-on="on" class="custom-info info circle icon"></i>
</template>
<span>{{ params.toolTipText }}</span>
</v-tooltip>
<div
v-if="params.enableSorting"
#click="onSortRequested('asc', $event)"
:class="ascSort"
class="customSortDownLabel"
>
<i class="fa fa-long-arrow-alt-down"></i>
</div>
<div
v-if="params.enableSorting"
#click="onSortRequested('desc', $event)"
:class="descSort"
class="customSortUpLabel"
>
<i class="fa fa-long-arrow-alt-up"></i>
</div>
<div
v-if="params.enableSorting"
#click="onSortRequested('', $event)"
:class="noSort"
class="customSortRemoveLabel"
>
<i class="fa fa-times"></i>
</div>
</div>
`;
data: function () {
return {
ascSort: null,
descSort: null,
noSort: null
};
},
beforeMount() {},
mounted() {
this.params.column.addEventListener('sortChanged', this.onSortChanged);
this.onSortChanged();
},
methods: {
onMenuClicked() {
this.params.showColumnMenu(this.$refs.menuButton);
},
onSortChanged() {
this.ascSort = this.descSort = this.noSort = 'inactive';
if (this.params.column.isSortAscending()) {
this.ascSort = 'active';
} else if (this.params.column.isSortDescending()) {
this.descSort = 'active';
} else {
this.noSort = 'active';
}
},
onSortRequested(order, event) {
this.params.setSort(order, event.shiftKey);
}
}
});
example was taken from ag-grid documentation: https://www.ag-grid.com/javascript-grid-header-rendering/#vueCellEditing
also here https://www.ag-grid.com/javascript-grid-header-rendering/#vueCellEditing you could find more details related to how header components works and custom header components should work
Related
I would like to make ready to use components with my classes/stylish, I'm using mixins for the thing, but it seams the properties are not passed. I get the style but not the "items" i.e.
This is the code:
<template>
<span>
<p
class="text-left text-secondary text-caption ml-2 pb-0 pt-0 mb-0 mt-0"
v-if="label"
>
{{ label }}
</p>
<v-autocomplete
:class="getClass"
outlined
single-line
hide-details
v-bind="$props"
/>
</span>
</template>
<script>
import { VAutocomplete } from "vuetify/lib";
export default {
mixins: [VAutocomplete],
data() {
return {};
},
mounted() {
console.log(this.$props);
},
watch: {},
computed: {
getClass() {
return "input-style font-size-input text-light-input placeholder-light border-radius-md select-style mt-0 mb-2";
},
},
methods: {},
};
</script>
Can someone show me an example of SwiperJs slider, using Vue3 option api, not composition Api?
I mean pure javascript with template inside the html.
like
<div>
<div slider container>
<div vfor>
</div>
</div>
</div>
You can use something like this:
<template>
<div
:id="id"
class="swiper-container"
>
<div
class="swiper-wrapper"
#click="$emit('click')"
>
<!-- swipe right template -->
<template v-if="direction === 'right'">
<v-list-item class="swiper-slide" />
<v-list-item class="swiper-slide">
<v-list-item-content>
<slot />
</v-list-item-content>
</v-list-item>
</template>
<!-- swipe left template -->
<template v-if="direction === 'left'">
<v-list-item class="swiper-slide">
<v-list-item-content>
<slot />
</v-list-item-content>
</v-list-item>
<v-list-item class="swiper-slide" />
</template>
</div>
</div>
</template>
<script>
import 'swiper/dist/css/swiper.min.css';
import { Swiper } from 'swiper/dist/js/swiper.esm.js';
export default
{
props:
{
id:
{
type: [String, Number],
required: true
},
direction:
{
type: String,
default: 'right',
validator: value => ['right', 'left'].indexOf(value) !== -1
}
},
mounted () {
const self = this;
const el = '#' + this.id;
const direction = this.direction;
// Initialize Swiper
const swiper = new Swiper(el, {
initialSlide: this.direction === 'left' ? 0 : 1,
resistanceRatio: 0,
speed: 150,
observer: true,
observeParents: true,
});
// Event will be fired after transition
swiper.on('transitionEnd', function () {
const activeIndex = this.activeIndex;
if ((direction === 'right' && activeIndex === 0) || (direction === 'left' && activeIndex === 1)) {
self.$emit('swiped');
// Destroy slider instance and detach all events listeners
this.destroy();
}
});
}
};
</script>
Use can use like this
<template>
<swiper
:slides-per-view="4"
:space-between="30"
#swiper="onSwiper"
#slideChange="onSlideChange"
class="default-slider"
>
<swiper-slide v-for="item in items" :key="item">
<img :src="item" />
</swiper-slide>
</swiper>
</template>
<script>
import { Swiper, SwiperSlide } from 'swiper/vue';
export default {
components: {
Swiper,
SwiperSlide,
},
data() {
return {
items: ['1.jpg','2.jpg','3.jpg','4.jpg','5.jpg','6.jpg','7.jpg']
}
}
}
</script>
Ok...king..
I'm trying to pass a value to child when a click event occur from other component it will change the prop value from parent. But it only shown the first mount value that pass.
topdown component that emit change
<template>
<div class="dropdown">
<button
class="btn btn-secondary dropdown-toggle h-75"
type="button"
id="dropdownMenuButton1"
data-bs-toggle="dropdown"
aria-expanded="false"
>
{{ value }}
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1" role="menu">
<li v-for="option in options" :key="option">
<a
class="dropdown-item"
#click="(value = option);dunder;dundet;"
href="javascript:void(0)"
>{{ option }}</a
>
</li>
</ul>
</div>
</template>
<script>
export default {
name: "TopDown",
data() {
return {
options: ["Edit", "Delete"],
value: "",
};
},
computed:{
dunder(){
return this.$emit("edit-task", this.value)
},
dundet(){
return this.$emit("edit-task-index",this.value)
}
}
};
</script>
<style>
</style>
parent component
<template>
<div
v-for="(item, index) in tasker"
:items="item"
:key="index"
class="border border-dark "
>
<section class="d-flex justify-content-between">
<h4 class="w-50 font-weight-bold fs-5">
<u>{{ item.title }}</u>
</h4>
<TopDown
#edit-task="val"
#edit-task-of="show(item, index)"
:index="index"
/>
</section>
<p class="text-start">{{ item.description }}</p>
<GoTask :showVal="showVal" :bool="bool" />
</div>
</template>
<script>
import TopDown from "#/components/TopDown.vue";
import GoTask from "#/components/GoTask.vue";
export default {
inheritAttrs: false,
components: {
TopDown,
GoTask,
},
data() {
return {
takss: {
items: "sss",
index: "",
},
showVal: "",
bool: false,
};
},
name: "Taski",
props: ["tasker"],
methods: {
show(item, index) {
this.takss.items = item;
this.takss.index = index;
},
val(val) {
if (val == "Edit") {
setTimeout(() => {
console.log(this.takss);
this.showval = this.takss;
console.log(this.showval);
console.log(this.bool)
}, 1000);
this.bool = !this.bool;
}
},
},
};
</script>
<style></style>
child component
<template>
<section
v-if="bools"
class="bg-white"
style="z-index: 20"
#click="closeModal"
></section>
<section
v-if="bools"
class="position-absolute"
style="
z-index: 50;
left: 50%;
top: 50%;
height: 100vh;
margin-top: 20vh;
"
>
<form
class="mt-10"
#submit.prevent="editTask"
>
<input
class="border rounded p-2 mb-2"
v-model.lazy="newTask.title"
placeholder="Title"
type="text"
/>
<textarea
ref="texsearch"
rows="20"
class=" p-2 mb-2"
v-model.lazy="newTask.description"
placeholder="Task Details"
type="text"
></textarea>
<button
class="border rounded p-2 bg-success text-white"
type="submit"
#submit.prevent=""
>
New Task
</button>
</form>
</section>
<button #click="test">dd</button>
</template>
<script>
export default {
inheritAttrs: false,
name: "GoTask",
props: ["tasker", "showVal", "bool"],
data() {
return {
showVals: this.showVal,
bools: this.bool,
newTask: {
title: "",
description: "",
},
};
},
methods: {
test() {
console.log(this.bools);
console.log(this.showVal);
},
ModalOpen() {
this.bools = true;
},
closeModal() {
this.bools = false;
},
showModal() {
this.bools = true;
// auto focus
this.$nextTick(() => {
this.$refs.textsearch.focus();
});
},
showtheVal() {
console.log(this.showtheVal);
},
},
};
</script>
<style></style>
When I click the button form other component that emit change of #edit-task-of and #edit-task the it doesn't send the new value of bool and showval to child component the bool value still false as same as first mount and showVal = "" when click button that run test function to see this two value at child. I'm totally new to vue. Thanks
You do mistake in GoTask component , method test, first console.log(this.bools);, bools is local state which is not updated after prop bool changed, just do correct console.log(this.bool);. You don't need to set props to local state, you can use props directly.
GoTask correct example:
props: ["tasker", "showVal", "bool"],
data() {
return {
newTask: {
title: "",
description: "",
},
};
},
methods: {
test() {
console.log(this.bool);
console.log(this.showVal);
},
codesandbox
I am new to Vue. I am building a simple app that will list all countries and when you click on a particular country it shows you more details about the country. Idea is to open country details in a modal.
I'm stuck with displaying that modal. The modal opens, but in the background. It also opens a detail page.
CountryDetail.vue:
<script>
import axios from 'axios';
export default {
name: 'country-detail',
props: [ 'isDarkTheme' ],
data () {
return {
pending: false,
error: null,
countryInfo: null,
alpha3Code: [],
alpha3CodetoString: [],
}
},
mounted () {
this.pending = true;
axios
.get(`https://restcountries.eu/rest/v2/name/${this.$route.params.country}?fullText=true`)
.then((response) => {
(this.countryInfo = response.data)
this.alpha3CodetoString = this.alpha3Code.join(';');
})
.catch(error => (this.error = error ))
.finally( () => { this.pending = false });
},
filters: {
formatNumbers (value) {
return `${value.toLocaleString()}`
}
}
}
</script>
<template>
<modal v-model="show">
<div class="modal-mask" :class="{ darkTheme : isDarkTheme }" name="modal">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
<h1 v-if="error !== null">Sorry, an error has occurred {{error}}</h1>
<div class="loaderFlex"><div v-if="pending" class="loader"></div></div>
</slot>
</div>
<div v-for="country in countryInfo" class="countryTile modal-body" v-bind:key="country.id">
<slot name="body">
<img v-bind:src="country.flag" alt="Country Flag" class="flag">
<div class="country-details">
<h1>{{country.name}}</h1>
<div class="listDiv">
<ul>
<li><span>Population:</span> {{country.population | formatNumbers }}</li>
<li><span>Capital:</span> {{country.capital}}</li>
<li><span>Iso:</span> {{country.alpha3Code}}</li>
</ul>
<ul>
<li><span>Currencies:</span> {{country.currencies['0'].name}}</li>
<li><span>Languages:</span>
<span
v-for="(language, index) in country.languages"
v-bind:key="index"
class="languages">
{{language.name}}<span v-if="index + 1 < country.languages.length">, </span>
</span>
</li>
</ul>
</div>
</div>
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
<a #click="$router.go(-1)" class="backBtn"><i class="fas fa-arrow-left" />Go Back</a>
</slot>
</div>
</div>
</div>
</div>
</modal>
</template>
Home.vue:
<script>
import axios from 'axios';
export default {
name: 'home',
props: [ 'isDarkTheme' ],
data () {
return {
pending: false,
error: null,
countryInfo: null,
search: '',
darkMode: false,
}
},
mounted () {
this.pending = true;
axios
.get('https://restcountries.eu/rest/v2/all')
.then(response => (this.countryInfo = response.data))
.catch(error => (this.error = error ))
.finally( () => { this.pending = false });
},
filters: {
formatNumbers (value) {
return `${value.toLocaleString()}`
}
},
computed: {
filteredCountries: function () {
return this.countryInfo.filter((country) => {
if (this.region === '' ) {
return country.name.toLowerCase().match(this.search.toLowerCase());
} else if (this.search !== '') {
return country.name.toLowerCase().match(this.search.toLowerCase());
} else {
return ('blbla');
}
})
}
},
}
</script>
<template>
<div class="home" :class="{ darkTheme : isDarkTheme }">
<div class="searchBar">
<div class="searchContainer">
<i class="fas fa-search searchIcon"></i>
<input
class="searchInput"
type="text"
v-model="search"
aria-label="Search for a country..."
placeholder="Search for a country..."
/>
<ul class="searchResults"></ul>
</div>
</div>
<h1 v-if="error !== null">Sorry, an error has occurred {{error}}</h1>
<div class="loaderFlex"><div v-if="pending" class="loader"></div></div>
<div v-if="countryInfo" class="tileGrid" #click="showModal = true">
<div v-for="country in filteredCountries" class="countryTile" v-bind:key="country.id">
<router-link
:to="{ name: 'country-detail', params: {country: country.name }}"
class="linkTile"
>
<img v-bind:src="country.flag" alt="Country Flag" class="flag">
<div class="text">
<h1>{{ country.name }}</h1>
</div>
</router-link>
</div>
</div>
</div>
</template>
The router-link will always redirect you to another page, because its basically <a href="..."> see here. You don't need router if you just want to show the detail on a modal, you could just add the modal component inside the Home.vue component, then bind the modal and the countryName with props, then pass them in when clicking a button.
Home.vue:
<template>
<div>
<button #click="showDetail">
Show Detail
</button>
<CountryDetail :countryName="countryName" :showModal="showModal"/>
<div>
</template>
<script>
import CountryDetail from './CountryDetail.vue'
export default {
name: 'Home',
components: { CountryDetail },
data: () => ({
countryName: '',
showModal: false,
}),
methods: {
showDetail() {
this.showModal = true;
},
},
}
</script>
And instead of making request on mounted, you could use watch to do something like watching for the showModal prop, and make request everytime it has a truthy value. Like this:
CountryDetail.vue:
<template>
<modal v-model="showModal">
<!-- modal content -->
</modal>
</template>
<script>
export default {
name: 'CountryDetail',
props: ['countryName', 'showModal'],
watch: {
'showModal': {
deep: true,
handler(val) {
if (val && this.countryName !== '') {
// Make request
}
}
}
}
}
</script>
My question is about core logic for the thing below
1) I have a Section Component and a Modal Component
2) In the Section Component i have an array of objects with title and description
3) In the Modal Component i have a template for the modal (im using Bulma framework for the modal)
Now, in the Section i have 7 buttons with a v-for loop to assign 'is-active' class and on each button click an individual modal opens.
Question: How do i parse data into the modal ? I want my modal to be reusable. So at the start my modal is empty at all. On button1 click i have title1 descr1, on button2 title2 descr2 and etc
My code:
Section Component:
<template>
<base-section name="clusters">
<div class="section-map">
<button
class="section-btn"
v-for="(item, index) in sectionItems"
:key="index"
:class="[`section-btn-num${index + 1}`, {'is-active': item.state}]"
#click="toggleModal(item)"
>
<div class="section-btn__text">
{{ item.title }}
</div>
</button>
</div>
<div class="modal"
v-for="(item, index) in sectionItems"
:key="index"
:class="{'is-active': item.state}"
>
<div class="modal-background"></div>
<div class="modal-content">
</div>
<button
#click="item.state = false"
class="modal-close is-large"
aria-label="close">
</button>
</div>
</base-section>
</template>
<script>
import BaseSection from './Section';
import BaseModal from './Modal';
export default {
components: {
BaseSection,
BaseModal,
},
methods: {
toggleModal: (item) => {
item.state = !item.state;
}
},
data() {
return {
sectionItems: [
{
title: 'title1',
},
{
title: 'title2',
description: 'descr',
},
{
title: 'title3',
description: 'descr',
},
{
title: 'title4',
description: 'descr',
},
{
title: 'title5',
description: 'descr',
},
{
title: 'title6',
description: 'descr',
},
{
title: 'title7',
description: 'descr',
},
].map(item => ({ ...item, state: false }))
};
}
};
</script>
<styles>
/* are skipped */
</styles>
Modal Component:
<template>
<div class="modal">
<div class="modal-background"></div>
<div class="modal-content">
<div class="modal__header">
<slot name="modal__header">
</slot>
</div>
<div class="modal__body">
<slot name="modal__body">
</slot>
</div>
</div>
<button
#click="item.state = false"
class="modal-close is-large"
aria-label="close">
</button>
</div>
</template>
<script>
import ClustersSection from './ClustersSection';
export default {
components: {
ClustersSection,
},
props: {
}
},
};
</script>
<style lang="scss">
</style>
Since you already defined slots in your component you can pass data to it via slots. E.g.
<your-modal-component>
<template slot="modal__header">
header bla bla a
</template>
<template slot="modal__body">
body anything here like <p> hehe</p>
</template>
</your-modal-component>