vue create component from server rendered html - javascript

I have a Vue instance already loaded with webpack which loads .vue files properly. However there are some files that I cannot use load as some of the html is rendered dynamically from the server.
Suppose I have a HTML file with the content below:
<div id="test">
<input type="text" :value="message"></input>
</div>
How do I create a vue component with the template above?
This was my attempt.
const component = new Vue({
name: 'test-component',
el: '#test',
data: {
message: "hello world!"
},
});
What I want rendered is
<div id="test">
<input type="text" value="hello world!"></input>
</div>

If neither render function nor template option is present, the in-DOM HTML of the mounting DOM element will be extracted as the template. In this case, Runtime + Compiler build of Vue should be used.
---- https://v2.vuejs.org/v2/api/index.html#el

Related

Adding or Injecting HTML or Component into Vue component generated at runtime

I have a Vue app where I take a bunch of markdown files and make them into Components that get dynamically generated and the links of which get handled by Vue Router. I'm loading my markdown using this Vue markdown loader.
The main route file looks like this:
import RamblePosts from "#/assets/rambles/rambles.json"; // Simple JSON that contains the name of the markdown documents
...RamblePosts.map(entry => ({
path: `/${entry}`,
name: entry,
component: () => import(`#/assets/rambles/${entry}.md`)
}))
];
As you can see, I'm generating components based off the markdown files I have in that directory.
Example usage would be:
<template>
<div class="wrapper-div rambling-wrapper">
<div class="ramble-cards-wrapper">
<RambleCard
v-for="route in rambleList"
:key="route.title"
:title="route.title"
:subtitle="route.subtitle"
:ramble-url="route.url"
/>
</div>
</div>
</template>
<script>
import RambleCard from "#/components/RambleCard";
import rambleList from "#/assets/rambles/rambleList.json";
export default {
components: {
RambleCard
},
data() {
return {
rambleList
};
}
};
</script>
This is a simple card element that just displays the name of the markdown entry, a subtitle and the vue-router link for it. Clicking on the link will take you to the relevant article, so something like url.com/foo
Is there a way for me to somehow edit or manipulate these markdown components and add, say, a Vue component to them or even just plain HTML? Since they're generated dynamically at, I'm not sure how to approach the situation because I can't just plug in a Component in the middle of those article components somewhere.

Vue component not mounting or rendering and no error messages

I have the following 2 components
BrewTitle.vue
<template>
<h1>{{ title }}</h1>
</template>
<script>
export default {
data() {
return {
title: "Brew Title"
};
},
created() {
console.log("title created")
}
};
</script>
Snackbar.vue
<template>
<h1>{{ title }}</h1>
</template>
<script>
export default {
data() {
return {
title: "Brew Title"
};
},
created() {
console.log("snackbar created")
}
};
</script>
How they are added to the index.js file
import Vue from "vue";
import BrewTitle from "./components/BrewTitle";
import Snackbar from "./components/Snackbar";
Vue.component("brewtitle", BrewTitle);
Vue.component("snackbar", Snackbar);
const app = new Vue({
el: "#app"
});
In my html template I have the following snippet
<div id="app">
<brewtitle />
<snackbar />
</div>
<script src="main.js"></script>
The components are almost identical, but the snackbar is nowhere to be found on the html page or in the view browser extension. There are no problems with webpack and there is no message in the browser.
What am I doing wrong?
Browsers don't support self-closing tags like these:
<brewtitle />
<snackbar />
Try having explicit closing tags instead:
<brewtitle></brewtitle>
<snackbar></snackbar>
If you use a self-closing tag for a component then the browser will just treat it as an opening tag. An implicit closing tag will be created when the parent element closes. That'll work fine if there are no other siblings but it will go wrong when there are.
So taking your original code as an example:
<div id="app">
<brewtitle />
<snackbar />
</div>
The <brewtitle> won't count as closed until it reaches the closing </div>. So this is equivalent to:
<div id="app">
<brewtitle>
<snackbar></snackbar>
</brewtitle>
</div>
So <snackbar> will be treated as a child of <brewtitle>. As brewtitle doesn't have a slot the snackbar will just be discarded.
This only applies if the HTML is being parsed directly by the browser. For anything parsed by Vue itself, such as in your .vue files, this won't be a problem.
From the official Vue documentation, https://v2.vuejs.org/v2/style-guide/#Self-closing-components-strongly-recommended
Components with no content should be self-closing in single-file components, string templates, and JSX - but never in DOM templates.
...
Unfortunately, HTML doesn’t allow custom elements to be self-closing - only official “void” elements.

Vue js for non SPA apps - loading components in with out the app component

I am very new to Vue.js and I am trying to figure out a few things about it. One of the things I would like to use it for is to implement components without creating an SPA. So in other words I can make a reference to components in a static page with out having to have it run through App component.
When I have done this with react js I have used react habitat. I am wondering if there is something similar for Vue.js that is available or is it something you can do with out a third party module-tool.
You don't need any App component. Just assign any wrapper (div) to a Vue module (Vue instance). I use a component for retrieving contacts, for example.
You can have multiple Vue applications in one page. They just cannot overlap.
html:
<div class="col-md-4 col-sm-4" id="safeContactsFooter">
..some html stuff
<ul class="phone">
<li>Phone: <safe-contact type="phone" ></safe-contact></li>
</ul>
</div>
Vue module:
export default new Vue({
el: '#safeContactsFooter',
components : {
'safe-contact' : () => import('./components/Safe contact') ,
},
});
Then, you have to register the module only when the div with the proper ID is present. Otherwise, the console will yell at you that the object doesn't exist. I do it this way:
if(document.getElementById("safeContactsFooter")){
import('../Safe contacts/Safe contacts footer.Module.js');
}
You can do that by importing your components into a JavaScript file and creating a vue instance with a referenced element:
// JS File
import Vue from 'vue';
import YourComponent from './YourComponent.vue';
export default new Vue({
el: '#app',
components: {
YourComponent
}
});
// HTML file
<div id="app">
<your-component></your-component>
</div>

Inject or Initialize Vue components in generated HTML

I use a an WYSIWYG article editor that generates some HTML for articles that I save in the database and later show to the user.
The problem is I need to insert Vue components into this auto generated HTML for showing dynamic products. I can make a custom block in the editor that adds in HTML but I want it to work as a Vue component that updates the product description directly from the database.
What Im thinking now is to add a button that adds a div with a data property of the products ID. I can then replace that div in the code with a Vue component with the same ID by injecting a component.
Another idea I had was to simply add in components like <product id="1031"/> as plain html and then try to compile the whole article HTML with Vue but I read that the v-html directive only compile code as plain HTML.
Is this possible? Or is there any better ideas?
If you are using the full build of Vue (not the runtime only build) you can initialize a new instance of Vue and mount it wherever you like, pass in data etc.
// Main app
new Vue({
el: '#app',
data: {
stuff: 'inserted message'
},
methods: {
clicked() {
// Add new
new Vue({
template: `<h1 style="color: red;">{{ message }}</h1>`,
parent: this,
data: {
message: 'new message'
}
}).$mount(document.getElementById('more'))
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.js"></script>
<div id="app">
There are some things here before like {{ stuff }}
but when you press <button #click="clicked()">add more</button>
you can add more things here:
<div id="more"></div>
</div>

Jquery and Vue, .html() is not working

I have been playing with the Vue tutorial Here and I have added a simple Jquery .html function. However it is not working. I have added the jQuery plugin, and there are no errors in the console. I have my "App" component defined like this:
<template>
<div id="app">
<div id="mainMenu"> Hello </div>
</div>
</template>
<script>
import * as start from './assets/scripts/start.js'
export default {
name: 'app',
created: start.loadMainNavigation()
}
</script>
and my loadMainNavigation function like this:
function loadMainNavigation() {
$('#mainMenu').html("ASERFDASRF");
console.log("In load Nav");
}
I can see the "In load Nav" in the console. No errors, but the DIV still has the original "Hello" - What am I doing wrong?
The reason the content doesn't change is that, at the time you are executing your function, the component has not yet been rendered to the DOM. The DOM is not rendered until the mounted event.
Beyond that, however, you need to be careful when you are integrating jQuery and Vue, or avoid it altogether. The idiomatic Vue way to do this would be something like this.
console.clear()
new Vue({
el: "#app",
data:{
message: "Hello"
},
created(){
this.message = "ASERFDASRF"
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.js"></script>
<div id="app">
<div id="mainMenu"> {{message}} </div>
</div>
There are a few times when you might mix jQuery and Vue (when you want to use a jQuery plugin for which there is no Vue counterpart, for example) but typically, there is almost always a way to do what you want without jQuery.

Categories