I had grabbed some code for test purpose, I have tried to fixing "item not define" error but I am stuck.
//Blade View
<v-app id="app" v-cloak><div class="card" :posts="{{$posts}}"></div></v-app>
//Vuejs template
<table striped hover :items="imageList"> <img :scr="'/storage/image/'+data.items.image"></table>
Vue Js:
<script>
export default {
// name: "ExampleComponent",
props: \['posts'\],
data() {
return {
imageList: \[\]
};
},
mounted() {
const fetch = this.fetch_image_list();
},
methods: {
fetch_image_list() {
let items = \[\];
if (Array.isArray(this.posts.data) && this.posts.length.data) {
this.posts.data.forEach((post, key) => {
let currentImage = {
id: post.id,
name: post.name,
image: post.img
};
items.push(currentImage);
});
this.imageList = items;
}
}
}
};
</script>]
item is not define
Isn't it because you are "calling" :
data.items.image instead of items[index].image ?
Related
I am using Vue 3 and what i would like to achieve is to load all images inside a card (Album Card) and only then show the component on screen..
below is an how it looks now and also my code.
Does anybody have an idea how to achieve this?
currently component is shown first and then the images are loaded, which does not seem like a perfect user experience.
example
<template>
<div class="content-container">
<div v-if="isLoading" style="width: 100%">LOADING</div>
<album-card
v-for="album in this.albums"
:key="album.id"
:albumTitle="album.title"
:albumId="album.id"
:albumPhotos="album.thumbnailPhotos.map((photo) => photo)"
></album-card>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import albumCard from "#/components/AlbumCard.vue";
interface Album {
userId: number;
id: number;
title: string;
thumbnailPhotos: Array<Photo>;
}
interface Photo {
albumId: number;
id: number;
title: string;
url: string;
thumbnailUrl: string;
}
export default defineComponent({
name: "Albums",
components: {
albumCard,
},
data() {
return {
albums: [] as Album[],
isLoading: false as Boolean,
};
},
methods: {
async getAlbums() {
this.isLoading = true;
let id_param = this.$route.params.id;
fetch(
`https://jsonplaceholder.typicode.com/albums/${
id_param === undefined ? "" : "?userId=" + id_param
}`
)
.then((response) => response.json())
.then((response: Album[]) => {
//api returns array, loop needed
response.forEach((album: Album) => {
this.getRandomPhotos(album.id).then((response: Photo[]) => {
album.thumbnailPhotos = response;
this.albums.push(album);
});
});
})
.then(() => {
this.isLoading = false;
});
},
getRandomPhotos(albumId: number): Promise<Photo[]> {
var promise = fetch(
`https://jsonplaceholder.typicode.com/photos?albumId=${albumId}`
)
.then((response) => response.json())
.then((response: Photo[]) => {
const shuffled = this.shuffleArray(response);
return shuffled.splice(0, 3);
});
return promise;
},
/*
Durstenfeld shuffle by stackoverflow answer:
https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array/12646864#12646864
*/
shuffleArray(array: Photo[]): Photo[] {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
},
},
created: function () {
this.getAlbums();
},
});
</script>
What i did to solve this problem was using function on load event on (img) html tag inside album-card component. While images are loading a loading spinner is shown. After three images are loaded show the component on screen.
<template>
<router-link
class="router-link"
#click="selectAlbum(albumsId)"
:to="{ name: 'Photos', params: { albumId: albumsId } }"
>
<div class="album-card-container" v-show="this.numLoaded == 3">
<div class="photos-container">
<img
v-for="photo in this.thumbnailPhotos()"
:key="photo.id"
:src="photo.thumbnailUrl"
#load="loaded()"
/>
</div>
<span>
{{ albumTitle }}
</span>
</div>
<div v-if="this.numLoaded != 3" class="album-card-container">
<the-loader></the-loader>
</div>
</router-link>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { store } from "#/store";
export default defineComponent({
name: "album-card",
props: {
albumTitle: String,
albumsId: Number,
},
data: function () {
return {
store: store,
numLoaded: 0,
};
},
methods: {
thumbnailPhotos() {
return this.$attrs.albumPhotos;
},
selectAlbum(value: string) {
this.store.selectedAlbum = value;
},
loaded() {
this.numLoaded = this.numLoaded + 1;
},
},
});
</script>
Important note on using this approach is to use v-show instead of v-if on the div. v-show puts element in html(and sets display:none), while the v-if does not render element in html so images are never loaded.
im trying to get row cout but returning 0 only.
my code
<template>
<div>
<p>{{ resultCount }}</p>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
registerlist: [],
};
},
async asyncData({ $axios }) {
let { data } = await $axios.$get("/Businessregisterlist");
// console.log(response)
return {
registerlist: data,
};
},
computed: {
resultCount() {
return Object.keys(this.registerlist).length;
},
},
};
</script>
This is because when you return a property in asyncData, you should not have it in data property of the component instance, instead the later will override the returned with asyncData.
<script>
import axios from "axios";
export default {
async asyncData({ $axios }) {
let { data } = await $axios.$get("/Businessregisterlist");
// console.log(response)
return {
registerlist: data,
};
},
computed: {
resultCount() {
return Object.keys(this.registerlist).length;
},
},
};
</script>
<template>
<div>
<p>{{ resultCount }}</p>
</div>
</template>
I have 2 of the same components in my laravel blade view, but they are conflicting.
What i'm trying to accomplish:
I've made a vue component that uploads a file to firebase and stores it in my database. In my blade view i have 2 places where i want to use this component. I configure the component with props so the component knows where to store the file.
What going wrong:
Every time i try to upload a file with the second component, i fire the function in the first component. How do i fix that the components can't conflict?
My laravel balde view:
component 1
<uploadfile
:key="comp100"
:user_data="{{ Auth::user()->toJson() }}"
store_path="/users/{{ Auth::user()->username }}/settings/email_backgrounds"
:store_route="'settings.project_email'"
:size="1000"
fillmode="cover"
></uploadfile>
component 2
<uploadfile
:key="comp200"
:user_data="{{ Auth::user()->toJson() }}"
store_path="/users/{{ Auth::user()->username }}/settings/email_backgrounds"
:store_route="'settings.project_email'"
:size="1000"
fillmode="cover"
></uploadfile>
The Vue component:
<template>
<div class="vue-wrapper">
<FlashMessage position="right top"></FlashMessage>
<div v-if="loading" class="lds-dual-ring"></div>
<div class="field">
<div class="control">
<label class="button main-button action-button m-t-20" for="uploadFiles"><span style="background-image: url('/images/icons/upload.svg')"></span>Kies bestand</label>
<input type="file" name="uploadFiles" id="uploadFiles" class="dropinput" #change="selectFile">
</div>
</div>
</div>
</template>
<script>
import { fb } from '../../firebase.js';
export default {
data() {
return {
fileObject: {
filePath: null,
url: null,
file: null,
resizedPath: null
},
loading: false
};
},
mounted() {
console.log(this.size)
console.log(this.fillmode)
},
props: [
'user_data',
'store_path',
'store_route',
'size',
'fillmode'
],
methods: {
selectFile(event)
{
var file = event.target.files[0];
this.fileObject.file = file
this.fileObject.filePath = this.store_path + '/' + file.name
this.fileObject.resizedPath = this.store_path + '/resized-' + file.name
if(file.type == 'image/png' || file.type == 'image/jpeg')
{
this.uploadFile(this.fileObject)
} else {
this.flashMessage.success({
title: 'Oeps!',
message: 'De afbeelding moet een png of een jpeg zijn!',
blockClass: 'success-message'
});
}
},
uploadFile(fileObject)
{
var vm = this
console.log(fileObject)
var storageRef = fb.storage().ref(fileObject.filePath)
var uploadTask = storageRef.put(fileObject.file)
this.loading = true
uploadTask.on('state_changed', function(snapshot){
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
},function(error) {
}, function() {
var resizeImage = fb.functions().httpsCallable('resizeImage')
resizeImage({filePath: fileObject.filePath, contentType: fileObject.file.type, watermark: false, size: vm.size, fit: vm.fillmode}).then(function(result){
var downloadRef = fb.storage().ref(fileObject.resizedPath);
downloadRef.getDownloadURL().then(function(url){
fileObject.url = url
vm.loading = false
vm.storeImage(fileObject)
}).catch(function(error){
console.log(error)
})
}).catch(function(error){
});
});
},
storeImage(file)
{
axios.post('/api/app/store_file', {
api_token: this.user_data.api_token,
user: this.user_data,
file: file,
storeRoute: this.store_route
}).then((res) => {
location.reload()
}).catch((e) => {
});
}
}
}
</script>
Does someone know how to fix this?
So I have this code:
<template>
<div id="search-wrapper">
<div>
<input
id="search_input"
ref="autocomplete"
placeholder="Search"
class="search-location"
onfocus="value = ''"
#keyup.enter.native="displayPic"
>
</div>
</div>
</template>
<script>
import VueGoogleAutocomplete from "vue-google-autocomplete";
export default {
data: function() {
return {
search_input: {},
pic: {}
};
},
mounted() {
this.autocomplete = new google.maps.places.Autocomplete(
this.$refs.autocomplete
);
this.autocomplete.addListener("place_changed", () => {
let place = this.autocomplete.getPlace();
if (place.photos) {
place.photos.forEach(photo => {
let pic=place.photos[0].getUrl()
console.log(pic);
});
}
});
},
methods: {
displayPic(ref){
this.autocomplete = new google.maps.places.Autocomplete(
this.$refs.autocomplete);
this.autocomplete.addListener("place_changed", () => {
let place = this.autocomplete.getPlace();
if (place.photos) {
place.photos.forEach(photo => {
let pic=place.photos[0].getUrl()
console.log(pic);
});
}
})
},
}
}
I want to pass the "pic" parameter, resulted in displayPic, which is a function, into my template, after one of the locations is being selected.
I've tried several approaches, but I'm very new to Vue so it's a little bit tricky, at least until I'll understand how the components go.
Right now, the event is on enter, but I would like it to be triggered when a place is selected.
Any ideas how can I do that?
Right now, the most important thing is getting the pic value into my template.
<template>
<div id="search-wrapper">
<div>
<input style="width:500px;"
id="search_input"
ref="autocomplete"
placeholder="Search"
class="search-location"
onfocus="value = ''"
v-on:keyup.enter="displayPic"
#onclick="displayPic"
>
<img style="width:500px;;margin:5%;" :src="pic" >
</div>
</div>
</template>
<script>
import VueGoogleAutocomplete from "vue-google-autocomplete";
export default {
data: function() {
return {
search_input: {},
pic:""
};
},
mounted() {
this.autocomplete = new google.maps.places.Autocomplete(
this.$refs.autocomplete,
{componentRestrictions: {country: "us"}}
);
},
methods: {
displayPic: function(){
this.autocomplete.addListener("place_changed", () => {
let place = this.autocomplete.getPlace();
if (place.photos) {
place.photos.forEach(photo => {
this.pic=place.photos[0].getUrl()
});
}
})
},
}
}
</script>
I'm using vue-multiselect and I would like the user to be able to search tags in the database using async and if they don't find what they want, enter their own tag. This means I'm using tagging and async. It works as expected until I add a tag not found in the , then the aysnc no longer searches. If I remove the added tag, then it does the async search again..
<template>
<div>
<label class="typo__label" for="ajax">Async multiselect</label>
<multiselect v-model="selectedTags" id="tags" label="name" track-by="code" placeholder="Type to search" open-direction="bottom" :options="tags" :taggable="true" #tag="addTag" :multiple="true" :searchable="true" :loading="isLoading" :internal-search="false" :clear-on-select="true" :close-on-select="false" :options-limit="300" :limit="3" :limit-text="limitText" :max-height="600" :show-no-results="false" :hide-selected="true" #search-change="asyncFind">
<template slot="clear" slot-scope="props">
<div class="multiselect__clear" v-if="selectedTags.length" #mousedown.prevent.stop="clearAll(props.search)"></div>
</template><span slot="noResult">Oops! No elements found. Consider changing the search query.</span>
</multiselect>
<pre class="language-json"><code>{{ selectedTags }}</code></pre>
</div>
</template>
<script>
import axios from 'axios';
import Multiselect from 'vue-multiselect'
export default {
components: {
Multiselect
},
props: {
userId: {
type: Number,
required: true
},
tagGroup: {
type: String,
required: true
}
},
data () {
return {
selectedTags: [],
tags: [],
isLoading: false
}
},
methods: {
addTag (newTag) {
const tag = {
name: newTag
}
this.tags.push(tag)
this.selectedTags.push(tag)
},
limitText (count) {
return `and ${count} other tags`
},
asyncFind (query) {
if( query.length > 3 ) {
this.isLoading = true
axios.get('/api/tags/'+this.tagGroup+'/'+query).then(response => {
this.tags = response.data.results.map(a => {
return { name: a.name.en };
});
})
}
},
clearAll () {
this.selectedTags = []
}
}
}
</script>
I'm using the component twice within another component:
<user-tags v-bind:tagGroup="'industry'" :typeahead-activation-threshold="2" :userId="user.id" :isSearchable="true"></user-tags>
<user-tags v-bind:tagGroup="'expertise'" :typeahead-activation-threshold="2" :userId="user.id" :isSearchable="true"></user-tags>