I am trying to add custom button using components.
Try to displaying company logo on player. Defining option objects and calling into component but not getting value in component function.
(function(window, videojs) {
var options = {"logo": "<https://brightcovelogo.png>"};
// inti player
var player = videojs.getPlayer('brightcoveplayer');
var ContentLogo= videojs.extend(Component, {
constructor: function ContentLogo(player, options) {
Component.apply(this, arguments);
console.log(options);
if (options.logo) {
this.updateLogo(options.logo);
}
},
createEl: function () {
return videojs.dom.createEl('div', {
className: 'vjs-video-logo'
});
},
// Pass logo url function
updateLogo:function (url) {
if (typeof url!== 'string') {
url = '';
}
videojs.dom.emptyEl(this.el());
videojs.dom.appendContent(this.el(),
videojs.dom.createEl('img'{
src: url
})
}
})
videojs.registerComponent('ContentLogo', ContentLogo);
})(window, window.videojs);
options inside the constructer is the options object passed to the constructor when creating a new instance of your component. After registering the component, create it with
player.addChild('ContentLogo', options);
Related
How Can Show Variable in Page if its on onchange Method. for Example this Code:
methods: {
onChange(image) {
if (image) {
EXIF.getData(this.$refs.pictureInput.file, function () {
var make = EXIF.getTag(this, "Make"),
model = EXIF.getTag(this, "Model");
})
} else {
console.log(`it's not image`)
}
},
}
I want show make and model variable to User.
To access the this of a component inside another scope, (in your case your EXIF callback) just create a new reference to the component's this in the higher scope and access it inside the callback function.
export default {
data () {
return {
name: '',
model: ''
}
},
methods: {
onChange(image) {
const component = this;
if (image) {
EXIF.getData(this.$refs.pictureInput.file, function () {
var make = EXIF.getTag(this, "Make"),
model = EXIF.getTag(this, "Model");
component.make = make;
component.model = model;
})
} else {
console.log(`it's not image`)
}
}
}
}
Now inside your template:
<template>
<div>
<span>Name: {{name}}</span>
<span>Model: {{model}}</span>
</div>
</template>
i am appending a child component in Vue programmatically as seen below:
var ComponentClass = Vue.extend(FormulaGeneratorConstant) //create instance from FormulaGeneratorConstant component
this.constants.push('variable1');
var constant = new ComponentClass({
propsData: {
value: this.constants[this.constants.length - 1]
}
});
constant.$mount();
this.$refs.droppableContainer.$el.appendChild(constant.$el)
but right now i can only pass props in this code.
i would like to know how to implement v-model and handle custom events as well if that is possible.
Found the solution here.
i just passed a created function inside the new Component constructor:
var constant = new ComponentClass({
propsData: {
value: this.constants[this.constants.length - 1]
},
created(){
this.$on(['change'], e => { console.log(e); })
}
});
I want a global dialog component which is called only by JavaScript. And never had custom content within it. So I don't want to put any HTML tag like <my-dialog ref="myDialog"></my-dialog> in my code. Just call this.$ref.myDialog.show().
I have a HTML tag version. How to instance the component only in JavaScript?
I think you neeed to create a JS window with a component inside
here is an example:
var componentName = "my-dialog";
var model = {d:1};
var d = document.createElement("div"); // JavaScript Window
document.body.appendChild(d);
d.id = 'win' + componentName;
var app = new Vue({
render(h, data) {
return h(componentName, { on: { 'close': this.close }, props: { model: this.model } });
},
el: d, data: { wait: false, error: "", after: 0, model },
mounted() {
},
methods: {
close() {
this.$destroy();
$(d).remove(); // remove the window by jQuery
}
}
})
First you need to assign Vue to window.vue.
window.vue = new Vue({ // options })
then call it using js. vue.$ref.myDialog.show()
When I get data from the server, like
[{methodName:mothodValue},{methodName:mothodValue}]
then I want dynamic generation method, like
methods: {
functionArray.forEach(function (item) {
item.functionName:function () {
item.functionValue;
}
})
}
so this is my code
var componentName = Vue.component(componentName, {
data: function () {
return {
value: value
}
},
template: componentTemplate,
methods:{
functionArray.forEach(function (item) {
item.functionName:function () {
item.functionValue;
}
})
}
})
the old code was
methods:{
getValue : function(){
getValue(this.value);
}
}
Is that possible?
If the data from the server is returned before the creation of the Vue component (I'm not sure if you can add methods after the creation of a Vue component), then you can create a methods object like so:
var methods = {};
functionArray.forEach(function (item) {
methods[item.functionName] = item.functionValue;
});
You can't populate an object literal with code, but you can populate an empty object literal afterwards with code like so.
Then you can put it into your component like so:
var componentName = Vue.component(componentName, {
// ..
methods: methods
});
I have a basic VueJS application with only one page.
It's not a SPA, and I do not use vue-router.
I would like to implement a button that when clicked executes the window.open() function with content from one of my Vue Components.
Looking at the documentation from window.open() I saw the following statement for URL:
URL accepts a path or URL to an HTML page, image file, or any other resource which is supported by the browser.
Is it possible to pass a component as an argument for window.open()?
I was able to use some insights from an article about Portals in React to create a Vue component which is able to mount its children in a new window, while preserving reactivity! It's as simple as:
<window-portal>
I appear in a new window!
</window-portal>
Try it in this codesandbox!
The code for this component is as follows:
<template>
<div v-if="open">
<slot />
</div>
</template>
<script>
export default {
name: 'window-portal',
props: {
open: {
type: Boolean,
default: false,
}
},
data() {
return {
windowRef: null,
}
},
watch: {
open(newOpen) {
if(newOpen) {
this.openPortal();
} else {
this.closePortal();
}
}
},
methods: {
openPortal() {
this.windowRef = window.open("", "", "width=600,height=400,left=200,top=200");
this.windowRef.addEventListener('beforeunload', this.closePortal);
// magic!
this.windowRef.document.body.appendChild(this.$el);
},
closePortal() {
if(this.windowRef) {
this.windowRef.close();
this.windowRef = null;
this.$emit('close');
}
}
},
mounted() {
if(this.open) {
this.openPortal();
}
},
beforeDestroy() {
if (this.windowRef) {
this.closePortal();
}
}
}
</script>
The key is the line this.windowRef.document.body.appendChild(this.$el); this line effectively removes the DOM element associated with the Vue component (the top-level <div>) from the parent window and inserts it into the body of the child window. Since this element is the same reference as the one Vue would normally update, just in a different place, everything Just Works - Vue continues to update the element in response to databinding changes, despite it being mounted in a new window. I was actually quite surprised at how simple this was!
You cannot pass a Vue component, because window.open doesn't know about Vue. What you can do, however, is to create a route which displays your component and pass this route's URL to window.open, giving you a new window with your component. Communication between the components in different windows might get tricky though.
For example, if your main vue is declared like so
var app = new Vue({...});
If you only need to render a few pieces of data in the new window, you could just reference the data model from the parent window.
var app1 = window.opener.app;
var title = app.title;
var h1 = document.createElement("H1");
h1.innerHTML = title;
document.body.appendChild(h1);
I ported the Alex contribution to Composition API and works pretty well.
The only annoyance is that the created window ignores size and position, maybe because it is launched from a Chrome application that is fullscreen. Any idea?
<script setup lang="ts">
import {ref, onMounted, onBeforeUnmount, watch, nextTick} from "vue";
const props = defineProps<{modelValue: boolean;}>();
const emit = defineEmits(["update:modelValue"]);
let windowRef: Window | null = null;
const portal = ref(null);
const copyStyles = (sourceDoc: Document, targetDoc: Document): void => {
// eslint-disable-next-line unicorn/prefer-spread
for(const styleSheet of Array.from(sourceDoc.styleSheets)) {
if(styleSheet.cssRules) {
// for <style> elements
const nwStyleElement = sourceDoc.createElement("style");
// eslint-disable-next-line unicorn/prefer-spread
for(const cssRule of Array.from(styleSheet.cssRules)) {
// write the text of each rule into the body of the style element
nwStyleElement.append(sourceDoc.createTextNode(cssRule.cssText));
}
targetDoc.head.append(nwStyleElement);
}
else if(styleSheet.href) {
// for <link> elements loading CSS from a URL
const nwLinkElement = sourceDoc.createElement("link");
nwLinkElement.rel = "stylesheet";
nwLinkElement.href = styleSheet.href;
targetDoc.head.append(nwLinkElement);
}
}
};
const openPortal = (): void => {
nextTick().then((): void => {
windowRef = window.open("", "", "width=600,height=400,left=200,top=200");
if(!windowRef || !portal.value) return;
windowRef.document.body.append(portal.value);
copyStyles(window.document, windowRef.document);
windowRef.addEventListener("beforeunload", closePortal);
})
.catch((error: Error) => console.error("Cannot instantiate portal", error.message));
};
const closePortal = (): void => {
if(windowRef) {
windowRef.close();
windowRef = null;
emit("update:modelValue", false);
}
};
watch(props, () => {
if(props.modelValue) {
openPortal();
}
else {
closePortal();
}
});
onMounted(() => {
if(props.modelValue) {
openPortal();
}
});
onBeforeUnmount(() => {
if(windowRef) {
closePortal();
}
});
</script>
<template>
<div v-if="props.modelValue" ref="portal">
<slot />
</div>
</template>