Passing div attribute in props give 503 - vue.js

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" />

Related

Paginated async Component doesn't trigger setup() on route change

I have a paginated component. The async setup() method is pulling data from an API to populate the page. It works fine when the route is directly loaded, but when I change the route to a different page slug (eg. clicking a router-link), the component is not reloaded and setup is not executed again to fetch the new data.
I guess I somehow want to force reloading the component?
This is my MainApp component it has the router view and fallback.
<router-view v-slot="{ Component }">
<Suspense>
<template #default>
<component :is="Component" />
</template>
<template #fallback>
loading...
</template>
</Suspense>
</router-view>
The router looks kinda like that. You see the page component takes a page_slug:
const routes: Array<RouteRecordRaw> = [
{
path: "/",
name: "",
component: MainApp,
children: [
{
name: "page",
path: "page/:page_slug",
component: Page,
props: true,
},
// [...]
]
}
And this is how my Page component looks like. It uses the page_slug to load data from an API which is then used in the template:
<template>
<div> {{ pageData }} </div>
</template>
export default defineComponent({
name: "Page",
props: {
page_slug: {
type: String,
required: true,
},
},
async setup(props) {
const pageData = await store.dispatch("getPageData", {
page_slug: props.page_slug
});
return { pageData }
}
}
When I directly open the route, the fallback "loading..." is nicely shown until the data is returned and the component is rendered.
But when I do a route change to another page, then async setup() is not executed again. In that case the url in the browser updates, but the data just remains the same.
How can I solve this case? Do I have to force reload the component somehow? Or have an entirely different architecture to the data loading?
The answer is simple, when trying to create Vue 3 Single File Components (SFCs) in Composition API way as shown below:
<template>
<!-- Your HTML code-->
</template>
<script>
export default {
name: 'ComponentName',
async setup():{
// Your code
}
};
</script>
<style>
/*Your Style Code*/
</style>
<script>, will only executes once when the component is first imported. So, when the data have changed by other component, the component above will not updated or in other words not re-created.
To make your component re-created whenever it about to mount, you have to use <script setup> which will make sure the code inside will execute every time an instance of the component is created, but you need to re-write your script code with few changes in comparison when using setup() method, and also you are able to use both of scripts like this:
<script>
// normal <script>, executed in module scope (only once)
runSideEffectOnce()
// declare additional options
export default {
name: "ComponentName",
inheritAttrs: false,
customOptions: {}
}
</script>
<script setup>
// executed in setup() scope (for each instance)
</script>
Read this documentation carefully to have full idea.

How do I reference an image inside the Setup function in the Composition API in Vue 3?

How do I reference an image in the Setup function in the Composition API? The path is '../assets/pic.png'
If I use the path directly inside the template, as the src in an img tag, the image displays on the page. When I inspect it, it shows the image name, followed by an id, then the file extension e.g: “/img/pic.123456.png”. I can do it like this to get what I want, but it doesn’t seem like the correct way of doing things in Vue.
I’m thinking it should be something like:
<template>
<div>
<img src="pic">
</div>
</template>
<script>
import { ref } from 'vue'
export default {
setup(){
const pic = ref('../assets/pic.png')
return { pic }
}
}
</script>
<style>
</style>
I believe it would work like this in the Options API (without ‘ref’, of course). I can’t get it to work with the Composition API. I'm thinking it may be something to do with the 'id'. Also how would I reference images in an array?
Thanks.
You need to require the image first with the require function, and then pass the returned value to ref. and you should bind the src attribute with v-bind.
here is a complete example based on your code:
<template>
<div>
<img v-bind:src="pic">
</div>
</template>
<script>
import { ref } from 'vue'
export default {
setup(){
const pic = ref(require('../assets/pic.png'))
return { pic }
}
}
</script>
<style>
</style>
I had the same issue, and using require didnt work for me, finally, I got this:
<template>
<div>
<img v-bind:src="pic">
</div>
</template>
<script>
import pic from '../assets/pic.png'
export default {
setup(){
}
}
</script>

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

Vue js loading js file in mounted() hook

I have the following Vue component:
<template>
<div id="wrapper">
<div class="main-container">
<Header />
<router-view/>
<Footer/>
</div>
</div>
</template>
<script>
import './assets/js/popper.min.js';
// other imports
// ....
export default {
name: 'App',
components : {
Header,
Footer
},
mounted(){
// this is syntax error
import './assets/js/otherjsfile.js'
}
}
</script>
As is clear from the code snippet, I want to have the otherjsfile.js loaded in mounted() hook. That script file has certain IIFEs which expects the html of the web page to be fully loaded.
So how do I invoke that js file in a lifecycle hook?
This is the pattern I use. The example is importing a js file which contains an IIFY, which instantiates an object on window.
The only problem with this would occur if you want to use SSR, in which case you need Vue's <ClientOnly> component, see Browser API Access Restrictions
mounted() {
import('../public/myLibrary.js').then(m => {
// use my library here or call a method that uses it
});
},
Note it also works with npm installed libraries, with the same path conventions i.e non-relative path indicates the library is under node_modules.
I'm a little unsure of what your asking. But if you are just trying to include an external js file in your page, you can just use the script tag in your template and not have to put anything in your mounted function, like this:
<template>
<div id="wrapper">
<div class="main-container">
<Header />
<router-view/>
<Footer/>
</div>
<script src="./assets/js/otherjsfile.js"></script>
</div>
</template>
<script>
import './assets/js/popper.min.js';
// other imports
// ....
export default {
name: 'App',
components : {
Header,
Footer
},
}
</script>
Does this solve your issue?

Create component with CSS selector?

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>