How to target elements inside <script setup> of Vue 3 component? - javascript

How can I target the element with test class inside this vue component:
<template>
<div id="test" class="test">
</div>
</template>
<script setup>
console.log(document.querySelector('.test'))
</script>
This component is imported into another component. The console outputs null.

the component is not rendered before that script is run
You want to wait until it is mounted
<template>
<div id="test" class="test">
</div>
</template>
<script setup>
import { onMounted } from 'vue';
onMounted(() => {
console.log(document.querySelector('.test'))
});
</script>
In general, there's hardly ever any need to use DOM methods like that in vue though - I won't say never, because I know as soon as I say that, someone will come up with a valid reason to
I never have though

The best practice is to use ref instead of DOM manipulations methods, and also use onMounted hook to check the element as mentioned in the following example:
<script setup>
import { ref,onMounted } from 'vue'
const input =ref()
onMounted(()=>{
input.value.focus()
})
</script>
<template>
<input ref="input">
</template>

you can use onMounted for target the element inside vue component:
<script setup>
import { onMounted } from 'vue'
onMounted(() => {
console.log(document.querySelector('.test'));
})
</script>
but I recommend use ref instead of DOM manipulations method:
<script setup>
import { ref, onMounted } from 'vue'
const el = ref()
onMounted(() => {
el.value // <div>
})
</script>
<template>
<div ref="el"></div>
</template>
docs: https://vuejs.org/api/composition-api-lifecycle.html#onmounted

Related

How to use #heroicons/vue in Nuxt3?

i want to import #heroicons/vue in Nuxt 3 but my icon not appear in frontend.
my setup:
import { HomeIcon, FilmIcon, PlusIcon } from "#heroicons/vue/solid"
my html:
<template v-for="(profileItem, i) in accountSetFields" :key="i">
<ProfileItems :user="user" :item="profileItem" />
<template v-slot:icon>
<component :is="profileItem.icon"></component>
</template>
</ProfileItems>
</template>
the variable profile.Item.icon has a string value of "HomeIcon"
I have tried to pass the value directly to the child component "ProfileItem.vue" but i receive the same error message.
When i pass the value directly as string ("HomeIcon" instead of profile.Item.icon) than it works because it mentioned the attribute from import { HomeIcon, FilmIcon, PlusIcon } from "#heroicons/vue/solid
<component :is="HomeIcon"></component>
Did anyone know how to load the icons dynamically?
That one works well
<script setup>
import { HomeIcon, FilmIcon, PlusIcon } from "#heroicons/vue/24/solid"
const icons = reactive({
home: HomeIcon,
film: FilmIcon,
plus: PlusIcon,
})
</script>
<template>
<component :is="icons.home"></component>
</template>
as explained here, you need the 24 in your import (for the size).
Not sure but this may also help maybe, didn't have to use that myself: https://github.com/tailwindlabs/heroicons/issues/564
Or you can forget about worrying about various icons configuration and fallback to that one (configured once and for all): https://stackoverflow.com/a/72055404/8816585
You can also use it without <component/> and register the icon as a component. Should also work with the composition api.
<template>
<CheckCircleIcon />
</template>
<script>
import { CheckCircleIcon } from "#heroicons/vue/24/solid";
export default {
components: {
CheckCircleIcon,
}
}
</script>

How to call Vue 3 method from outside the app

what I want is to call a method, declared in vue 3 app form outside the component of the page. So what I did sofar:
App.vue
<script setup>
function test(){
console.log('test');
}
</script>
vue.js
import { createApp } from 'vue'
import App from 'App.vue'
window.app = createApp(App).mount('#app')
index.html
<div id="app"></app>
<script src="app.js"></script>
<script>
fuction callTest(){
window.app.test() // <-- this returns undefined
}
</script>
however it worked with vue2. Any idea how to get it work with vue3?
You need to use defineExpose inside in the first file in order to use it outside the component:
<script setup>
function test(){
console.log('test');
}
defineExpose({
test
})
</script>

vuejs how to access a ref inside a child component?

I am new to vuejs and not very experienced in JavaScript. I use Vue3 in Laravel
I have a child component which exposes a ref on an input like this
<input
v-model="raw_input"
ref="raw"
#input="checkLength(limit)"
#keydown="enterNumbers($event)"
type="number"
/>
const raw = ref('');
defineExpose({
raw
})
In the parent
<template lang="">
<PageComponent title="Dashboard">
<SmartVolumeInputVue ref="svi" />
<div class="mt-16 border h-8">
{{ val }}
</div>
</PageComponent>
</template>
<script setup>
import PageComponent from "../components/PageComponent.vue"
import SmartVolumeInputVue from "../components/customInputs/SmartVolumeInput.vue";import { computed, ref } from "vue";
const svi = ref(null)
//let val=svi
//let val=svi.raw
let val=svi.raw.value
</script>
At the bottom of the script there are 3 lines (I only uncomment one at a time)
The first displays this in the template
{ "raw": "[object HTMLInputElement]" }
The second displays nothing
And the third reports an error
Uncaught (in promise) TypeError: svi.raw is undefined
I need some help to get the value of the referenced input in the child component.
Do you need the ref on the element? Or only the value?
If not, just expose the value like this: Live example
// App.vue
<script setup>
import { ref } from 'vue'
import SmartVolumeInputVue from './SmartVolumeInput.vue'
const svi = ref()
</script>
<template>
<SmartVolumeInputVue ref="svi" />
<div>
{{svi?.raw_input}}
</div>
</template>
// SmartVolumeInput.vue
<script setup>
import { ref, defineExpose } from 'vue'
const raw_input = ref(123)
defineExpose({
raw_input
})
</script>
<template>
<input v-model.number="raw_input" type="number" />
</template>

Passing HTML or Components to the Vue Plugin

I have created the basic Vue component which is as follow.
<template>
<div class="example">
/* here render the component or HTML passed by pluing */
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
name: 'Example',
});
</script>
Now I need to create a plugin that will render any HTML or Component passed to the Example.I know the basic syntax of plugins and how to use them in the Vue but don't know how to do this task since I am a newbie to Vue.
export default {
install(vue, opts){
/* how to take the component or HTML and pass to `Example` Component */
}
}
I need to implement these in vue2.
You can use a slot to render an arbitrary HTML inside any of your components.
Your Example Component:
<template>
<div class="example">
<slot />
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
name: 'Example',
});
</script>
Then use it like this:
<template>
<example>
<div>Render me inside the slot</div>
</example>
</template>
And it will result in the following rendered HTML:
<div class="example">
<div>Render me inside the slot</div>
</div>
Then in you plugin you can use your Example component and pass any html you want to it
Update: this how your plugin might look like. Just create a global component inside of it
import Vue from 'vue'
const ExamplePlugin = {
install(Vue){
Vue.component('Example', {
name: 'Example',
template: '<div class="example"><slot /></div>'
})
}
}
Then you can Vue.use(ExamplePlugin) and Example component will be available globally in your application

Laravel 8 pass data from blade to Vue 3

I try to pass data from Laravel blade to Vue with props and I get undefined in console.
I tried also
<example-component :course="{{ $course }}"></example-component>
<example-component course="{{!! $course !!}}"></example-component>
index.blade.php
#extends('layouts.app')
#section('content')
<div id="app">
</div>
<example-component course="{{ $course }}"></example-component>
<script src="{{asset('js/course/app.js')}}"></script>
#endsection
app.js
import { createApp } from 'vue';
import App from './components/App.vue'
import router from '../../router'
createApp(App).use(router).mount("#app")
App.vue
<template>
{{ course }}
</template>
<script>
export default {
props: ['course'],
mounted() {
console.log(this.course)
}
}
</script>
The best practice is to make you component call an API to get the course.
If it's not worth an API try to pass the $course as attr to your #app element. Then you can get your course with getAttribute
<div id="app" course="{{json_encode($course)}}"></div>
in vue.js:
document.getElementById('app').getAttribute('course')

Categories