I have an element part of a modal, like this:
<template>
<portal to="portal-level-3">
<div
v-if="isOpen"
class="fixed z-50 px-4 pb-4 inset-0 flex items-center justify-center"
:class="[isContentHeightGreaterThanHolder ? 'items-baseline' : 'items-center']"
>
<div
class="fixed inset-0 transition-opacity"
enter-active-class="ease-out duration-300"
enter-class="opacity-0"
enter-to-class="scale-100"
leave-active-class="ease-in duration-200"
leave-class="opacity-100"
leave-to-class="opacity-0"
>
<div class="absolute inset-0 bg-gray-500 opacity-75"></div>
</div>
<div
v-if="isOpen"
v-click-outside="closeModal"
ref="refContent"
:class="[
notFullWidth ? '' : 'w-full',
modalWidthClass
]"
class="bg-white rounded-lg overflow-hidden shadow-xl transform transition-all px-4 pt-5 pb-4"
enter-active-class="ease-out duration-300"
enter-class="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enter-to-class="opacity-100 translate-y-0 sm:scale-100"
leave-active-class="ease-in duration-200"
leave-class="opacity-100 translate-y-0 sm:scale-100"
leave-to-class="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<div class="flex mb-4">
<div v-if="title" class="flex-1">
<h3 class="text-lg leading-6 font-medium text-brand">
{{ title }}
</h3>
</div>
<div class="pl-3">
<button
#click.prevent="closeModal()"
type="button"
class="text-gray-400 hover:text-gray-500 focus:outline-none focus:text-gray-500 transition ease-in-out duration-150"
>
<font-awesome-icon class="h-6 w-6" :icon="['fal', 'times']" />
</button>
</div>
</div>
<slot></slot>
</div>
</div>
</portal>
</template>
In the Vue instance, I watch for the modal opening like this:
watch: {
visible(val) {
this.isOpen = val
},
isOpen(val) {
if (val) {
this.$nextTick(() => {
let holderHeight = this.$el.offsetHeight
let contentHeight = this.$refs.refContent.offsetHeight
this.isContentHeightGreaterThanHolder = contentHeight >= (holderHeight - 30)
})
}
}
},
But this results in:
"TypeError: Cannot read property 'offsetHeight' of undefined"
But if I console.log(this.$refs) I get:
{}
refContent: div.bg-white.rounded-lg.overflow-hidden.shadow-xl.transform.transition-all.px-4.pt-5.pb-4.w-full.max-w-xl
##clickoutsideContext: {id: 5, methodName: "closeModal", documentHandler: ƒ, bindingFn: ƒ}
accessKey: ""
align: ""
ariaAtomic: null
ariaAutoComplete: null
ariaBusy: null
ariaChecked: null
ariaColCount: null
ariaColIndex: null
ariaColSpan: null
ariaCurrent: null
ariaDescription: null
ariaDisabled: null
ariaExpanded: null
....
offsetHeight: 805
Why can I not access this.$refs.refContent.offsetHeight? Thanks!
Related
I have a problem, i am trying to search an element by id in the script but it was not working, when i go to show the values in console, i see that it adds after each variable a random hash, and that is why it does not find the id.
How can I avoid those random hashes?
Svelte
console
I tried different declarations, splits and so on, but it always adds it. Help
<script>
import { page } from '$app/stores';
import { onMount, beforeUpdate } from 'svelte';
import { Line } from 'svelte-chartjs';
import { Chart as ChartJS, Title, Tooltip, Legend, LineElement, LinearScale, PointElement, CategoryScale } from 'chart.js';
ChartJS.register(Title, Tooltip, Legend, LineElement, LinearScale, PointElement, CategoryScale);
export let param = String($page.params.slug);
let ruta_api = `${import.meta.env.VITE_WP_API}posts?slug=${param}`;
let ruta_api_chart = '';
let value = [];
let value_chart = [];
let data_chart = new Array;
let id_chart = '';
onMount(async () => {
await loadData();
});
async function loadData() {
const response = await fetch(ruta_api);
const newData = await response.json();
value = [...value, ...newData];
ifChart();
}
beforeUpdate(async () => {
});
async function ifChart(){
//comprobamos si viene una grafica en el contenido
let posicion_chart = value[0].content.rendered.indexOf('m-chart-container-');
if(posicion_chart >= 0){
console.log(id_chart);
const regex = /(?<=m-chart-container-)(.*?)(?=-)/mg;
console.log(value[0].content.rendered.match(regex)[0]);
id_chart = value[0].content.rendered.match(regex);
//recorremos los ids
id_chart.forEach(function(id) {
getChart(id);
let div_chart = 'm-chart-container-'+id+'-1';
console.log('primero');
console.log({div_chart});
console.log('segundo');
console.log(`${div_chart}`);
console.log('tercero');
console.log(div_chart);
document.getElementById(div_chart).innerHTML = '11111';
})
//<Line data={data_chart} options={{ responsive: true }} />
}
};
export async function getChart(id){
ruta_api_chart = `${import.meta.env.VITE_WP_API}m-chart/` + id;
console.log(ruta_api_chart);
const response_chart = await fetch(ruta_api_chart);
const newData_chart = await response_chart.json();
value_chart = newData_chart['m-chart'];
var datos = value_chart['data'][0][1].filter(n => n).map(Number);
data_chart =
{'labels' : value_chart['data'][0][0].filter(n => n),
'datasets': [{
'label' : 'My First dataset',
'borderColor': 'rgb(205, 130, 158)',
'data' : datos
}]
};
};
</script>
{#each value as article}
<div class="hero" style="background-image: url({article.featured_image_url ? article.featured_image_url : '../img/componentes/blog-img-defecto.png'});">
<div class="hero-overlay bg-opacity-60"></div>
<div class="hero-content text-center text-neutral-content">
<div class="max-w-md">
<h1 class="mb-5 text-5xl font-bold text-secondary">{#html article.title.rendered}</h1>
</div>
</div>
</div>
<div class="w-full mb-32 contenidoblog pt-8">
{#html article.content.rendered}
<div class="flex items-center flex-col my-20">
<button onclick="" class="btn btn-sm border-0 w-40 rounded-full bg-primary font-normal hover:bg-accent text-secondary hover:text-primary transition ease-in-out duration-500 transform hover:scale-105 px-10 mt-4 pr-10 relative">
<span class="absolute left-8">Descargar</span>
<span class="material-symbols-outlined absolute right-8">
download
</span>
</button>
</div>
<!--
<div class="flex items-center flex-col w-full bg-accent h-24">
Bloque post relacionados
</div>
-->
<div class="flex items-center flex-col my-20">
<button onclick="" class="btn btn-sm border-0 w-40 rounded-full bg-accent font-normal hover:bg-primary text-primary hover:text-secondary transition ease-in-out duration-500 transform hover:scale-105 px-10 mt-4 pr-10 relative">
<span class="absolute left-6">Suscribete</span>
<span class="material-symbols-outlined absolute right-6">
add_circle
</span>
</button>
</div>
</div>
{/each}
I tried using this api-key provided by RapidAPI for my code. I made sure that the API key entered is correct. I was previously using the .env file,'X-RapidAPI-Host': process.env.COIN_RANKING_HOST, for both the api host and api key but to make sure that the error is not caused by the .env file not loading, I entered both directly. This is my code:
import Header from '../components/Header'
import PortfolioChart from '../components/PortfolioChart'
import BuyTokens from '../components/BuyTokens'
import Notice from '../components/Notice'
import Asset from '../components/Asset'
import { BiDotsHorizontalRounded } from 'react-icons/bi'
import { AiOutlinePlus } from 'react-icons/ai'
import axios from 'axios'
const styles = {
wrapper: 'w-screen h-screen flex flex-col',
mainContainer: 'w-2/3 h-full m-auto flex mt-16',
leftMain: 'flex flex-col w-3/4 h-full p-6 overflow-y-scroll',
portfolioAmountContainer: 'flex flex-col ',
portfolioAmount: 'text-white text-4xl',
portfolioPercent: 'text-white font-bold text-sm',
pastHour: 'text-gray-400',
chartContainer:
'text-5xl flex justify-center w-full h-1/3 text-white mt-11 mb-11',
buyingPowerContainer:
'w-full border-t mb-24 border-b h-16 border-[#30363b] flex justify-between items-center p-4',
buyingPowerTitle: 'text-white font-bolder text-lg',
buyingPowerAmount: 'text-white font-bolder text-xl',
notice: 'flex border border-[#30363b] mx-11 my-4 p-5 flex-col flex-1',
noticeContainer: 'flex-1',
noticeTitle: 'text-gray-500',
noticeMessage: 'text-white font-bold',
noticeCTA: 'font-bold text-green-500 cursor-pointer mt-5',
rightMain:
'flex flex-col flex-1 h-4/5 bg-[#1E2123] mt-6 rounded-lg overflow-y-scroll noScroll',
rightMainItem: 'flex items-center text-white p-5 border-b border-[#30363b]',
ItemTitle: 'flex-1 font-bold',
moreOptions: 'cursor-pointer text-xl',
}
export default function Home({coins}) {
console.log(coins)
return(
<div className={styles.wrapper}>
<Header />
<div className={styles.mainContainer}>
<div className={styles.leftMain}>
<div className={styles.portfolioAmountContainer}>
<div className={styles.portfolioAmount}>
23 SOLANA
</div>
<div className={styles.portfolioPercent}>
+0.0008(+0.57%)
<span className={styles.pastHour}>
Past Hour
</span>
</div>
</div>
<div>
<div className={styles.chartContainer}>
<PortfolioChart />
</div>
</div>
<div className={styles.buyingPowerContainer}>
<div className={styles.buyingPowerTitle}>Buying Power</div>
<div className={styles.buyingPowerAmount}>12 SOLANA</div>
</div>
<div className={styles.notice}>
<div className={styles.noticeContainer}>
<div className={styles.noticeTitle}>
Send Funds
</div>
<div className={styles.noticeMessage}>
Transfer your funds here.
</div>
<BuyTokens />
</div>
</div>
<Notice />
</div>
<div className={styles.rightMain}>
<div className={styles.rightMainItem}>
<div className={styles.ItemTitle}>
Crypto Currencies
</div>
<BiDotsHorizontalRounded className={styles.moreOptions} />
</div>
<Asset coin={"BTC"} price={0.89} />
<Asset coin={"SOL"} price={0.90} />
<Asset coin={"ETH"} price={-1} />
<Asset coin={"USDC"} price={2} />
<div className={styles.rightMain}>
<div className={styles.ItemTitle}>
Lists
</div>
<AiOutlinePlus className={styles.moreOptions} />
</div>
</div>
</div>
</div>
)
}
export const getStaticProps = async () => {
const options = {
method: 'GET',
url: 'https://coinranking1.p.rapidapi.com/coins',
params: {
referenceCurrencyUuid: 'yhjMzLPhuIDl',
timePeriod: '24h',
tiers: '1',
orderBy: 'marketCap',
orderDirection: 'desc',
limit: '50',
offset: '0',
},
headers: {
'X-RapidAPI-Host': 'coinranking1.p.rapidapi.com',
'X-RapidAPI-Key': '23734db4e2msha5580c4a7b981c0p1557d0jsn9c9dcf2b8505',
},
}
const res = await axios.request(options)
const coins = res.data.data.coins
return {
props: { coins },
}
}
The error showing in the terminal is this.The error was very lengthy and I couldn't post the entire error due to character limit. I have put up the initial two lines and the last two lines of the error though.
error - [AxiosError: Request failed with status code 403] {
code: 'ERR_BAD_REQUEST',
...
data: { message: 'You are not subscribed to this API.' }
},
page: '/'
}
I am unable to figure out why I am getting this error. Please help.
I am subscribed to RapidAPI.
I have the following component, I would like to emit a second value isDeleted to the parent:
<template>
<div class="flex items-center">
<button class="btn my-auto inset-y-0 ml-1 mr-3"
:class="isDeleted ? 'btn-danger' : 'btn-secondary'"
#click="switchMode"
>
<Icon name="Trash" class="w-4 h-4" />
</button>
<div class="w-56 relative text-slate-500 mr-2">
<input
id="tabulator-html-filter-value"
name="search"
type="text"
autocomplete="off"
class="form-control w-56 box pr-10"
aria-label="default input example"
:value="modelValue"
#input="$emit('update:modelValue', $event.target.value)"
placeholder="Search..."
/>
<Icon name="Search" class="w-4 h-4 absolute my-auto inset-y-0 mr-3 right-0"/>
</div>
<button
id="tabulator-html-filter-reset"
type="button"
class="btn btn-secondary w-full sm:w-16 mt-2 sm:mt-0 sm:ml-1"
#click="$emit('reset')"
>
Reset
</button>
</div>
</template>
<script>
import Dropdown from '#/components/Dropdown/Dropdown'
import Icon from '#/components/Icons/Icons'
export default {
components: {
Dropdown,
Icon
},
props: {
modelValue: String,
maxWidth: {
type: Number,
default: 300,
},
},
data() {
return {
isDeleted: null,
}
},
emits: ['update:modelValue', 'reset'],
methods: {
switchMode() {
this.isDeleted = this.isDeleted ? null : 'only';
console.log('1'+ this.isDeleted);
}
}
}
</script>
The parent has the following code:
<search-filter v-model="form.search" class="mr-4 w-full max-w-md" #reset="reset" />
I tried following this example: https://dev.to/codybontecou/vuejs-custom-event-emit-multiple-values-221b to add emit the second value isDeleted without success.
Thanks
In child
<button
id="tabulator-html-filter-reset"
type="button"
class="btn btn-secondary w-full sm:w-16 mt-2 sm:mt-0 sm:ml-1"
#click="$emit('reset', isDeleted /* <---- Pass your value */)"
>
In parent
<search-filter
v-model="form.search"
class="mr-4 w-full max-w-md"
#reset="reset($event /* <---- Here got your value */)"
/>
const reset = (isDeleted) =>
{
console.log(isDeleted)
}
I am using vue chevron in accordion inside for loop. When I am clicking a single dropdown, all other chevrons are rotating. How to rotate the specific chevron for the clicked dropdown in vue ? I am using vue chevron package from https://ispal.github.io/vue-chevron/ . My dropdown looks like this -
My vue code:
<div class="accordion" id="accordionExample">
<div
v-for="(data, index) in topicList"
:key="index"
class="card"
>
<div class="card_header" id="headingOne">
<h2 class="mb-0">
<div
class="btn btn-topic example text-left collapsed"
#click="toggle"
type="button"
data-toggle="collapse"
:data-target="'#collapseOne' + index"
aria-expanded="true"
aria-controls="collapseOne"
>
<vue-chevron
:point-down="pointDown"
:duration="duration"
:thickness="thickness"
:angle="angle"
:round-edges="roundEdges"
/>
{{ data.title }}
</div>
</h2>
</div>
<div
:id="'collapseOne' + index"
class="collapse"
aria-labelledby="headingOne"
data-parent="#accordionExample"
>
<div class="card-body">
<ul
v-for="(data, index) in topicList[index].lessons"
:key="index"
#click="getContent(data.lessonId)"
class="list-group py-1"
>
<li class="list-group-item list-style">
{{ data.title }}
</li>
</ul>
</div>
</div>
</div>
</div>
<script>
import VueChevron from "vue-chevron"
export default{
components:{ VueChevron }
data(){
return{
pointDown: false,
thickness: 8,
duration: 500,
angle: 40,
roundEdges: true,
easing: function n(t) {
return t;
}
}
methods: {
toggle() {
this.pointDown = !this.pointDown;
},
}
}
courseAccess() {
this.$axios
.get(this.$api + "api/v1/courses/" + this.courseId, {
headers: {
Authorization: "Bearer " + localStorage.getItem("_utoken"),
},
})
.then((response) => {
// this.topicList = response.data.data.topics.map((element) => {
// return { ...element, pointDown: true };
// });
this.topicList = response.data.data.topics
this.firstTopic = response.data.data.topics[0].lessons[0].lessonId;
this.getFirstContent(this.firstTopic);
this.loadTopics = true;
});
},
All vue-chevron are binding there point-down prop to the same boolean. You could try to use an array of boolean instead and change your toggle method.
<div class="accordion" id="accordionExample">
<div
v-for="(data, index) in topicList"
:key="index"
class="card"
>
<div class="card_header" id="headingOne">
<h2 class="mb-0">
<div
class="btn btn-topic example text-left collapsed"
#click="toggle(index)"
type="button"
data-toggle="collapse"
:data-target="'#collapseOne' + index"
aria-expanded="true"
aria-controls="collapseOne"
>
<vue-chevron
:point-down="pointDown[index]"
:duration="duration"
:thickness="thickness"
:angle="angle"
:round-edges="roundEdges"
/>
{{ data.title }}
</div>
</h2>
</div>
<div
:id="'collapseOne' + index"
class="collapse"
aria-labelledby="headingOne"
data-parent="#accordionExample"
>
<div class="card-body">
<ul
v-for="(data, index) in topicList[index].lessons"
:key="index"
#click="getContent(data.lessonId)"
class="list-group py-1"
>
<li class="list-group-item list-style">
{{ data.title }}
</li>
</ul>
</div>
</div>
</div>
</div>
<script>
import VueChevron from "vue-chevron"
export default{
components:{ VueChevron }
data(){
return{
pointDown: [],
thickness: 8,
duration: 500,
angle: 40,
roundEdges: true,
easing: function n(t) {
return t;
}
}
methods: {
toggle(index) {
this.pointDown[index] = !this.pointDown[index];
},
}
}
EDIT
The problem discussed in the comments could be caused by reactivity issues. To solve these we are trying to initialize pointDown with an array of the correct size.
courseAccess() {
this.$axios
.get(this.$api + "api/v1/courses/" + this.courseId, {
headers: {
Authorization: "Bearer " + localStorage.getItem("_utoken"),
},
})
.then((response) => {
// this.topicList = response.data.data.topics.map((element) => {
// return { ...element, pointDown: true };
// });
this.topicList = response.data.data.topics;
this.pointDown = new Array(this.topicList.length).fill(false);
this.firstTopic = response.data.data.topics[0].lessons[0].lessonId;
this.getFirstContent(this.firstTopic);
this.loadTopics = true;
});
},
My vue template:
<div
class="col-sm-4 col-xs-6 thumb"
v-for="(photo, index) in photos"
#click.prevent="check(index)"
>
<a class="thumbnail" :class="{'active': photo.checked}">
<img class="img-responsive" :src="photo.picture" alt="">
</a>
</div>
My check() method:
check(index) {
if(!("checked" in this.photos[index]))
this.photos[index].checked = true
else
this.photos[index].checked = !this.photos[index].checked
},
Everything seems correct but it's not working. What could the problem be?
Vue cannot detect changes to an index of an array.
Get a reference to the photo object of the index passed to check() and then use Vue.set() to update the array like so:
check(index) {
let photo = this.photos[index];
if (!("checked" in photo)) {
photo.checked = true
} else {
photo.checked = !photo.checked
}
Vue.set(this.photos, index, photo);
},
Here's a fiddle.
How about just #click.prevent="$set(photo, 'checked', !photo.checked)" and forget the handler?
<div class="col-sm-4 col-xs-6 thumb" v-for="(photo, index) in photos"
#click.prevent="$set(photo, 'checked', !photo.checked)">
<a class="thumbnail" :class="{'active': photo.checked}">
<img class="img-responsive" :src="photo.picture" alt="">
</a>
</div>
If you want to use the handler:
<div class="col-sm-4 col-xs-6 thumb" v-for="(photo, index) in photos"
#click.prevent="check(photo)">
And
check(photo) {
this.$set(photo, 'checked', !photo.checked)
},