When trying to add a json-ld script tag to a section that gets teleported to the HEAD, the Vue 3 compiler fails with this error:
VueCompilerError: Tags with side effect (<script> and <style>) are ignored in client component templates.
Template:
<template>
<teleport to="head">
<script type="application/ld+json">
{
"#context": "https://schema.org",
"#type": "WebSite",
"url": "https://www.example.com/",
"potentialAction": {
"#type": "SearchAction",
"target": "https://query.example.com/search?q={search_term_string}",
"query-input": "required name=search_term_string"
}
}
</script>
</teleport>
<div>
Hello world!
</div>
</template>
How can I add this json-ld tag without installing additional dependencies?
A workaround is to use Vue's built-in component (i.e., <component :is="'script'">) instead of <script>:
<template>
<teleport to="head">
<component :is="'script'" type="application/ld+json">
{
"#context": "https://schema.org",
"#type": "WebSite",
"url": "https://www.example.com/",
"potentialAction": {
"#type": "SearchAction",
"target": "https://query.example.com/search?q={search_term_string}",
"query-input": "required name=search_term_string"
}
}
</component>
</teleport>
<div>
Hello world!
</div>
</template>
demo
Related
I downloaded the DataTable component vue3-easy-data-table. Then I created a custom component where I define the theme for the table.
Since the easy-data-table uses slots to operate on the table items, how can I redirect my template tags to the table instead of my custom component?
<script>
export default {
setup() {
const themeColor = getComputedStyle(document.documentElement).getPropertyValue('--primary');
return { themeColor }
}
}
</script>
<template>
<DataTable table-class-name="table-theme" :theme-color="themeColor" alternating>
<template #expand="item">
<slot name="expand" v-bind="item"></slot>
</template>
</DataTable>
</template>
<style lang="scss" scoped>
.table-theme {
width: 100%;
height: 100%;
overflow: hidden;
}
</style>
This is my custom component. At the moment I manually created a copy template for the expand function and it works alright, but not only it looks ugly and redundant, it also won't work to access specific items.
Do you have a solution?
I found a solution. The slots object that you get in your setup function will contain the "parent requested slot" even if they are not defined in the template.
Therefore you can easily pass the slots names to the template, iterate through them and automatically generate the needed slots.
<script>
export default {
setup(props, { slots }) {
const themeColor = getComputedStyle(document.documentElement).getPropertyValue('--primary');
const slotNames = Object.keys(slots)
return { themeColor, slotNames }
}
}
</script>
<template>
<DataTable table-class-name="table-theme" :theme-color="themeColor" alternating>
<template v-slot:[slot]="model" v-for="slot in slotNames">
<slot :name="slot" v-bind="model"></slot>
</template>
</DataTable>
</template>
You don't really need to wrap the table with a custom component.
But unfortunately the vue3-easy-data-table does not update with changing the themeColor.
So, the quick and dirty solution is to force the table recreate, by destroying it using v-if.
Here is the playground (check it in the full page)
const App = {
components: {
EasyDataTable: window['vue3-easy-data-table'],
},
data () {
return {
themeColor: "#f48225",
headers:[
{ text: "Name", value: "name" },
{ text: "Age", value: "age", sortable: true }
],
items: [
{ "name": "Curry", "height": 178, "weight": 77, "age": 20 },
{ "name": "James", "height": 180, "weight": 75, "age": 21 },
{ "name": "Jordan", "height": 181, "weight": 73, "age": 22 }
],
}
},
methods: {
resetTable() {
this.themeColor = null;
}
}
};
Vue.createApp(App).mount('#app');
<div id="app">
Theme Color: {{themeColor}}<br /><br />
<input type="radio" v-model="themeColor" value="#f48225" #input="resetTable"/> #f48225
<input type="radio" v-model="themeColor" value="#123456" #input="resetTable" /> #123456 <br /><br />
<easy-data-table v-if="themeColor != null"
:headers="headers"
:items="items"
:theme-color="themeColor"
buttons-pagination
alternating
/>
</div>
<link href="https://unpkg.com/vue3-easy-data-table/dist/style.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/vue#3.2.1/dist/vue.global.js"></script>
<script src="https://unpkg.com/vue3-easy-data-table"></script>
Where I can found the default schema code in shopify?
<script type="application/ld+json">
{
"#context": "http://schema.org/",
"#type": "AggregateRating",
"reviewCount": "2",
"ratingValue": "5.0",
"itemReviewed": {
"#type" : "Product",
"name" : "Cuisinart Automatic Bread Maker",
"offers": {
"#type": "AggregateOffer",
"lowPrice": "125.0",
"highPrice": "125.0",
"priceCurrency": "CAD"
}
}
}
</script>
This code actually visible after html tag. Need help. Screenshot attached
Currently the above mentioned schema not visible in latest version of structured data. Checked and confirmed.
How would I read deep JSON data nested deep inside a file? I've tried different methods and can't seem to get this to work.
<template>
<div>
<div v-for="edu in info" :key="edu">
<div>{{ edu.section.title }}</div> // this is what im trying to get to work
</div>
<div class="card container">
{{ info }}
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
info: null
}
},
mounted() {
axios
.get('./calculus.json') // Data Below
.then(response => (this.info = response.data.edu))
.catch(error => console.log(error))
}
}
</script>
My JSON looks like this:
{
"edu": {
"1": {
"title": "Title One",
"subtitle": "Subtitle One",
"description": "Description One",
"section": {
"1": {
"title": "Section One Title",
"content": "Section One Content"
}
}
},
"2": {
"title": "Title Two",
"subtitle": "Subtitle Two",
"description": "Description Two",
"section": {
"1": {
"title": "Section One Title",
"content": "Section One Content"
}
}
}
}
}
How can I use vue-for and get the data inside the section to get it to display under the title? For example: title, section>title, section>subtitle, etc.
Given each section is also an object with weird numeric keys, you can iterate them in the same way you do info.
I would also advise you to use identifiable values instead of the entire edu object in your :key bindings.
<div v-for="(edu, eduId) in info" :key="eduId">
<div v-for="(section, sectionId) in edu.section" :key="sectionId">
{{ section.title }}
</div>
</div>
If possible, I would alter the format of your JSON data to use actual arrays instead of objects with numeric keys.
One way to browse your object deeply is to cumulate v-for on your object (and children) entries.
ie:
<div v-for="([category, books], catkey) in Object.entries(info)" :key="`category-${catkey}`">
<div>{{ category }} :</div>
<div v-for="([num, book], numkey) in Object.entries(books)" :key=`book-${catkey}-${numkey}`>
<div v-for="([field, value], valkey) in Object.entries(book)" :key=`field-${catkey}-${numkey}-${valkey}`>
{{ field }} : {{ value }}
</div>
</div>
</div>
If you find it too verbose, you may try to flatten your computed data to have the following structure:
[
{
"category": "edu",
"id": "1",
"title": "Title One",
"subtitle": "Subtitle One",
"description": "Description One",
"section": {
"1": {
"title": "Section One Title",
"content": "Section One Content"
}
}
}
]
I cannot get values in my template while i have the data, here is my code:
code
<template>
<div>
{{project}}
</div>
</template>
<script>
export default {
props: ['id'],
data() {
return{
project:[]
}
},
created(){
this.fetchProject();
},
methods:{
fetchProject(){
var self = this;
axios.post('/showprojectvue/' +self.id).then(res => {
self.project.push(res.data);
});
},
}
}
</script>
output
[ { "id": 33, "user_id": 2, "title": "kjfsdjowhd", "slug": "kjfsdjowhd", "body": "<p>khweihgtfihrwhtg</p>", "attachment": null, "projectclass": "sthrh", "budget": 36346, "deadline": "2018-08-24", "published": "n", "runing": "n", "payment_verified": "n", "created_at": "2018-08-05 03:43:16", "updated_at": "2018-08-05 03:43:16" } ]
i cannot use any of {{project.title}} or {{project['title']}}
How can I get out my data?
As your data is an array you need to use v-for to iterate over it.
<template>
<div v-for="obj in project">
{{obj.title}}
</div>
</template>
Example,
function callMe(){
var vm = new Vue({
el : '#root',
data : {
project : []
},
methods: {
ajaxCall(){
this.project=[{ "id": 33, "user_id": 2, "title": "kjfsdjowhd", "slug": "kjfsdjowhd", "body": "<p>khweihgtfihrwhtg</p>", "attachment": null, "projectclass": "sthrh", "budget": 36346, "deadline": "2018-08-24", "published": "n", "runing": "n", "payment_verified": "n", "created_at": "2018-08-05 03:43:16", "updated_at": "2018-08-05 03:43:16" }];
}
},
})
}
callMe()
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.11/dist/vue.js"></script>
<div id='root'>
<button type="button" #click="ajaxCall">Click ME</button>
<div v-for="obj in project">
Title: {{obj.title}}
<p>
Object:{{obj}}
</p>
</div>
</div>
The Product Schema code that i am using as a custom HTML tag for implementing product schema using DOM variables in GTM..
<script>
var jsonData = {
"#context": "http://schema.org",
"#type": "Product",
"name": {{productName}},
"image": {{productImg}},
"url": {{Page URL}},
"aggregateRating": {
"#type": "AggregateRating",
"ratingValue": {{avgRating}},
"reviewCount": {{ratingsCount}},
}
}
var script = document.createElement('script');
script.type = 'application/ld+json';
script.text = JSON.stringify(jsonData);
$("head").append(script);
</script>
how can i configure the DOM element variable for AggregateRating Variables (avgRating, ratingsCount) in GTM.
here is the Markup
<div class="woocommerce-product-rating">
<div class="star-rating">
<span style="width:100%">
<strong class="rating">5.00</strong> out of <span>5</span> based on <span class="rating">1</span> customer rating </span>
</div>
(<span class="count">1</span> customer review) </div>
You need to create two variables in GTM
1) Go to Variables->User-Defined Variables->New->Custom Javascript
2) Create variable with name ProductAvgRating and JS code:
function () {
try {
return parseFloat(document.querySelector('.woocommerce-product-rating strong.rating').innerText);
}
catch(e) {return 0;}
}
2) Create variable with name ProductRatingsCount and JS code:
function () {
try {
return parseInt(document.querySelector('.woocommerce-product-rating span.rating').innerText);
}
catch(e) {return 0;}
}
And then change your html tag like that:
<script>
var jsonData = {
"#context": "http://schema.org",
"#type": "Product",
"name": {{productName}},
"image": {{productImg}},
"url": {{Page URL}},
"aggregateRating": {
"#type": "AggregateRating",
"ratingValue": {{ProductAvgRating}},
"reviewCount": {{ProductRatingsCount}},
}
}
var script = document.createElement('script');
script.type = 'application/ld+json';
script.text = JSON.stringify(jsonData);
$("head").append(script);
</script>
P.S. You didn't ask about productName and productImg variables, i guess you already have it