How to wrap dynamic HTML from database around Vue.js template - javascript

I need to be able to wrap custom HTML around my Vue template content. As you can see below, it's not simply inserting html content using <div v-html="HtmlWrapperTopHalf"> because that will automatically close any unclosed tags. The tags will always be closed in the bottom half of the dynamic HTML. Basically, I'm looking to insert the Vue template code into my dynamic template HTML.
I also can't just assume what's in the dynamic HTML and build that inside the Vue template. This HTML comes from a RichText editor that my customers create on their own. They just insert a placeholder {{MAIN_CONTENT}} in the middle of their dynamic template and that's where the Vue Template functionality should appear.
Page.vue
<template>
<div>
//Top half of dynamic XHTML wrapper goes here
<p>Inner Content Here</p>
<ComponentA />
<ComponentB />
<!-- etc. --->
<p>More Inner Content</p>
//Bottom half of dynamic XHTML wrapper goes here
</div>
</template>
<script>
axios.get("getHtmlContent").then((result) =>{
console.log("top", result.data.HtmlWrapperTopHalf)
console.log("bottom", result.data.HtmlWrapperBottomHalf)
});
</script>
console.log
top: <div class="my-dynamic-class" id="my-unique-id"><h1>DYNAMIC TITLE</h1>
bottom: <div id="my-dynamic-footer">custom footer text</div></div>
HTML Output:
<div>
<div class="my-dynamic-class" id="my-unique-id"><h1>DYNAMIC TITLE</h1>
<p>Inner Content Here<p>
<div>Hello from ComponentA!!</div>
<div>Hello from ComponentB!!</div>
<!-- etc. --->
<p>More Inner Content<p>
<div id="my-dynamic-footer">custom footer text</div></div>
</div>
Hopefully this diagram of the concept will help:

Given that other components can be a part of this split up html content, using the render syntax to generate a slot within the content seems to be the only alternative.
render(createElement) {
return createElement(
'div', { 'class': 'hello'},
this.$slots.default
)
},
Have your axios component be built out within the render (see docs), and then use this as a slot to fill in within future components.
E.g. <ClientHtmlInject> <Comp1/><Comp2/> </ClientHtmlInjection>

Related

Remove component tag in StencilJS

I'm trying to remove the called component tag from HTML to prevent some broken CSS from external libraries and just show the inner content.
something.component.html
<div>
Hello World
</div>
another.component.html
<div>
<app-something [config]="somethingConfig"></app-something>
</div>
Then outputs:
<div>
<app-something>
<div>
Hello World
</div>
</app-something>
</div>
And I want:
<div>
<div>
Hello World
</div>
</div>
This is not possible due to the nature of web components which Stencil outputs.
What you could do instead: use the CSS rule display: contents on your component which prevents it from generating a box in the layout (see https://caniuse.com/css-display-contents, still somewhat experimental).
There are also functional components in Stencil (https://stenciljs.com/docs/functional-components) which don't generate a parent element, but those are only available within JSX, so you'll always need at least one parent Stencil component (so that you can render some JSX).

Render external element inside Vue component

I have an external div that I need to render inside my Vue app. I'm trying to use a slot, like but that's a no go as nothing renders.
Any ideas?
Goal is to have HTML like this (Vue mounts on #app):
<div id="app" data-slot-header="#header"></div>
<div id="header">
<h1>Title here</h1>
</div>
Then the Vue component
<template>
<div>
<slot name="header"></slot>
</div>
</template>
You can use a dynamic <component> and refer to your #header element as a template reference.
For example
new Vue({
data: () => ({
headerComponent: {
template: '#header' // refer to template element by selector
}
}),
}).$mount('#app')
#app:before,#header:before{position:absolute;top:0;right:0;color:rgba(1,1,1,.5);font-size:.8rem}#app{border:1px solid #666;position:relative}#app:before{content:'Vue app'}#header{position:relative;opacity:.5}#header:before{content:'Original header'}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<div id="app">
<p>Dynamic component rendered here 👇</p>
<component :is="headerComponent"></component>
</div>
<div id="header">
<h1>Title here</h1>
</div>
Slots are mainly used with reusable Vue components so that the parent component can render custom stuff inside designated sections of the child. The root component does not have a parent, so it doesn't make sense to use slots for this.
Why can't you just hard-code the div in the template? Or do you need it to be dynamic; will you be swapping out the header contents in some situations? Please provide more information about what your use-case is, otherwise my answer is "just hard-code it".
Take a look at portal-vue. It allows child components to render templates anywhere in the DOM. This might work for your situation.

How can I use template tag inside slot in Vue.js?

I have a template that includes some HTML along with some script tags. I want to use it inside my vue component as a template that later I will place into the DOM and I would like it to be placed as is, so my script tags are also executed.
I would like to keep the template inside the component tag and use a slot.
e.g.
<amazing-component>
<template>
<p>This is the content</p>
<script>
console.log("I want to be executed as long as someone puts me in the DOM!");
</script>
</template>
</amazing-component>
<script type="text/x-template" id="component-template">
<slot></slot>
</script>
But the problem is that Vue removes the template and the script tags and then replaces the slot tag.
What I've desperately tried so far and didn't work:
Put the template inside another template - the template just disappears.
Wrap the slot with a template - the template just disappears.
Use a <script type="text/x-template" > - that was an epic failure.
Get the slot from $slots - It is a VNode that doesn't have template/script tags.
The biggest problem is that the front-end doesn't have a clue of what the html inside the template tag looks like. It is just some html that is rendered on the server, some immutable legacy code that has to be inserted as-is in the page in order to work.
Of course I can put the template tag outside of the component and fetch it another way, but I would like to have it inside the component to keep it a bit more tidy and elegant.
While Vue consumes template tags in its own compiling, you can still force it to emit HTML template tags by using <component is="template">
var app = new Vue({
el: '#app',
template: `
<div>
<h1>No template:</h1>
<template>
test
</template>
<p>More code (check the page source)</p>
<h1>Yes template: </h1>
<component is="template">
test
</component>
<p>More code(check the page source)</p>
<h1>Yes script: </h1>
<component is="script">
console.log('Scrpt test');
</component>
<p>More code(check the console)</p>
</div>
`,
data: {}
})
<!-- development version, includes helpful console warnings -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app"></div>
That's not how Vue works. <script> tags do not belong in the <template> and are omitted for a reason. If you want something to be executed on page load, use a coresponding hook
To execute server generated JS code use eval()
Parent.vue
<template>
<child script="console.log('something')"></child>
</template>
Child.vue
<template>
</template>
<script>
props: ['script'],
created() {
eval(this.script)
}
</script>

Multiple Ractive components

At the moment it is not possible to use more then one component in a template. For example:
<div class='wrapper'>
<LeftColumn>
<RightColumn>
<p>text here</p>
</div>
Ractive displays only the first one. The situation is the same if I want to use same component tag twice. It's even more strange when I have only one component but place something after the tag (the <p>text here</p> above). It is not displayed too.
Here is a JSBin showing the problem http://jsbin.com/maxen/3/edit?html,js,output
You need to either add closing </widget> tag or use self-closing syntax - <widget />. Demo here.

Can I wrap CKEditor's editing block in several tags to mimic context?

I need to wrap editing block's in some divs to mimic context, so the preview does render with according CSS stylesheet.
I'd like CKEditor to render HTML inside
<div class="page">
<div class="sidebar">
<div class="header">
<!-- ckeditor edited HTML here -->
</div>
</div>
<div>
so the, for example, H1 will look like rendered on site.
Can I achieve this?
You can add extra styles to the editor in the config.js file.
CKEDITOR.editorConfig = function (config) {
config.contentsCss = ['/Content/Style/site.css', '/Content/Style/bootstrap/bootstrap.css'];
}

Categories