vue3 how to use suspense passing async props to component - async-await

I've been learning about suspense but I still don't figure out how to use it in my use case.
I understand how to use it when you have a component which has the responsibility to fetch data itself, but I show a legacy example which I don't know how to migrate:
ExampleView.vue
<template>
<skeleton-component v-if="isLoading && !hasError">
<alert-component v-if="hasError">
<example-sub-component v-if="!isLoading && !hasError" :data=data />
</template>
<script setup>
const isLoading = ref(true)
const hasError = ref(false)
const data ref(null)
fetchData().then((response) => {
data.value = response
}).catch((e) => {
hasError.value = e
}).finally(() => {
isLoading.value = false
})
</script>
ExampleSubComponent.vue
<template>
{{data}}
</template>
<script setup>
defineProps([data])
</script>
Can I use suspense to simplify my code? I thought suspense would remove all this kind of logic about loading and showing/hiding errors.
But the only way I see to accomplish this is moving the fetchData logic inside ExampleSubComponent but I don't like this approach... In my use case I feel it's the view who has to fetch the data and pass down to components.
I tried this code but not working... suspense is looking for ExampleSubComponent to be async but it's not, the only async logic is the fetchData.
ExampleView.vue
<template>
<suspense>
<template #default>
<example-sub-component v-if="!hasError" :data=data />
<alert-component v-if="hasError">
</template>
<template #fallback>
<slot name="fallback">
<skeleton-component>
</slot>
</template>
</suspense>
</template>
<script setup>
const hasError = ref(false)
const data ref(null)
await fetchData().then((response) => {
data.value = response
}).catch((e) => {
hasError.value = e
})
</script>
I will need to still write this loading/showing hiding errors logic in every view?

Related

Why is usePage().url returning ComputedRefImpl?

I have the following vue page:
<template>
<a :class="isCurrent($page.url)"
</template>
<script setup>
import {usePage} from '#inertiajs/inertia-vue3'
const isCurrent = (url) => {
console.log(url);
console.log(usePage().url);
};
</script>
The url of the page is /comment and if I inspect the page I find exactly that:
However, on the console log, the url is not displayed correctly:
While I can access the page correctly inside the template section using $page.url I cant access it within <script setup> usePage() creates a document where everything is ComputedRefImpl:
How can I access the page object using usePage() without having to pass $page from the template section?
You need to add .value, similiar as with ref https://vuejs.org/api/reactivity-core.html#ref
<script setup>
import {usePage} from '#inertiajs/inertia-vue3'
const isCurrent = (url) => {
console.log(url);
console.log(usePage().url.value);
};
</script>
You need to access the page props ref before accessing url.
usePage().props.value.url

How can I programatically show/hide editLink client side in Vuepress 2?

I want to show the edit link only for privileged users. I have user information that I am using for example for routing, and I can use it in components. However, I have not found any way to show/hide the edit link on each page based on the user roles. It must be done client side. Please help.
I found a way to do this:
Follow the instructions to extend the default theme.
Make your own EditLink component like this:
// EditLink.vue
<template></template>
<script setup>
import { onMounted } from "vue";
import { usePageFrontmatter } from "#vuepress/client";
onMounted(() => {
const fm = usePageFrontmatter();
fm.value.editLink = true; // Replace true with your logic
});
</script>
In the Layout component (see instructions linked above) do this:
// Layout.vue
<template>
<Layout>
<template #page-bottom> <EditLink /></template>
</Layout>
</template>
<script setup>
import Layout from "#vuepress/theme-default/lib/client/layouts/Layout.vue";
import EditLink from "../components/EditLink";
</script>

Removing ui elements from vimeo player

I want to create a simple player and remove some of the ui elements from the vimeo player, but whatever I try it doesn't work...
I have this code to load the data. At the "videoUrl" I set the params, but with no effect
But according to their documentary it should go
https://help.vimeo.com/hc/en-us/articles/360001494447-Using-Player-Parameters
<template>
// <img :src="data.thumbnail_url" alt="" #click="startVideo"/>
<div v-html="data.html" />
</template>
<script>
mounted() {
const videoUrl = `https://player.vimeo.com/video/${this.video_id}?
title=0&
byline=0&
portrait=0`
const requestUrl = `https://vimeo.com/api/oembed.json?url=${videoUrl}`
this.$axios.get(requestUrl).then((response) => {
this.data = response.data
// I also tried to create the iFrame by myself and set the params again in the src but also without any effect.
this.createIframe()
})
},
</script>
createIframe () {
const el_iframe = document.createElement('iframe')
el_iframe.setAttribute('src', `
https://player.vimeo.com/video/${this.video_id}?
title=0&
byline=0&
portrait=0
`)
}
this.$el.appendChild(el_iframe)
}
I also upgraded to a Pro account in case some of these customizations are only possible within that plan.
What I'm missing?
To set this attributes the video owner have to check this toggle button
and if you like to write the attributes in a list style, the ampersand must be in front of the attribute and the question mark in the same line with the the video-id
this.el_iframe.setAttribute('src',
`https://player.vimeo.com/video/${this.video_id}?
title=0
&byline=0
&portrait=0
`)

How do I trigger a reaction when bind:this is used in {#await} in Svelte?

Let us say that I want to have a little UI overlay that points to a DOM element (let us call it "Tap Here"). To get the location of where it should point to: I use bind:this and it works, unless I don't use it in {#await}.
<script>
import TapHere from './TapHere.svelte';
let enableButton;
$: enableButtonRect = enableButton && enableButton.getBoundingClientRect();
let promise = new Promise((resolve) => {
setInterval(resolve, 3000);
});
</script>
{#await promise}
<p>
waiting...
</p>
{:then}
<div>
<button bind:this={enableButton}>Enable</button>
<button>Disable</button>
<TapHere rect={enableButtonRect}/>
</div>
{/await}
https://svelte.dev/repl/4e0e477d6a394a83a2d79b3d1fa50525?version=3.12.1
(enableButtonRect may be a bit of red-herring as this problem manifests it with just trying to pass in enableButton itself to TapHere.) If you remove await, the TapHere goes to the intended location; but with await, TapHere does not get triggered by the enableButtonRect change. What should I do here?
Somehow enableButton is undefined within the promise resolve block even after the promise resolves.
However, if you evaluate enableButton outside of the block, it is correctly undefined while the promise is still pending, and correctly set to [object HTMLButtonElement] once the promise resolves.
There must be an explanation for this behavior, but I do not know it. Hopefully someone can elaborate.
So you can achieve the result you want by moving the <TapHere> component outside the promise block:
<script>
import TapHere from './TapHere.svelte';
let enableButton;
$: enableButtonRect = enableButton && enableButton.getBoundingClientRect();
let promise = new Promise((resolve) => {
setInterval(resolve, 3000);
});
</script>
{#await promise}
<p>
waiting...
</p>
{:then}
<div>
<button bind:this={enableButton}>Enable</button>
<button>Disable</button>
</div>
<p>Inside promise resolve block: {enableButton}</p>
{/await}
<p>Outside promise resolve block: {enableButton}</p>
<TapHere rect={enableButtonRect}/>
Edit
To show the tooltip after a promise resolves, you could do the following:
<script>
import { onMount } from 'svelte';
import TapHere from './TapHere.svelte';
let enableButton;
let disabled = true;
$: enableButtonRect = enableButton && enableButton.getBoundingClientRect() && !disabled;
onMount(() => {
const interval = setInterval(() => { disabled = false }, 3000)
return () => clearInterval(interval)
})
</script>
<div>
<button bind:this={enableButton} {disabled}>Enable</button>
<button>Disable</button>
<TapHere rect={enableButtonRect}/>
</div>
(REPL updated)
https://svelte.dev/repl/e647bc2b1a024e8885ebb96317887710?version=3.12.1

Laravel Vue js : How can I update a component form Javascript like this:

in my blade.php use one component
<loading :prop_show_loading="show_loading"></loading>
Still in my blade.php
This Doesn't work
<script>
var show_loading = true;
</script>
this Does't work too
<script>
window.event = new Vue();
window.event.$emit('prop_show_loading', 'true');
</script>
and my component doing this (window is not defined)
created(){
let App = this;
console.log(global.event);
window.event.$on('close-modal', (event) => {
this.prop_show_loading = true;
})
},
Any idea?
if you need pass the prop_show_loading value from laravel to loading vue component.
you don't use ":" in the head:
<loading prop_show_loading="show_loading"></loading>
and in the loading component use:
export default {
props: ['prop_show_loading'],
...
and than you can use this.prop_show_loading to get the value.

Resources