Create component with CSS selector? - vue.js

Is it possible to create a Vue Component by passing a CSS selector instead of the name of a custom HTML tag? And, in turn, is it possible to use non-custom HTML tags for template placeholders?
I ask because I am wary of the SEO implications of custom HTML tags.

Not sure if i get your questions right but vuejs does not actually render these custom-tag like template-placeholders. It will transform all template-placeholders with their actual template. See the following example:
CustomComponent.vue
<template><div class="child">Hello World</div></template>
<script>
export default {
name: 'CustomComponent'
}
</script>
Parent Component:
<template>
<div class="parent"><custom-component></custom-component></div>
</template>
<script>
import CustomComponent from './CustomComponent'
export default {
components: {
CustomComponent
}
}
</script>
This will render a dom that looks something like this
<div class="parent"><div class="child">Hello World</div></div>
If you are really concerned about CEO I would recommend looking into server-side rendering. Otherwise all your view components are rendered using javascript execution on the client. Not sure if the search engine crawlers execute javascript or even if they do, how long they will wait for your page to render.

First yes it is possible to define a component using a selector or the element #id to be specific. However, it does not work quite as you are thinking if I understand correctly what you are wanting.
The method is not widely used or even well documented, link & link, but you can use what is known as an x-template. You define the component as follows.
Vue.component('my-cool-component', {
template: '#my-cool-component', //refers to script tag id
data() {
//
},
methods: {
//
}
});
Then you include the actual template markup in your html within an 'text/x-template' script tag with the template id set from your component.
<script type="text/x-template" id="my-cool-component">
<section>
<h1>Title</h1>
<p>...</p>
</section>
</script>
In the case of above you may use just standard html tags.
However to further clarify the second part of your question, you should be able to use custom html tags when naming your components in templates without concern because these are parsed out by Vue.js during rendering. For example if you were to write all you template markup directly in the component instead using template literals as follows,
Vue.component('my-cool-component', {
template: `<section>
<h1>Title</h1>
<p>...</p>
</section>',
data() {
//
},
methods: {
//
}
});
Then in your page markup when you include your custom html element tags <my-cool-component></my-cool-component> Vue will remove the tags and only render the template markup.
<section>
<h1>Title</h1>
<p>...</p>
</section>

Related

How to change the language of whole application from the dropdown in Navbar component in vue

I created a language selection dropdown in my Navbar component. So here is my navbar component:
<div>
<h6>{{ translate("welcomeMsg")}} </h6>
<select name="lang" v-model="lang">
<option value="en">English</option>
<option value="de">Deutsch</option>
</select>
</div>
<script>
export default {
mixins: [en, de],
data() {
return {
lang: "en",
};
},
methods: {
translate(prop) {
return this[this.lang][prop];
}
}
}
</script>
So the parent of this component is an Index.vue which is main component in my application.
<div id="app">
<Topnav/>
<Navbar/>
<router-view></router-view>
<Footer/>
</div>
Currently, I am able to change the language in my Navbar component. So according to the selected value in the dropdown in Navbar component, welcomeMsg is changing. What I am trying to do is I want to put this pieve of code to TopBar "{{ translate("welcomeMsg")}} ", and according to the value of the dropdown in Navbar component, I want to change this value.
Can you help me with this or can you give me an idea how to do it?
If I understand you correctly, you want to use translate method inside Topnav component.
This method is however defined in Navbar, so it's not accessible in Topnav.
To use it elsewhere you could create a mixin with this method to import it to any component. I don't recommend this solution though as mixins are making the code messy.
Another solution is to create a component with translate method defined inside. Let this component do just that: translate a message passed by prop and render it inside some div:
<div>
{{ translatedMessage }}
</div>
<script>
mixins: [en, de],
props: {
message: {
type: String,
default: ''
},
language: {
type: String,
default: 'en'
}
},
computed: {
translatedMessage() {
return this[this.language][this.message];
}
}
</script>
You can reuse this component anywhere in the application. You would still need to pass a language prop somehow, possibly the solution would be to use vuex store to do this, since language is probably global for entire application.
For easier and more robust solutions I would use vue-i18n, which #Abregre has already suggested in his comment: https://stackoverflow.com/a/70694821/9463070
If you want a quick solution for a full-scale application and you don't have a problem with dependencies, you could try to use vue-i18n.
It's a plugin for vue that does exactly this for multi-locale websites/apps in Vue.
https://www.npmjs.com/package/vue-i18n
EDIT
Then in order to use it globally in your app, you should use vuex.
Keep the language selection state there and then wherever you want to use it, you make a computed function with the state.language getter.
The translate function should be a global registered filter
https://v2.vuejs.org/v2/guide/filters.html

Vue component not rendered on second visit

I have a Vue component that lists a bunch of clickable tags. When you click on a tag, it takes you to another page with a list of objects containing that tag.
The relevant parts of the component code are:
<template>
<div>
<h2>All Tags</h2>
<TagList v-bind:tags="tags"/>
</div>
</template>
...
<script>
import TagList from './TagList'
export default {
name: 'AllTags',
components: {
TagList
},
data () {
return {
tags: []
}
},
mounted () {
tags = // array loaded from a database
}
}
</script>
This all works fine when I initially view the page. However if I browse away from this list, e.g. by clicking on a single tag, and then browse back, I only see the <h2>All Tags</h2> header. Using the Vue debugger in the browser, I can see that the data are still there.
I'm using <router-view :key="$route.fullPath"> to control the overall app and suspect the problem lies with the keys somehow.
Can someone point me in the right direction here? How can I get the TagList component to render every time I visit that page of the app?
EDIT: Here's the code of the TagList component:
<template>
<div class="tags">
<Tag v-for="tag in tags" v-bind:tag="tag" v-bind:key="tag" />
</div>
</template>
<script>
import Tag from './Tag'
export default {
name: 'TagList',
props: ['tags'],
components: {
Tag
}
}
</script>
You can try removing v-bind all thought its not required to use, I've checked your code it seems to work fine after visiting a tag and going back, all tags are still rendered. You can take a look at this working sample .
https://codesandbox.io/s/vue-template-3tcs4?fontsize=14

Passing div attribute in props give 503

I am using Trustpilot to make components, which uses different widget on same pages, so every template-id is different. Following is my code but I do not see anything expect TrustPilot logo but if I remove props and give the provided template-id, it works.
What am I doing wrong?
TheWidget.vue
<div class="trustpilot-widget"
data-locale="en-GB"
data-template-id="'${tid}'"
data-businessunit-id=""/omitted because of security
data-style-height="20px"
data-style-width="100%">
Trustpilot
</div>
<script>
export default {
props: ['tid'],
created() {
//Code omitted
}
}
</script>
Home.vue
<TheWidget tid="09765291018" />

How to use the contents of a Vue js component as are initially loaded and then bind them to a variable

We are looking to get the contents from the html (for example using a slot ) but we later (after mounting) want to bind this to a variable as one would do with a v-html.
In other words we want on initialization to have the contents being loaded as they appear in the slot and later this entire piece of content to be controlled by a binding variable like v-html (because it will be html content).
How to achieve this? without following any ugly solutions such as needing to pass the entire initial html content inside v-html attribute!
You can try like this
<template>
<custom-component>
<div v-if="html_variable" v-html="html_variable"></div>
<template v-else>
<!-- default content here -->
</template>
</custom-component>
</template>
<script>
export default
{
data()
{
return {html_variable: null};
}
}
</script>
How using v-html is ugly? Anyway just use a non-visible element to define your initial html. a <script ref="initHTML" type="text/html"> ... </script> might be a good option.
Define a data entry that should hold your HTML init:
data () {
return {
dHTML: '',
}
},
On created() update your initial html state using the ref
created() {
this.dHTML = this.$refs.initHTML.innerHTML;
},
Now you can have a pretty v-html="dHTML"

How to preserve custom component tag names in Vue.js

I'm using Vue's single-file component spec (*.vue) for custom components in my application. Together with rollup and rollup-plugin-vue, I have observed the output in the DOM, for custom components I have written, to be composed of the equivalent html elements.
For example:
component-a.vue
<template>
<span>Hello World</span>
</template>
<script>
export default { name: 'component-a' };
</script>
component-b.vue
<template>
<component-a></component-a>
</template>
<script>
import ComponentA from './path/to/component-a.vue';
export default { name: 'component-b', components: { ComponentA } };
</script>
The above example, if component-a is added to the Vue mount component, will render to a the sum of the two component's template contents in the DOM, which in this case is simply a span element:
<span>Hello World<span>
Is it possible to achieve a rendered output in the DOM like the snippet below, such that custom elements' templates are represented in the DOM by tags which preserve their tag names?
<component-b>
<component-a>
<span>Hello World</span>
</component-a>
</component-b>
Inside your component-a.vue you should be able to achieve that by including some html code within your <template> tag as follow
component-a.vue:
<template>
<customelement>
// Other stuff
</customelement>
</template>
In this way you will be able to call your component-a from anywhere in your app, and to render an element named customelement.
Ideally you should use this "trick" to render standard HTML5 elements, otherwise you might see some error in your vue app console. Let me know how it goes.
Referring to the Vuejs documentation
https://v2.vuejs.org/v2/guide/components.html#DOM-Template-Parsing-Caveats
It should be noted that this limitation does not apply if you are
using string templates from one of the following sources:
String templates (e.g. template: '...')
Single-file (.vue) components
<script type="text/x-template">
If you use Vuejs like the examples above you won't get the result you wanted. So if you render your components in other ways you should get the result you wanted.