Howler.js: sound doesn't load - vue.js

Following basic example in the docs, yet sound doesn't play. I see the mp3 file in Network tab but it's 90KB instead of 5MB so I suppose it doesn't load properly.
I tried different paths: src: ['#/assets/audios/test.mp3'], `src: ['../assets/audios/test.mp3']. Nothing works. No console error. Why is it not working?
<template>
<div class="container">
<button #click="play">
PLAY
</button>
</div>
</template>
<script>
import { Howl, Howler } from 'howler'
export default {
data () {
return {
sound: ''
}
},
mounted () {
this.sound = new Howl({
src: ['test.mp3']
})
},
methods: {
play () {
this.sound.play()
}
}
}
</script>

It sounds like you're trying to load an asset URL for src.
The asset URL needs to be required so that Webpack resolves the actual URL to the file.
Errors are silently ignored, but you can set onloaderror to handle them.
export default {
mounted () {
this.sound = new Howl({
// 1
src: [
require('#/assets/audios/test.mp3')
],
// 2
onloaderror(id, err) {
console.warn('failed to load sound file:', { id, err })
}
})
}
}

Related

Getting "Cannot read properties of undefined (reading 'commit')"NUXT

I am new to Vue and stuck. I am trying to send user input data from a form into a vuex store. From that vuex store, an action will be called (fetching from API) and I would like that data back into my app and components.
<template>
<div>
<h1>APP NAME</h1>
<form action="submit" #submit.prevent="sendCityName()">
<label for="query"></label>
<input
type="text"
id="query"
v-model="cityName"
>
<button type="submit">Submit</button>
</form>
<h3>{{ lat }}</h3>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
data() {
return {
cityName: ''
}
},
computed: {
coordinates () {
return this.$store.state.lat
}
},
methods: {
sendCityName() {
this.$store.commit('fetchCity', this.cityName)
}
},
}
</script>
Here is my index.vue and getting the error "Cannot read properties of undefined (reading 'commit')"
here is my store.js. I want to use the lat and lon across my app.
export const state = () => ({
lat: '',
lon: ''
})
export const mutations = {
SET_LAT(state, payload){
state.lat = payload
},
SET_LON(state, payload){
state.lon = payload
}
}
export const actions = {
async fetchCity({ commit }, cityName) {
// make request
axios.get(
`https://api.openweathermap.org/geo/1.0/direct`, {
params: {
appid: "xxxxxxx",
q: cityName,
}
}).then((response) => {
commit('SET_LAT', response.data[0].lat);
commit('SET_LON', response.data[0].lng);
});
},
};
When I button submit I get the error "Cannot read properties of undefined (reading 'commit')"
Here is my working repo with the fixes mentioned below.
There are 3 things in your code:
remove vuex from package.json and run yarn again, that one is already baked into Nuxt as stated in the official documentation, those are the only steps needed
all the files inside of store will be namespaced by default for you, since you do have store/store.js, the proper syntax will be
async sendCityName() {
await this.$store.dispatch('store/fetchCity', this.cityName) // 👈🏻 store prefix
}
since you do use the axios module, you should have the following in your action (using the async/await syntax since it's more modern and preferable)
async fetchCity({ commit }, cityName) {
const response = await this.$axios.get(
`https://api.openweathermap.org/geo/1.0/direct`, {
params: {
appid: "3d91ba5b3c11d13158a2726aab902a0b",
q: cityName,
}
})
commit('SET_LAT', response.data[0].lat)
commit('SET_LON', response.data[0].lng)
}
Looking at the browser's console, you also have some errors to fix.
I can also recommend an ESlint + Prettier configuration so that you keep your code error-proof + properly formatted at all times.

How to dynamically switch a component based on the existence of window in Nuxt.js?

I have a dynamic component that looks different at different screen resolutions.
<template>
<div>
<headerComponent></headerComponent>
<div v-if="!large" class="placeholder"></div>
<component
v-else
:is="tariffBlock"
>
</component>
</div>
</template>
<script>
import smallComponent from '#/components/small-component'
import largeComponent from '#/components/large-component'
import headerComponent from '#/components/header-component'
const components = {
smallComponent,
largeComponent
}
export default {
components: {
headerComponent
},
data () {
return {
large: false
}
},
computed: {
getComponent () {
if (!this.large) return components.smallComponent
return components.largeComponent
}
},
created () {
if (process.browser) {
this.large = window.matchMedia('(min-width: 1200px)').matches
}
}
}
</script>
By default, a smallComponent is shown, and then a largeComponent. To avoid "jumping" I decided to show the placeholder while large === false.
To avoid the error window in not defined I use the check for process.browser.
PROBLEM: placeholder is only shown in dev mode, but when I start generate the placeholder is not displayed.
The following solutions DIDN'T help:
1.
created () {
this.$nextTick(() => {
if (process.browser) {
this.large = window.matchMedia('(min-width: 1200px)').matches
}
})
}
created () {
this.$nextTick(() => {
this.large = window.matchMedia('(min-width: 1200px)').matches
})
}
mounted () {
this.large = window.matchMedia('(min-width: 1200px)').matches
}
and with the addition process.browser and nextTick()
Creating a mixin with ssr: false, mode: client
Thanks in advance!
This is how you toggle between components in Nuxt.js
<template>
<div>
<div #click="toggleComponents">toggle components</div>
<hr />
<first-component></first-component>
<second-component></second-component>
<hr />
<component :is="firstOrSecond"></component>
</div>
</template>
<script>
export default {
data() {
return {
firstOrSecond: 'first-component',
}
},
methods: {
toggleComponents() {
if (this.firstOrSecond === 'first-component') {
this.firstOrSecond = 'second-component'
} else {
this.firstOrSecond = 'first-component'
}
},
},
}
</script>
You don't need to import them, it's done automatically if you have the right configuration, as explained here: https://nuxtjs.org/blog/improve-your-developer-experience-with-nuxt-components
In this snippet of code, first-component and second-component are shown initially (between the two hr) just to be sure that you have them properly loaded already. You can of course remove them afterwards.
Not recommended
This is what you're looking for. Again, this is probably not how you should handle some visual changes. Prefer CSS for this use-case.
<template>
<div>
<component :is="firstOrSecond"></component>
</div>
</template>
<script>
export default {
data() {
return {
firstOrSecond: 'first-component',
}
},
mounted() {
window.addEventListener('resize', this.toggleComponentDependingOfWindowWidth)
},
beforeDestroy() {
// important, otherwise you'll have the eventListener all over your SPA
window.removeEventListener('resize', this.toggleComponentDependingOfWindowWidth)
},
methods: {
toggleComponentDependingOfWindowWidth() {
console.log('current size of the window', window.innerWidth)
if (window.innerWidth > 1200) {
this.firstOrSecond = 'second-component'
} else {
this.firstOrSecond = 'first-component'
}
},
},
}
</script>
PS: if you really wish to use this solution, at least use a throttle because the window event will trigger a lot and it can cause your UI to be super sluggish pretty quickly.

How to get the progress on file upload using filepond?

I have an API endpoint which works on PUT Request to update User info such as user avatar. This API is built on Django. In my Frontend, I'm using NUXT to upload the file using FilePond, I did the following:
<template>
<section class="section">
<div class="container">
<file-pond
name="test"
ref="pond"
label-idle="Drop files here..."
v-bind:allow-multiple="true"
accepted-file-types="image/jpeg, image/png"
/>
<vs-button success #click='userinfo_put_avatar'>File upload data</vs-button>
</div>
</section>
</template>
<script>
import vueFilePond from 'vue-filepond';
import 'filepond/dist/filepond.min.css';
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.min.css';
import FilePondPluginFileValidateType from 'filepond-plugin-file-validate-type';
import FilePondPluginImagePreview from 'filepond-plugin-image-preview';
let FilePond = vueFilePond(FilePondPluginFileValidateType, FilePondPluginImagePreview);
export default {
components: {
FilePond,
},
methods: {
async userinfo_put_avatar() {
let file = this.$refs.pond.getFiles(0)
let fileupload = new FormData();
fileupload.append('avatar', file)
let config = {
headers: {
'Content-Type': 'multipart/form-data'
}
}
let data = await this.$axios.put('user-info/', fileupload, config);
},
}
};
</script>
This works for me very well. But I want the feature of Filepond to show the upload status with the spinning svg, when in process of uploading and when completed show the green status.
I tried using the pond.processFile(0) but it doesnot upload the file.
I tried using the FilePond.setOptions() but it gives me an error setOptions is not a function. If this could work somehow.
I would be able to overwrite onaddfileprogress event using the following code from GITHUB ISSUE LINK
FilePond.setOptions({
instantUpload: true,
allowImagePreview: false,
server: {
url: '/images',
process: {
url: '/upload',
},
revert: '/revert',
restore: '/restore/',
load: '/load/',
},
onremovefile: function(error, file) {
if (file.serverId) {
let input = document.createElement('input');
input.type = 'hidden';
input.name = 'DeletedFilepondImages';
input.value = file.serverId;
uploadForm.appendChild(input);
}
},
onaddfilestart: function(file) {
console.log(`onaddfilestart`);
buttonForm.classList.add('filepondUpload');
buttonForm.setAttribute('disabled', 'true');
},
onaddfileprogress(file, progress) {
console.log(`onaddfileprogress`);
buttonForm.classList.remove('filepondUpload');
buttonForm.removeAttribute('disabled');
},
});
// get a reference to the input element
const filepondInput = document.querySelector(
'#filepondFileUploader input[type="file"]'
);
// create a FilePond instance at the input element location
const filepondObject = FilePond.create(filepondInput, {
maxFiles: 5,
acceptedFileTypes: ['image/*'],
labelIdle:
'<div class="image-upload__file-upload-content">Add images</div>',
files: filepondInitialFiles,
onprocessfiles() {
console.log('onprocessfiles');
buttonForm.classList.remove('filepondUpload');
buttonForm.removeAttribute('disabled');
},
});
You need to define the server prop on the component. You can use v-bind:server="myServer" and then add it to your component data.
<file-pond
name="test"
ref="pond"
v-bind:server="myServer"/>
export default {
name: 'app',
data: function() {
return {
myServer: {
// server config here
}
};
},
components: {
FilePond
}
};
If you need setOptions, you can import it from vueFilePond
import vueFilePond, { setOptions } from 'vueFilePond'

Nuxt: Page crashing on page reload

Anyone know why a sub page crashes when user reloads the page? It is fine when you navigate to the page using nuxt-link from another page (using route params), but when the user reloads/refreshes the page, it will crash.
Here is my sandbox where you can test it out: Codesandbox
Code from nuxt link:
<nuxt-link :to="{name: 'photos-id-title', params: { id: photo.id, title: photo.title }}">
Code from photo details page:
<template>
<section>
<!-- <template v-if="photo"> -->
<img
:id="photo.filename"
:src="photo.url"
class="img-fluid thumbnail rounded"
:alt="photo.title"
/>
<h1 class="h3">{{ photo.title }}</h1>
</section>
</template>
<script>
import { Annotorious } from '#recogito/annotorious'
export default {
data() {
return {
photo: {},
anno: {},
title: this.$route.params.title
}
},
async mounted() {
await this.getPhotoDoc()
this.anno = await new Annotorious({ image: this.photo.filename })
},
methods: {
async getPhotoDoc() {
const docRef = await this.$fireStore
.collection('photos')
.doc(this.$route.params.id)
.get()
try {
if (docRef.exists) {
// data() returns all data about the doc
console.log('got the doc: ', docRef.data())
this.photo = docRef.data()
} else {
console.log('no docs exist')
}
} catch (error) {
console.log('Error getting document:', error)
}
}
},
head() {
return {
title: this.photo.title,
meta: [
{
hid: 'description',
name: 'description',
content: this.photo.description
}
]
}
}
}
</script>
User journey: Click PHOTOS from navbar, select any photo on the page. You shall see a "photo detail" page. Loads fine. Try to refresh the page -- it will crash.
Note: I also have this scaffolded in a regular/plain vue app using Vue-cli and have NO issues. Only seems to be a problem with Nuxt. Must be SSR related?
Thanks for any help...
If you think this is SSR related and the Annotorious plugin might cause the problem try this:
nuxt.config.js add the plugin with mode client
plugins: [
{ src: '~/plugins/client-only.js', mode: 'client' }, // only on client side
]
You can find more information in the nuxtjs docs here

Get blank while using vue-pdf

I want to use vue-pdf to preview online pdf file. But I always got blank page and there is no error message on console. My code is
<template>
<div class="pdf">
<pdf
:src="src">
</pdf>
</div>
</template>
<script>
import pdf from 'vue-pdf'
export default {
name: 'Pdf',
components:{
pdf
},
data(){
return {
src:"http://file.dakawengu.com/file/2018-05-29/20180527-tianfeng.pdf",
}
},
mounted() {
this.src = pdf.createLoadingTask(this.src)
this.src.then(response => {
this.numPages = response.numPages
})
}
}
</script>
vue version: 2.9.6
vue-pdf version: 4.0.6
Do not re-assign variable src. Your onmounted function is re-assigning src to something else just change it to:-
.....
data(){
return {
src:"http://file.dakawengu.com/file/2018-05-29/20180527-tianfeng.pdf",
newsrc: null,
}
},
.................
........your code..............
........................
mounted() {
this.newsrc = pdf.createLoadingTask(this.src)
this.newsrc.then(response => {
this.numPages = response.numPages
})
}