I have the following barebones component:
<template>
<div v-for="blog in blogs">
<h1 class="text-lg font-medium">{{ blog.title[0].text }}</h1>
<div v-if="blog">
<PrismicRichText :field="blog.body" />
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { usePrismic } from "#prismicio/vue";
import { PrismicRichText } from "#prismicio/vue";
const { client, predicate } = usePrismic();
const blogs = ref({});
async function getContent() {
const res = await client.getByType("post");
blogs.value = res.results.map((blog: any) => blog.data);
}
onMounted(getContent);
</script>
<style scoped></style>
When running this, the title is displayed just fine, but the body isn't displayed at all. I see the two nested div's being displayed, but there's no content. When logging the body, it is looking correctly, an array of objects. What am I doing wrong here?
Related
I developed a vuejs program and run the npx serve command. I go to the directory and run npx serve. I browse the http://localhost:300/myvuefile.html , I get the following output only.
{{count}} inside the button. My code :
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>
<div id="app">
<button #click="count++">{{ count }}</button>
</div>
<script>
import { createApp } from 'vue'
const app = createApp({
data() {
return {
count: 0
}
}
})
app.mount('#app')
</script>
I have to get the value of the count and onclick the count should increment. Instead I get the output as {{count}} only. Please help to fix this issue.
According to the documentation-
When using the global build of Vue, all top-level APIs
are exposed as properties on the global Vue object.
So, either use like this-
const app = Vue.createApp({
data() {
return {
count: 0
}
}
})
app.mount('#app')
<div id="app">
<button #click="count++">{{ count }}</button>
</div>
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>
Or use like this-
const { createApp } = Vue
const app = createApp({
data() {
return {
count: 0
}
}
})
app.mount('#app')
<div id="app">
<button #click="count++">{{ count }}</button>
</div>
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>
I am trying to pass a value into a child component. The child component will then preform the save operation. The parent doesn't need to know anything about it. I am able to pass in the object but not save its updated form.
Parent
<template>
<div v-show="isOpened">
<EditModal #toggle="closeModal" #update:todo="submitUpdate($event)"
:updatedText="editText" :todo="modalPost" />
</div>
</template>
<script setup lang="ts">
import Post from "../components/Post.vue";
import { api } from "../lib/api";
import { ref } from "vue";
import { onMounted } from "vue-demi";
import EditModal from "../components/EditModal.vue";
const postArr = ref('');
const message = ref('');
let isOpened = ref(false);
let modalPost = ref('');
let editText = ref('');
function closeModal() {
isOpened.value = false
}
function openModal(value: string) {
isOpened.value = true
modalPost.value = value
}
// call posts so the table loads updated item
function submitUpdate(value: any) {
console.log("called update in parent " + value)
editText.value = value
posts()
}
</script>
Child EditModal
<template>
<div>
<div>
<textarea id="updateTextArea" rows="10" :value="props.todo.post"></textarea>
</div>
<!-- Modal footer -->
<div>
<button data-modal-toggle="defaultModal" type="button"
#click="update(props.todo.blogId, props.todo.post)">Save</button>
</div>
</div>
</template>
<script lang="ts" setup>
import { api } from "../lib/api";
import { reactive, ref } from "vue";
const props = defineProps({
todo: String,
updatedText: String,
})
const emit = defineEmits(
['toggle','update:todo']
);
function setIsOpened(value: boolean) {
emit('toggle', value);
}
function update(id: string, value: string) {
console.log('the value ' + value)
try {
api.updateBlog(id, value).then( res => {
emit('update:todo', value)
emit('toggle', false);
})
} catch (e) {
console.log('Error while updating post: '+ e)
}
}
</script>
I know the props are read only, therefore I tried to copy it I can only have one model.
I do not see the reason I should $emit to the parent and pass something to another variable to pass back to the child.
I am trying to pass in text to a modal component where it can edit the text and the child component saves it.
Advice?
First, your component should be named EditTodo no EditModal because you are not editing modal. All Edit components should rewrite props to new local variables like ref or reactive, so you can work on them, they won't be read only any more.
Child EditTodo.vue
<template>
<div>
<div>
<textarea id="updateTextArea" rows="10" v-model="data.todo.title"></textarea>
</div>
<div>
<button data-modal-toggle="defaultModal" type="button" #click="update()">Save</button>
</div>
</div>
</template>
<script setup lang="ts">
import { api } from "../lib/api";
import { reactive } from "vue";
const props = defineProps<{ id: number, todo: { title: string} }>()
const emit = defineEmits(['toggle']);
const data = reactive({ ...props })
// I assuming api.updateBlog will update data in database
// so job here should be done just need toogle false modal
// Your array with todos might be not updated but here is
// no place to do that. Well i dont know how your API works.
// Database i use will automaticly update arrays i updated objects
function update() {
try {
api.updateBlog(data.id, data.todo ).then(res => {
emit('toggle', false);
})
}
}
</script>
Parent
<template>
<div>
<BaseModal v-if="todo" :show="showModal">
<EditTodo :id="todo.id" :todo="todo.todo" #toggle="(value) => showModal = value"></EditTodo>
</BaseModal>
</div>
</template>
<script setup lang="ts">
const showModal = ref(false)
const todo = reactive({ id: 5, todo: { title: "Todo number 5"} })
</script>
I separated a modal object with edit form, so you can create more forms and use same modal. And here is a simple, not fully functional modal.
<template>
<div class="..."><slot></slot></div>
</template>
<script setup>
defineProps(['show'])
defineEmits(['toogle'])
</script>
You might want to close modal when user click somewhere outside of modal.
In Nuxt2 there were template $refs that you could access in <script> with this.$refs
I would like to know what is the Nuxt3 equivalent of this is.
I need this to access the innerText of an element. I am not allowed to use querySelector or getElementById etc.
This is the way we write code. I can give html elements ref="fooBar" but I can't access it with this.$refs.fooBar or even this.$refs.
<script setup lang="ts">
import { ref, computed } from 'vue';
const foo = ref('bar');
function fooBar() {
//Do stuff
}
</script>
<template>
//Html here
</template>
With Options API
<script>
export default {
mounted() {
console.log('input', this.$refs['my-cool-div'])
}
}
</script>
<template>
<div ref="my-cool-div">
hello there
</div>
</template>
With Composition API
<script setup>
const myCoolDiv = ref(null)
const clickMe = () => console.log(myCoolDiv)
</script>
<template>
<button #click="clickMe">show me the ref</button>
<div ref="myCoolDiv">
hello there
</div>
</template>
I have a function which gives me list of objects. After update it renders correctly for a second than the list disappears. Any idea why this is happening ?
<script setup lang="ts">
import { getList, Version } from "#/services/firebaseService";
import { ref, watch } from "vue";
import { useRouter } from "vue-router";
const platformRef = ref(
useRouter().currentRoute.value.query.platform?.toString()
);
const abiRef = ref(useRouter().currentRoute.value.query.abi?.toString());
const list = ref([] as Version[]);
watch([platformRef, abiRef], async ([platform, abi]) => {
if (platform) {
list.value = await getList(platform, abi);
console.log(list.value);
}
});
</script>
<template>
<section>
<div class="form-selector">
<div class="form-block">
<o-radio v-model="platformRef" name="platform" native-value="android"
>Android</o-radio
>
<!-- rest of the form to set values for platform and abi -->
</div>
</div>
<div class="card" v-for="item in list" :key="item.name">
{{ item.name }}
</div>
</section>
</template>
and console output looks correctly (shows proxy to the array)
Proxy {}
Object[[Target]]:
Array(1)0:
{name: 'v0.2.0-beta.apk', link: 'https://firebasestorage.googleapis.com/v0/b/...'}
[[Prototype]]: Objectlength: 1
[[Prototype]]: Array(0)
UPDATE when chenged the function inside watch to this:
const result = await getList(platform, abi);
console.log(result);
console.log(result.length)
I get correct array but length 0...
I think that problem is in this string:
list.value = await getList(platform, abi);
You try to set the value field of list, but arrays do not have this field;
Instead, you should use this:
list = await getList(platform, abi);
The documentation is not enough to be able to do the emit. I have seen many tutorials and nothing works, now I am testing this
Child component
<div #click="$emit('sendjob', Job )"></div>
With the Vue DevTools plugin I can see that the data is sent in the PayLoad, but I can't find a way to receive this emit from the other component.
Many people do this
Any other component
<template>
<div #sendjob="doSomething"></div>
</template>
<script>
export default {
methods:{
doSomething(){
console.log('It works')
}
}
}
</script>
In my case it doesn't work
You should import the child component in the parent component and use it instead of the regular div tag.
I'm sharing examples for your reference to achieve emits in Vue 3 using <script setup> and Composition API. I strongly suggest going with <script setup if you are going to use Composition API in Single File Component. However, the choice is yours.
Example with <script setup>: https://v3.vuejs.org/api/sfc-script-setup.html
<!-- App.vue -->
<template>
<UserDetail #user-detail-submitted="userDetailSubmitted"/>
</template>
<script setup>
import UserDetail from './components/UserDetail';
function userDetailSubmitted(name) {
console.log({ name })
}
</script>
<!-- UserDetail.vue -->
<template>
<input type="text" v-model="name" #keyup.enter="$emit('user-detail-submitted', name)" />
</template>
<script setup>
import { ref } from 'vue';
const name = ref('');
</script>
Example using Composition API: https://v3.vuejs.org/api/composition-api.html
<!-- App.vue -->
<template>
<UserDetail #user-detail-submitted="userDetailSubmitted"/>
</template>
<script>
import UserDetail from "./components/UserDetail";
export default {
components: {
UserDetail,
},
setup() {
function userDetailSubmitted(name) {
console.log({ name });
}
return {
userDetailSubmitted
}
},
};
</script>
<!-- UserDetail.vue -->
<template>
<input type="text" v-model="name" #keyup.enter="$emit('user-detail-submitted', name)" />
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const name = ref('');
return {
name,
}
}
}
</script>
You should import this child-component in the parent. And don't rename it to the html's original tag.vue3. You'd better use the Composition API.