Render Component in iframe using vuejs without src attribute - html

<iframe id="frame" width="100%" height="100%">
</ifrme>
I want to render component in this iframe. Is there any option of creating html element or rendering component in iframe?
new Vue({
el:'#frame',
store:store,
router:router,
render: component
})

The easiest way for me is to use srcdoc attribute. It loads raw html overriding src attribute.
<template>
<iframe :srcdoc="html"></iframe>
</template>
Update: More detail example: Consider a textarea for a user html input and want to display in an iframe.
<template>
<div id="app">
<textarea v-model="html"></textarea>
<iframe :srcdoc="html"></iframe>
</div>
</template>
<script>
export default {
name: "App",
data(){
return {
html:"<h1>Hello I am H1 block</h1>"
}
}
};
</script>

You can refer below link That helped me a lot.
Here is the link and the code snippets.
Vue.component('i-frame', {
render(h) {
return h('iframe', {
on: { load: this.renderChildren }
})
},
beforeUpdate() {
//freezing to prevent unnessessary Reactifiation of vNodes
this.iApp.children = Object.freeze(this.$slots.default)
},
methods: {
renderChildren() {
const children = this.$slots.default
const body = this.$el.contentDocument.body
const el = document.createElement('DIV') // we will mount or nested app to this element
body.appendChild(el)
const iApp = new Vue({
name: 'iApp',
//freezing to prevent unnessessary Reactifiation of vNodes
data: { children: Object.freeze(children) },
render(h) {
return h('div', this.children)
},
})
iApp.$mount(el) // mount into iframe
this.iApp = iApp // cache instance for later updates
}
}
})
Vue.component('test-child', {
template: `<div>
<h3>{{ title }}</h3>
<p>
<slot/>
</p>
</div>`,
props: ['title'],
methods: {
log: _.debounce(function() {
console.log('resize!')
}, 200)
},
mounted() {
this.$nextTick(() => {
const doc = this.$el.ownerDocument
const win = doc.defaultView
win.addEventListener('resize', this.log)
})
},
beforeDestroy() {
const doc = this.$el.ownerDocument
const win = doc.defaultView
win.removeEventListener('resize', this.log)
}
})
new Vue({
el: '#app',
data: {
dynamicPart: 'InputContent',
show: false,
}
})
https://jsfiddle.net/Linusborg/ohznser9/

I've tried and haven't found a way to mount vue directly on #iframe.
Yet, you can add div to #iframe and mount to that:
// create iframe element
var iframe = document.createElement('iframe')
iframe.id = 'iframe'
// place iframe inside page html
document.documentElement.insertBefore(iframe, document.querySelector('html').firstChild)
// append div to iframe
var container = document.createElement('div')
container.id = 'container'
iframe.contentWindow.document.body.appendChild(container)
// render vue component inside iframe on #container
new Vue({
el: container,
render: h => h(component)
})
Result:
<html>
<iframe id="iframe">
#document
<html>
<head>
</head>
<body><!-- <-- here was <div id="container"></div> -->
<div class="message" style="color: orange;">Hello from Vue component!</div>
</body>
</html>
</iframe>
<head>
</head>
<body>
</body>
</html>
P.s. I've used this code in chrome extension content scripts (javascript injected into pages). If you're going to use
it elsewhere make sure not to break Same-origin policy.

new Vue({
el:'#frame',
store:store,
router:router,
render: component
})
just try to give a name to your route view.
Hope it works

Related

Vue.js: Dynamically render html in child component's slot

In my vue.js application, I am trying to render the html content dynamically in child component's slot. If I enter the text only then there is no issue, it works with fine.
Here is my code:
ChildComponent.vue
<template>
<div :class="type" class="message" v-if="type">
<slot />
</div>
</template>
<script>
export default {
...
props: ['type'],
...
}
</script>
ParentComponent.vue
<script>
import Alert from '#/Alert';
export default {
components: {
Alert,
},
data() {
return {
...
alert: {
error: '',
message: '',
}
};
},
created () {
this._onLoad()
},
methods: {
_onLoad() {
axios.get(`api.call.here`).then((res) => {
...
}).catch(error => {
this.alert.error = error.type;
this.alert.message = `<p>message here</p>`; // from response
});
},
}
}
</script>
Here is the screenshot of the issue:
What you trying to do can be achieved with v-html. You can use it while calling your ChildComponent.vue. This is a small example for your case:
<Alert>
<span v-html="alert.message"></span>
</Alert>

vue + pure html component?

how to implement vue-cli calling pure html method?
Please check below as sample file. because I have custom pure html code and facing difficulty converting it to vuejs.
product.vue
<template>
<custombutton #childclick="childclick" />
</template>
<script>
export default {
component: { custombutton },
methods: {
childclick(value) {
console.log(value)
}
}
}
</script>
custombutton.html
<html>
<body>
<button #click="childclick" />
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.6/vue.min.js"></script>
<script>
var App = new Vue({
el: '#app',
data() {
return {
vueMessage: 'testing vue message',
}
},
methods: {
childclick() {
this.$emit('childclick', 'success!')
}
},
});
</script>
</html>
Assuming you want to preserve the possibility to call Vue component from both .html file and .vue files, I would recommend moving your Vue logic from custombutton.html file into a separate custombutton.js file, which will export an object representing Vue component previously defined in HTML. You can then import custombutton.js both in custombutton.html and product.vue.
Example:
custombutton.js:
export default {
name: 'CustomButton',
template: '<div>Hello world!</div>'
}
custombutton.html:
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app"></div>
<script type="module">
import CustomButton from "./custombutton.js"
new Vue({
el: '#app',
components: { CustomButton },
template: '<CustomButton />'
});
</script>
</body>
</html>
product.vue:
<template>
<CustomButton />
</template>
<script>
import CustomButton from "./custombutton.js"
export default {
components: { CustomButton }
}
</script>
Note that:
For custombutton.html to work target browsers should implement ECMAScript modules.
For product.vue to work you should set runtimeCompiler: true in your Vue CLI configuration. (Since the template in custombutton.js is defined as a string runtime compiler needs to be included in the final bundle.)
It is important to find a suitable location for custombutton.js so it can be imported easily using relative paths from both custombutton.html and custombutton.vue files.
Defining the template as a string in custombutton.js can be quite inconvenient, as you have no markup highlighting, however I don't see any workaround for this.
This solution is a bit more cumbersome, but allows template to be written with syntax highlighting into <script> element, which is more convenient than writing template as a string literal into a template property.
custombutton.js:
export default {
name: 'CustomButton',
data: function () {
return { testVar: 125 }
}
}
custombutton.component.html:
The template is now located in #custombutton-template element. "Hello world! 125" should be printed out.
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.14/dist/vue.js"></script>
</head>
<body>
<script id="custombutton-template" type="x-template">
<div>Hello world! {{ testVar }}</div>
</script>
<div id="app"></div>
<script type="module">
import CustomButton from "./custombutton.js"
CustomButton.template = "#custombutton-template"
new Vue({
el: '#app',
components: { CustomButton },
template: '<CustomButton />'
});
</script>
</body>
</html>
product.vue: Thanks to Webpack config (see below) we are able to import contents of custombutton.component.html file as a string, parse it and get inner HTML of #custombutton-template element, which is the desired template.
<template>
<CustomButton />
</template>
<script>
import CustomButton from "./custombutton.js"
import CustomButtonComponent from "./custombutton.component.html"
var el = document.createElement("html")
el.innerHTML = CustomButtonComponent
var template = el.querySelector("#custombutton-template").innerHTML
CustomButton.template = template
export default {
components: { CustomButton }
}
</script>
Importing custombutton.component.html file as string is done by non-default Webpack raw-loader, therefore it is necessary to adjust Webpack config:
vue.config.js:
module.exports = {
runtimeCompiler: true,
configureWebpack: {
module: {
rules: [
{
test: /\.component\.html$/,
use: ["raw-loader"]
}
]
}
}
}
package.json:
{
"devDependencies": {
"raw-loader": "^4.0.2"
}
}

Pass VueJS data key-variable to onmouseover atrribute inside a <a> tag

I have the following bits:
<script>
window.onload = function vue () {
var app = new Vue({
el: '#app',
data () {
return {
message: 'Click here to edit your details!'
}
}
});
}
</script>
<h2>Hello <a id="myName" href="#" onmouseover="???" v-bind:title="message">{{username}}</a></h2>
({{username}} is being fetched from a Django view.)
What I need is to pass the 'message' value to onmouseover somehow, or something similar, so that when you hover over the username link, it shows the value of message in a Vue tooltip.
Many Thanks
You can use v-on mouseover to fire a function wich will set the message :
window.onload = function vue () {
var app = new Vue({
el: '#app',
data () {
return {
message: '',
username: 'sss'
}
},
methods: {
showMessage() {
this.message= 'Click here to edit your details!'
}
}
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="app">
<h2>Hello <a id="myName" href="#" v-on:mouseover="showMessage" v-bind:title="message">{{username}}</a></h2>
<div>
{{message}}
</div>
</div>
I have just discovered that the VueJs data variable containing the "message" needs to be v-bind to an actual HTML element, as is, for example, an html tag's 'title' attribute. Thus, it can be passed to 's title attribute likewise:
<div id="app">
<a id="user_name" href="#" v-bind:title="message">{{user_name}}</a>
</div>
And having only this:
var app = new Vue({
el: '#app',
data: {
message: 'LOL'
}
})
And that's pretty much how it works, without a need for a mouseover call.

v-on:click in component not working

A vue.js component creates a button which should call a function, but the function is never called and the v-on:click is not visible in Chrome's element inspect. My html goes like this:
<bottomcontent></bottomcontent>
And my Vue is like this:
var bottomcontent = {
template: '<div class="bottomcontent"><div class="moreresults" v-on:click="appendcontent">More Results</div></div>'
}
new Vue({
el : 'body',
data : {
homepage:{
numberofdivs: 60
}
},
methods : {
appendcontent: function() {
homepage.numberofdivs += 60
}
},
components: {
'bottomcontent': bottomcontent
}
})
The problem is that methods has to use funcions, not objects.
methods: {
appendcontent: function() {
homepage.numberofdivs += 60
}
}
You also have to correct your markup accordingly.
var bottomcontent = {
template: '<div class="bottomcontent"> <div class="moreresults" v-on:click="appendcontent"> More Results </div></div>'
}
There are some problems lead to the crack.
In the function appendcontent,you should call the data "this.homepage.numberofdivs".
and the correct demo is posted on https://jsfiddle.net/atsknydr/
methods : {
appendcontent: function() {
this.homepage.numberofdivs += 60;
console.log(this.homepage.numberofdivs);
}
}
First, as the warning says:
[Vue warn]: Do not mount Vue to <html> or <body> - mount to normal elements instead.
So, you should create an element like <div id="app"></div> to mount your app instead of <body>.
The problem you are facing is a scope problem. You are trying to call a method from the inside a component scope, that is why it's not finding the method.
Take a look at the docs to understand better.
So, in order to make this work you should change the method from the app scope to the template scope.
Your html:
<body>
<div id="app">
<bottomcontent></bottomcontent>
</div>
</body>
Your js:
<script>
var bottomcontent = {
template: '<div class="bottomcontent"><div class="moreresults" v-on:click="appendcontent">More Results</div></div>',
data: function () {
return {
homepage: {
numberofdivs: 60
}
}
},
methods: {
appendcontent: function () {
console.log('Called method!');
this.homepage.numberofdivs += 60
}
}
}
new Vue({
el: '#app',
components: {
'bottomcontent': bottomcontent
}
})
</script>

How to bulid Application template Vue

I'm new to Vue and to ES6
And I did the following:
import Vue from 'vue'
import VueRouter from 'vue-router'
import $ from 'jquery'
Vue.use(VueRouter)
var App = {};
App.template = `
<main-menu></main-menu>
<router-view></router-view>`;
const header = Vue.component('main-menu', require('./components/app/header.vue'));
const facebook = Vue.component('facebook-gif', require('./components/facebook.vue'));
const router = new VueRouter({
routes: [
{
path: '/',
},
{
path: '/facebook',
component: {
facebook: facebook
}
}
]
});
App.app = new Vue({
router,
render (h) {
return h(`div`, App.template)
}
}).$mount('#app');
But what it's nothing render , I just see the main-menu and router-view tags in my broswer...
And when I edit my html and put there this:
<div id="app">
<main-menu></main-menu>
<router-view></router-view>
</div>
I get this error when I'm trying to enter the facebook route:
[Vue warn]: Failed to mount component: template or render function not defined.
and the facebook template is wrapped with template tag and it's inside a vue file
facebook.vue
<template>
<div>
dsfsdsfdsf
<div v-if="showLogin">
<button v-on:click="login">Log In With Facebook</button>
<span v-if="error">{{ error }}</span>
</div>
</div>
</template>
<script>
export default {
data() {
return {
showLogin: true,
error:null,
}
},
methods() {
return {
login() {
}
}
}
}
</script>
But the main-menu component is render...
What is the problem?
EDIT
I downloaded the example like wostex said
I create an App.vue file contain:
<template>
<div id="app">
<main-menu></main-menu>
<router-view></router-view>
</div>
</template>
I edit my html file to contain
I added in app.js
import App from './components/App.vue'
const v = new Vue({
el: "#app",
router,
render: h => h(App)
});
and my html file contain:
<div id="app"></div>
and I get this error:
vue.common.js:436 [Vue warn]: Failed to mount component: template or render function not defined.
found in
---> <Anonymous>
<App> at /opt/lampp/htdocs/gif/resources/assets/js/components/App.vue
<Root>
it happens because the facebook component, when I'm in the main page I don't see the error, only when I enter the facebook route
It seems your first set up was failing because of what build you we're using. For eg:
App.app = new Vue({
router,
render (h) {
return h(`div`, App.template) // this part can be roughly
// translated to `return h(`div`,
// `<one-component></one-component>
// <router-view></router-view>`)` and I believe
// this failed due to the fact that when you pass
// template string to the render method it needs to
// be compiled and your setup didn't account for that.
}
}).$mount('#app');
Your other set up ( as per suggestion of #wostex ) is much better but I think that here you are missing .$mount('#app') at the end of your Vue initialization. So:
const v = new Vue({
router,
render: h => h(App)
}).$mount('#app')
I looked at Laracasts in Jeffry tutorial about Vue
He did there like that:
const router = new VueRouter({
routes: [
{
path: '/',
},
{
path: '/facebook',
component: require('./components/facebook.vue')
}
]
});
and it work's
So thanks every one that tried to help me