Render image data from directus - vue.js

[UPDATE: SOLVED]
I am new to directus, I have problem in rendering image data from directus cloud api to my vue project.
How can I render UUID directus image? This is the json image
json image
and this is my vue app code
<script setup>
import Button from './Button.vue'
const { story } = defineProps(['story'])
//console.log(story.img)
</script>
<template>
<div class="card-wrapper shadow-lg shadow-slate-400 m-2 p-2 w-40 md:w-60 rounded-md flex flex-col justify-between">
<div class="content text-white">
<h2 class="text-2xl font-bold">{{ story.title }}</h2>
<!-- <h4 class="headline1 text-md font-semibold">{{ story.headline }}</h4> -->
<p>{{ story.article_body }}</p>
</div>
<div class="cat-ava flex justify-center items-center">
<img :src="`//https://my.directus-api.app/assets/${story.img}`" :alt="`${story.title} image`">
</div>
<div class="btn-wrapper flex justify-center">
<Button name="Read More..." />
</div>
</div>
</template>
this is the result:
result
the title and article body is working but not for the image.
this is what I expected:
expected result
UPDATE
this is how I solved:
the code from vue before:
<img :src="`//https://my.directus-api.app/assets/${story.img}`" :alt="`${story.title} image`">
this is after I fixed it:
<img :src="`https://my.directus-api.app/assets/${story.img}?some_random_token`" :alt="`${story.title} image`">

Related

Only select post Im clicking on (v-for #click vue.js) but its selecting all saved posts because of the v-for, what can I use instead?

Im doing a little blog project to practice vue.js. Im using composition API script setup. When you write a post it saves in localStorage. When you click on the text in the blog it opens up an overlay and a big sized blogtext. its just that its not only showing the one I clicked on but the other earlier blog posts aswell. How can I focus so it only shows the one I click on. Im using tailwind as css.
On this link you can test yourself but here I have some dummytext in before I made it so the note.text will be shown; https://unique-sprinkles-d1a6cd.netlify.app/
<template>
<div v-if="showModal" #click="showModal = false" class="absolute w-screen h-screen bg-black opacity-75 z-10 flex cursor-pointer items-center justify-center">
<div v-for="note in notes" :key="note.id" class="bg-white hover:border-red-400 p-4 rounded-full text-2xl font-bold"><p>{{ note.text }}</p></div>
</div>
<div class="w-6/12 text-center m-auto">
<h1 class="text-4xl font-bold text-indigo-500 m-5">Blog Posts</h1>
<div class="border-2 border-slate-100 rounded-3xl hover:border-red-400" v-for="note in notes" :key="note.id" >
<div class="relative flex flex-col m-0 justify-around cursor-pointer">
<button class="absolute top-0 right-0 w-5 h-5 cursor-pointer rounded-full hover:bg-red-400 p-2.5" #click="deleteBtn(note)">x</button>
<img class="w-24 h-24 p-3.5 rounded-full" :src="note.img">
<p class="text-xs text-right pr-3.5"> {{ note.writer }}</p>
<p class="text-lg font-bold"> {{ note.headline }}</p>
<p #click="showModal = true" class="text-left p-3.5 text-sm"> {{ note.text }}</p>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
const notes = ref([]);
notes.value = JSON.parse(localStorage.getItem('notes'));
function deleteBtn(note){
notes.value.splice(notes.value.indexOf(note), 1);
localStorage.setItem('notes', JSON.stringify(notes.value));
notes.value = JSON.parse(localStorage.getItem('notes'));
console.log(notes.value)
}
const showModal = ref(false)
</script>
after changes it looks like this; How can I make the empty squares dissapear and also the opacity to 0 in the white textarea so no text from the behind shows. Ive tried tailwind opacity functions but doesnt work.
Here's a method you can use for conditional rendering.
When dealing with v-loops without using a child component, you can use index in the loop then conditionally render it with v-if="selectedIndex = index.
In the modal section, you add the v-if like this
<div
v-if="showModal"
#click="showModal = false"
class="absolute w-screen h-screen bg-black opacity-75 z-10 flex cursor-pointer items-center justify-center"
>
<div
v-for="(note, index) in notes"
:key="note.id"
class="bg-white hover:border-red-400 p-4 rounded-full text-2xl font-bold"
>
<p v-if="selectedIndex === index">{{ note.text }}</p>
</div>
</div>
then in the place where you rendered the text to be clicked, you add a click event to update selectedIndex when you click on different rendered contents with their relevant index.
<div
v-for="(note, index) in notes"
:key="note.id"
class="border-2 border-slate-100 rounded-3xl hover:border-red-400"
#click="selectedIndex = index"
>
<div
class="relative flex flex-col m-0 justify-around cursor-pointer"
>
...
</div>
</div>
then in the script tag, just add a ref of the selectedIndex
const selectedIndex = ref(null)
Note:
If your #click="showModal = true" is faster than the selectedIndex update, you will get a "delayed" update. To fix this you want to convert the #click="showModal = true" into a function, which includes the updateIndex and this showModal reassigning.
It would look something like this
<template>
// other parts...
<p #click="updateValues(index)" class="text-left p-3.5 text-sm"> {{ note.text }}</p>
// other parts...
</template>
<script setup>
// ... your other functions above
const updateValues = (index) => {
selectedIndex.value = index
showModal.value = true
}
</script>
Anyhow, I think it would be better to split those 2 items (the modal and the render text) into different components, that way you will be able to have an easier time handling the logic.

Vue RouterLink not working inside a component

I have a very simple vue 3 project. In created a Layout component that has the navigation links which looks like this
<script setup>
import { useRouter } from "vue-router";
</script>
<template>
<div>
<div class="hidden md:flex md:w-64 md:flex-col md:fixed md:inset-y-0">
<div
class="flex-1 flex flex-col min-h-0 border-r border-gray-200 bg-white"
>
<div class="flex-1 flex flex-col pt-5 pb-4 overflow-y-auto">
<div class="flex items-center flex-shrink-0 px-4">
<h1 class="text-3xl font-extrabold text-gray-900">MiniSend</h1>
</div>
<nav class="mt-5 flex-1 px-4 bg-white space-y-2">
<ul>
<li class="mb-4">
<RouterLink to="/dashboard" class="text-gray-700">
Dashboard</RouterLink
>
</li>
<li class="mb-4">
<RouterLink to="/settings" class="text-gray-700">
Settings</RouterLink
>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md:pl-64 flex flex-col flex-1">
<main class="flex-1">
<div class="py-6">
<div class="max-w-7xl mx-auto px-4 sm:px-6 md:px-8">
<h1 class="text-2xl font-semibold text-gray-900">
<slot name="pageTitle"></slot>
</h1>
</div>
<div class="max-w-7xl mx-auto px-4 sm:px-6 md:px-8">
<div class="py-4">
<slot></slot>
</div>
</div>
</div>
</main>
</div>
</div>
</template>
In my Dashboard view I imported the Layout component as seen below
<script setup>
import Layout from "../components/Layout.vue";
</script>
<template>
<Layout>
// ...content
</Layout>
</template>
When the Dashboard view is served, I can see the links but I cannot click the links. I copied the same link code into the Dashboard view file and I was able to click and get routed to the right page.
Why are the links not working inside the component but work inside the view?

Understanding how to properly add pagination with Bootstrap vue

I'm using Vue and Vue Bootsrap. I wrote the following code:
<b-card border-variant="primary" header="Results:" header-bg-variant="primary" header-text-variant="white" align="center">
<div v-if="loading">
<img width="50px" height="50px" src="/assets/img/loading.gif" />
</div>
<div v-else-if="tools.length">
<div id="app" class="container">
<div class="grid">
<article v-for="tool in tools">
<div class="title">
<h3>{{capitalizeFirstLetter(tool.name)}}</h3>
</div>
<div class="description">
{{tool.description}}
</div>
</article>
</div>
</div>
</div>
</b-card>
I want to add pagination. Each page should contain up to 9 cards. In the docs it was suggested to add:
<div class="overflow-auto">
<b-pagination
v-model="currentPage"
:total-rows="rows"
:per-page="perPage"
first-text="First"
prev-text="Prev"
next-text="Next"
last-text="Last"
></b-pagination>
</div>
But how should I wrap the cards and show only 9?
<article v-for="tool in tools.slice((currentPage-1)*perPage,(currentPage-1)*perPage+perPage)" :key=tool>
just slice your array according to the current page
you can check out the fiddle here
https://jsfiddle.net/allanbanis/La8b0k23/21/
PS: I'm not using 9 as perpage value because I copied and pasted only 9 unique entries[Silly me], so each page would look the same if i used 9

scroll between Nav and components Vue

I have created a vue single page this way:
My app.vue
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<template>
<div id="app">
<Navegacion/>
<Cabecera/>
<Contenido/>
<Aside/>
<Footer/>
</div>
</template>
My navigation.vue
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<template>
<div class="flex flex-row blanco">
<div class="item-uno">
<nav class="flex flex-row items-center">
<a #click="desplazar" href="#">Quienes somos</a>
<a #click="desplazar" href="#">Cómo funciona</a>
<a #click="desplazar" href="#">Servicios a empresas</a>
<a #click="desplazar" href="#">Compromiso</a>
</nav>
</div>
<div class="item-dos flex justify-center">
<img id="logo" src="../assets/logo.svg" alt="logo apeteat">
</div>
<div class="item-uno flex justify-center items-center">
<a class="btn blue">Nuevo pedido</a>
<div class="flex flex-row items-center">
<i class="fas fa-shopping-bag"></i>
<p>0,00 €</p>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Navegacion',
props: {
},
methods: {
desplazar: function() {
window.scrollTo(0,200);
}
}
}
</script>
I want to make scroll to the correspondent component when clicking on a navigation link.
I have installed npm scroll-to, and I have tried to add a function methd desplazar but it's not working.
Thanks in advance for your help.
window.scrollTo() is javascript window method, you don't need to install anything to use it.
It works in your code but href="#" always throw you at the top of the page so it's cancelling window.scrollTo().
You need to remove href="#" from your links.
To scroll to component first you need to add ref to it like this:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<template>
<div id="app">
<Navegacion ref="Navegacion" />
<Cabecera ref="Cabecera" />
<Contenido ref="Contenido" />
<Aside ref="Aside" />
<Footer ref="Footer" />
</div>
</template>
and your function should looks like this
scrollToNavegacion() {
window.scrollTo(0, this.$refs.Navegacion.$el.offsetTop);
}

Template is not loading showing error [Vue warn]: Error compiling template:

I'm loading default listing using vuejs. When I browse page it show me following error
[Vue warn]: Error compiling template:
My html template is as bellow:
<template id="results-template">
<div class="results-wrap col-lg-8 col-md-8 ">
<h3>Results:</h3>
<div v-for="category in books" class="col-xs-3 col-sm-3 col-md-3 col-lg-3 pl-0">
<div class="single-vertical-book box">
<div class="book mt-20 text-center">
<img v-bind:src="{{category.URL}}" />
<div class="book-title-latest">
{{category.Title}}
</div>
<div class="book-author-lastest">
<a href="#" v-if="(category.Category == result.id)" v-for="(result,key) in genres" v-bind:key="result.id">
{{result.name}}
</a>
</div>
</div>
</div>
</div>
</div>
</template>
I'm using API to get data. When I inspected API response it's showing me response correctly but vuejs is not showing data in template. My VueJs code is as bellow:
Vue.component('Results',{
template : '#results-template',
props: ['books','genres']
})
and VueJs method is as bellow:
getBooks : function(){
var vm = this;
return $.get('apis.php?gtype=Books')
.done(function(d){
vm.books = JSON.parse(d);
});
}
My created on loading page code is as bellow:
created : function(){
var vm = this;
this.getBooks().done(function(){
........
});
}
Code for data :
data : {
books : []
}
Please help me what's wrong I'm doing?
Your are binding image incorrect way first of all make it correct. Replace your code:
<template id="results-template">
<div class="results-wrap col-lg-8 col-md-8 ">
<h3>Results:</h3>
<div v-for="category in books" class="col-xs-3 col-sm-3 col-md-3 col-lg-3 pl-0">
<div class="single-vertical-book box">
<div class="book mt-20 text-center">
<img :src="category.URL" />
<div class="book-title-latest">
{{category.Title}}
</div>
<div class="book-author-lastest">
<a href="#" v-if="(category.Category == result.id)" v-for="(result,key) in genres" v-bind:key="result.id">
{{result.name}}
</a>
</div>
</div>
</div>
</div>
</div>
</template>
with this code:
<template id="results-template">
<div class="results-wrap col-lg-8 col-md-8 ">
<h3>Results:</h3>
<div v-for="category in books" class="col-xs-3 col-sm-3 col-md-3 col-lg-3 pl-0">
<div class="single-vertical-book box">
<div class="book mt-20 text-center">
<img v-bind:src="{{category.URL}}" />
<div class="book-title-latest">
{{category.Title}}
</div>
<div class="book-author-lastest">
<a href="#" v-if="(category.Category == result.id)" v-for="(result,key) in genres" v-bind:key="result.id">
{{result.name}}
</a>
</div>
</div>
</div>
</div>
</div>
</template>
You've to use :src="category.URL" for image src binding not :src="{{category.URL}}"
Secondly in template call you are using "genres" have you initialized genres array or not? this may also cause for error. 1st check both of causes if problem not solved the check further.