How do I programmatically bind in video player URLs in Nuxt/Vue? - vue.js

I was looking for an idea of how to programmatically bind in video player urls. I understand the idea of using img and doing v-for and a :src, but the url for my videos get put in the data of the script. Is it possible to bind and make these programmatic as well? Here is an example of a working script now, but I just have to replace this as a component for every single video manually.
<template>
<div class="player">
<client-only>
<video-player
ref="videoPlayer"
:options="playerOptions"
/>
</client-only>
</div>
</template>
<script>
export default {
name: "index",
data() {
return {
playerOptions: {
sources: [{
type: 'application/x-mpegurl',
src: 'myvideo.m3u8'
}],
The above code is working, but I need to have a component for every single video. Then in each component put the same code, but change the name of the src for the m3u8 video. Ideally, I would want to just pass something from an api into the src of the m3u8 and create one dynamic component. The question is, how would I make this dynamic component?
I tried something like this, but couldnt do a :src in the script.
<template>
<div class="player">
<client-only>
<video-player
ref="videoPlayer"
:options="playerOptions"
/>
</client-only>
</div>
</template>
<script>
export default {
name: "index",
data() {
return {
playerOptions: {
sources: [{
type: 'application/x-mpegurl',
:src: video.url
}],

#tomdale I'm not sure if i'm understanding your question correctly, but if you want something dynamic you're probably best to remove playerOptions from your data() property and turn it into a computed property.
It could then look something like this,
computed: {
playerOptions() {
return {
sources: [{
type: 'application/x-mpegurl',
src: this.video.url
}]
}
},
}
Your question doesn't really show where you're getting the video and video.url data from, but if the component is working with a collection of video data, you could do something like,
playerOptions() {
let sources = []
let i = 0
while (i < this.videos.length) {
sources.push({
type: 'application/x-mpegurl',
src: this.videos[i].url
})
i++
}
return sources
},
You'll be be able to reference playerOptions the same way that you were in when it was in data(), ie this.playerOptions, however now it will be dynamic.

Related

How can I can show a div if an object doesn't have a value outside of the object scope

I have a small Nuxt issue that I can't work out how to get around.
Essentially, I have an object (used for a carousel slider).
<template>
<div
:class="[$style.swiperSlide, 'swiper-slide']"
v-for="slide in slides"
:key="slide.id">
<nuxt-img
:class="[$style.img]"
:alt="slide.alt"
:src="imgSources(slide)"
sizes="sm:100vw"
/>
<div :class="[$style.info, 'info-b']" v-if="slide.info">
{{ slide.info }}
</div>
</div>
<button :class="[$style.infoOpen]"
#click="showTab"
v-if="slideInfoAvailable"
>
Close
</button>
</template>
<script>
export default {
props: {
slides: {
type: Array,
required: true,
default: () => []
}
},
computed: {
slideInfoAvailable() {
return this.slide?.info
}
},
mounted() {
const swiper = new Swiper(".swiper-container", {
. . .
});
},
methods: {
imgSources(slide) {
return `/img${slide.imgPath}.jpg`;
},
};
</script>
All works o.k, the problem is that I have a button outside of this v-for that I need to only be visible if there's slide.info but because this div is outside of the v-for it can't tell if it's available.
Cannot read property 'info' of undefined
The easiest way out of this is to add the button inside of the slider - but I can't for Z-index CSS issues. It has to be outside of the 'slider' div.
Any ideas how I can only show the button if there's slide.info? For some of my slides, there won't be.
<slider
:slides="[
{
imgPath: '/demo',
info: 'Demo info for this slide',
alt: 'Homepage'
},
{
imgPath: '/demo2',
alt: 'Homepage'
},
]"
/>
One way I could do it would be to see if .slide-active .style.info exists. If it doesn't exist then I can hide the button as slide-active is added to the active div by the slider API.
The issue is coming from the fact that you probably have some async fetching and that slides are not available upon initial render. To prevent this, you can use a computed with some optional chaining like this
export default {
computed: {
slideInfoAvailable() {
return this.slide?.info
}
}
}
Then, call it like this
<button :class="[$style.infoOpen]" #click="showTab" v-if="slideInfoAvailable">
You cannot use ?. directly in the template.
You could also do the classic way of
<button :class="[$style.infoOpen]" #click="showTab" v-if="slide && slide.info">
but it does not look as sexy IMO (but you do not need any computed).
And yeah, for this kind of thing, better to handle it with Vue than relying on some hacky dirty CSS tricks!

node webkit: open thousands of urls in browser

I am using following snippet to open a link in default browser.
<template>
<div>
<a #click.prevent="fireUpLink">External Link</a>
</div>
</template>
.
<script>
/* global nw */
export default {
methods: {
fireUpLink: function() {
nw.Shell.openExternal("http://example.com/");
}
}
};
</script>
But lets say if I have thousands of links, this solution is not scalable. Is there any better way?
In a Vue SFC, it expects a referenced variable to be defined or imported in the component, or be global. If you reference it from the global window object, it should work.
window.nw.Shell.openExternal('http://example.com');
For Vue, as shown by Max, <a #click.prevent="window.nw.Shell.openExternal('http://example.com')">Link</a> works.
You could also just create a component:
<template>
<a
:href="url"
class="link"
#click.prevent="openExternal"
><slot></slot></a>
</template>
<script>
export default {
name: 'ExternalLink',
props: {
url: {
type: String,
required: true
}
},
methods: {
openExternal: function () {
window.nw.Shell.openExternal(this.url);
}
}
};
</script>
Then just reference it like this:
<external-link url="http://example.com">Link</external-link>
Alternatively you could create a mixin that has the openExternal method in it, and globally install it across all components, so you can just do <a #click.prevent="openExternal('http://example.com')>
If you are using something other than Vue, which does not use a Virtual DOM, then you could just add a class="external-link" then target all elements on the page with that class and handle them.
$('.external-link').click(function (evt) {
// Prevent the link from loading in NW.js
evt.preventDefault();
// Get the `href` URL for the current link
let url = $(this).attr('href');
// Launch the user's default browser and load the URL for the link they clicked
window.nw.Shell.openExternal(url);
});

How to get more info knowing only ID

I'm creating very simple app and I have a problem with getting info from furnitures.js:
export default [
{ id: 1, name: 'Kanapa Sydney', dim1: '2,25m', dim2: '1,45m x 1,95m'},
{ id: 2, name: 'Kanapa Alex', dim1: '1,95m', dim2: '1,45m x 1,95m'}
]
File ProductDetail contain app-prodrend component. The only thing I know is Id (from route params) and I want to display (id, name, dim1 and dim2) in this component (app-prodend).
ProductDetail.vue
<template>
<div class="prod-det">
<app-header style="background-color: black"></app-header>
<app-prodrend style="position: absolute; margin-top: 50vh" :prod="prods"></app-prodrend>
</div>
</template>
<script>
import header from '../Header';
import prodrend from './ProdDetRen';
export default {
data() {
return {
id: this.$route.params.id
}
},
components: {
appHeader: header,
appProdrend: prodrend
},
computed: {
prods(id) {
return 'kook'
}
}
}
</script>
ProdDetRen.vue
<template>
<h1>dawdwa {{ prod.id }}</h1>
</template>
<script>
export default {
props: ['prod']
}
</script>
I tried to make a getter in furn.js file:
furnDetail(state, index) {
const record = state.products.find(element => element.id == index);
return {
id: index,
name: record.name,
dim1: record.dim1,
dim2: record.dim2
}
}
I have no idea what to do. Thanks in advance
The solution i would recommend is using Vuex to manage your data. Vuex will give you the ability to create getters that you can import into the components that require data. With that data you can filter the data down to only the item you are looking for.
Ive created a repo on my Git that you can have a look at to get a better idea of what i mean.
Visit https://github.com/FloydWatson/furnitureapp
Ive utilized Vuex for state management and vue-router to create the routing paths that have an id in them.
Within the page furniture.vue I get the list of furniture and find the item im looking for using route parameters
computed: {
...mapGetters(["allFurniture"]),
// get the details here
loadedItem() {
return this.allFurniture.find((item) => item.id == this.$route.params.id);
},
},
This is done in a computed field so that if the data was updated our Vuex would let the page know and our data would dynamically update.
Ive tried to leave some comments in there so you can see whats going on easier. Feel free to ask me if theres any other clarification you need.
Happy coding

Vue: render <script> tag inside a variable (data string)

I'm new to Vue.js
I want to render a script tag inside a variable (data string).
I tried to us a v-html directive to do so, but it doesn't work Nothing is rendered
Any way I can achieve this?
I'd place a v-if directive on the script tag and put the content of it in a variable.
<script v-if="script">
{{script}}
</scrip>
If I understand you correctly, my answer is:
<template>
<div>
{{ strWithScriptTag }}
</div>
</template>
<script>
export default {
name: 'Example',
methods: {
htmlDecode(input) {
const e = document.createElement('div')
e.innerHTML = input
return e.childNodes[0].nodeValue
},
},
computed: {
strWithScriptTag() {
const scriptStr = '<script>https://some.domain.namet</script>'
return this.htmlDecode(scriptStr)
}
},
}
</script>
I think that by safety vue is escaping your <script> automatically and there is no way to avoid this.
Anyway, one thing you can do is eval(this.property) on created() lifecycle hook.
data: {
script: 'alert("this alert will be shown when the component is created")'
},
created() {
eval(this.script)
}
Use it with caution, as stated in vue js docs, this may open XSS attacks in your app

vuejs set img src by using current route name

There is a file contains images.Every pictures'name is a route name. I want to change the img src attribute by current route name.But I can not get the full path,only can get the picture name.
<template>
<!-- footer -->
<div class="index-footer">
<img v-bind:src = "$route.name" />
</div>
</template>
<script>
import { Carousel } from 'iview'
// export default {
// components: { Carousel }
// }
export default {
name: 'index',
data () {
return {
index: '/static/img/footer/index.png',
more: '/static/img/footer/index.png',
product: '/static/img/footer/index.png',
information: '/static/img/footer/index.png',
news: '/static/img/footer/index.png',
down: '/static/img/footer/index.png',
enterprise: '/static/img/footer/enterprise.png',
value3: 0,
setting: {
autoplay: true,
autoplaySpeed: 4000,
dots: 'inside',
trigger: 'hover',
arrow: 'hover'
},
scrolled: false
}
},
components: {
Carousel
}
}
</script>
You're not binding the src at all. You need to use the binding directive to bind the src.
Like this
<img :src="index">
or this
<img v-bind:src="index">
Use this[this.$route.name] or this[$route.name] as the binding text for v-bind.
v-bind evals the text you pass in as javascript code (expression, to be more exact), with a bit extra trick of considering the variables in the expression to be members of the view-model (aka this).
The tricky part here is that we want this[this.$route.name], which is confusing to translate to the v-bind text with the "I'll fill in the this for you" rule Vue provides. I tested a bit and found both this[this.$route.name] and this[$route.name] works. Not sure why they work, however. :/