Parse string with components inside to template in vue.js - 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...

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

How to work with vue.js and window.getSelection()?

Here is an example from some tutorial:
<p id="p">Example: <i>italic</i> and <b>bold</b></p>
<script>
let range = new Range();
range.setStart(p.firstChild, 2);
range.setEnd(p.querySelector('b').firstChild, 3);
alert(range); // ample: italic and bol
// use this range for selection (explained later)
window.getSelection().addRange(range);
</script>
How to do this with vue?
Should I use query selectors too?
I am interested how to do this selection manipulation within contenteditable. I can use "ref" for contenteditable container but inner content with bold, italic etc. tags is dynamic and mark this code with refs:
... <b><i>some text</i></b> ...
isn't appropriate.
If you're using the Selection API to manipulate the DOM (not just creating ranges, but adding/removing/modifing/reordering DOM nodes), then you should be doing those manipulations on DOM elements not managed by Vue. You must not modify parts of the DOM managed by Vue because Vue won't know about those changes and it will get confused when trying to patch the DOM during the next render cycle. Vue "owns" the rendered DOM of its components.
This doesn't mean you can't use the Selection API and Vue together, it just means you need to be careful not to tinker in the DOM willy-nilly.
Should I use query selectors too? Using p.querySelector('b').firstChild isn't vue way but I don't know what should I use insted
This rule only applies if you want to get a reference to a DOM node rendered by Vue. If the container were content editable, then its contents would not be managed by Vue and you would have no way of referencing its contents without using querySelector and other DOM functions. Try not to get caught up with "am I doing it the Vue-way?" when what you are trying to do is inherently not Vue related anyway.

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.

VueJS using parent name tag inside child

Here is an example:
<input name="TESTE" id="TESTE" placeholder="TESTE">
is there a way to do that?
<div name="TESTE">
<input :name="parent.name" :id="parent.name" :placeholder="parent.name">
</div>
I dont want to do that using vue data or components. Can i do that using only pure html like example above?
Thanks!!!
Unfortunately that's not possible. You'll need to use some sort of data field for this to work. Vue renders HTML according to the data you provide it and is otherwise unaware of the properties of surrounding elements. Your best bet is to either hard-code these values or add the appropriate data fields to reference.
It's generally better practice to use the data, anyway, as it will cut down maintenance time and mitigate issues with user error.

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!