How to replace DOM elements with a Vue component? - vue.js

I inject raw html into my page. I would like to extract all the <a> elements in this and replace them with my <custom-link-component>. Is there a way of doing this with Vue?
I get raw html from the data service and inject it into a vue component using v-html.
So far I have a mixin that finds all <a> elements but can't work out how to replace them:
const links = document.querySelectorAll('a');
Many thanks.

I think it's not possible to achieve what you want in this way. If you want to use vue component instead of links, you have to place them in your markup as components like vue router-link as an example:
<!-- literal string -->
<router-link to="home">Home</router-link>
<!-- renders to -->
Home
It was discussed here, look like same question.

Related

Render non-vuejs HTML in a component

I have a working VueJS app with nested components.
In one of the components, I want to be able to inject arbitrary HTML but I don't want VUEJS to parse it : I want plain old HTML tags (scripts, iframes, style, divs, native events, whatever I need).
I know I can do that outside the root "#app", but is there a way to do that inside it ?
Thanks.
You can use v-html directive, it takes an expression that evaluates to a string and sets the element's innerHTML to that string. Vue won't parse it as a template and insert it into the DOM instead. This is one of those things that you need to pay attention to security for.
See docs: https://vuejs.org/api/built-in-directives.html#v-html

Parse string with components inside to template in vue.js

Is it possible to parse string with components inside to template in vue.js? Example of string:
"Some text, some <b>bold text</b>, and inserted image from this
component <vue-simple-image :src='images/my_image_name.png' />, another text and html tags."
It looks like I need store such strings to database to use them later for recreating user input from vue-wysiwyg editor.
In the strict sense you asked the question, I do not think this is possible. There is a v-html directive, that can render html for you but not components. This is also considered an anti-pattern, as the vue guide states:
Dynamically rendering arbitrary HTML on your website can be very dangerous because it can easily lead to XSS attacks. Only use v-html on trusted content and never on user-provided content.
You could look into dynamic components in order to render vue components based on user input.
You could parse the wysiwyg user input, split the string on recognized vue-component tags (so you have an array of pieces of elements with sequences of regular html and elements that are single vue-components), and then use a template with v-for looping to render this. (non-working pseudocode) example:
<div id="renderedWysiwygInput">
<div v-for="elem in splitInput">
<component v-if="stringIsVueComponent(element)" v-bind:is="element"></component>
<div v-else v-html="element"></div>
</div>
</div>
You'll have to work this example out a bit more though to account for the possibility of input inside the vue components themselves, for example if you are filling slots. I would try to limit what kind of input you are going to support to keep it manageable.
No, this is not possible, because Vue component is not just an html piece, it is a js class. So you need to register it properly and so on...

Is it possible in Vue to programatically wrap an element or component with a transition using a custom directive or render function?

To make code more simple/clean for me and my designers, I'd like to be able to do something like below. Is it possible - using a custom directive or render function to implement this with a simple attribute?
This would really help separating animation from structure and functionality, which I think could be helpful in many cases. I figure render functions can easily wrap an element with other HTML elements, but can they wrap elements (or components) with custom Vue transitions?
This:
<template>
<my-component custom-transition></mycomponent>
</template>
Becomes this:
<template>
<custom-transition>
<my-component></mycomponent>
</custom-transition>
</template>
Or maybe bring it up on Github?
Thanks!
A Vue forum member provided a great solution for me in this thread using dynamic components. Happy!

Are self-closing tags, e.g. <tag />, legal in Vue?

In the Vue documentation, I have seen opening and closing tags, but I've seen in other places where authors write components as self closing tags, like <some-component />
Is the practice of self-closing tags legal in Vue?
From the Vue style guide:
Components with no content should be self-closing in single-file
components, string templates, and JSX - but never in DOM templates.
It's legal and strongly recommended by the Vue style guide:
Vue Style Guide #self-closing components
Both the questions are answered above. But, I would like to point out what exactly is meant by no content in self closing tags.
When we use <div><p>Something</p></div>, <p> tag here is the content and hence, we cannot use div as a self closing tag.
Similarly in case of Vue JS components, you can also include content inside the component tags. e.g., <MyComponent><p>Something Else</p></MyComponent>.
Then, in the component definition of <MyComponent>, you have to includes to render the content passed wherever <MyComponent> is used.
If you intend to not have any content to be passed from the <MyComponent>. i.e. If you do not have the <slot> tag in the definition of your component, then your <MyComponent> can be a self closing tag.

How to disable replacing the app root div with the component HTML while using templates

So basically, when using components - the app root passed to the Vue instance gets replaced by whatever HTML is in the component. Is there a way to disable this and just nest the stuff Vue renders inside the app root instead?
for example - if index.html has a wrapper of
<div id="myVueApp"></div>
and I set el: "#myVueApp" on the Vue instance, the whole node will get removed and replaced by whatever I have in my template resulting in
<div id="myComponent">...</div>
Is there a way to make it into
<div id="myVueApp">
<div id="myComponent">...</div>
</div>
Should work. From what I understand, you want to have multiple parts of your Vue app to be splitted up in the rendered HTML output as well, more specifically into multiple divs.
I think this should work if you use multiple Vue instances.
Set up a structure in your HTML file and give them appropriate id's.
Then, create the Vue instances you want and assign each of them to their specific div using el.
However, I can't tell you if this is a good idea and follows the best practice..
Hope this helps!