How to add AggregateRatingin in GTM using DOM element Variables? - schema

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

Related

Adding and reading json data stored in vuex

I have a vuex store and i am adding some josn data and this is the format.
[
{
"id":1,
"firstname": "toto",
"lastname": "titi"
},
{ "id":2,
"firstname": "one",
"lastname": "two"
}
]
I am adding the data on an on click action and this is the action method
addLink: function() {
var dt = '[{"id":1,"firstname":"xx","lastname": "yy"},{"id":2,"firstname": "one","lastname": "two"}]';
this.ADD_LINK(dt)
this.newLink = '';
},
The data is getting added to the store and i can access it like this
computed: {
users(){
return this.countLinks;
}
}
I can display the data this way {{users}} and this is getting displayed. This is because i clicked twice and added the json twice.
[ "[{\"id\":1,\"firstname\":\"xx\",\"lastname\": \"yy\"},{\"id\":2,\"firstname\": \"one\",\"lastname\": \"two\"}]", "[{\"id\":1,\"firstname\":\"xx\",\"lastname\": \"yy\"},{\"id\":2,\"firstname\": \"one\",\"lastname\": \"two\"}]" ]
However, when i try to use v-for
<ul id="users">
<li v-for="user in users" :key="user.id">
{{ users.firstname}}
</li>
</ul>
i cannot display any data and i have no error. How can i display the data saved in vuex?.
You can create a computed property that returns the objects in one list parsed as JSON:
new Vue({
el:"#app",
data: () => ({
users: [ "[{\"id\":1,\"firstname\":\"xx\",\"lastname\": \"yy\"},{\"id\":2,\"firstname\": \"one\",\"lastname\": \"two\"}]", "[{\"id\":1,\"firstname\":\"xx\",\"lastname\": \"yy\"},{\"id\":2,\"firstname\": \"one\",\"lastname\": \"two\"}]" ]
}),
computed: {
usersList: function() {
return this.users.flatMap(userList => JSON.parse(userList));
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul id="users">
<li v-for="(user, index) in usersList" :key="index">
{{ user.firstname}}
</li>
</ul>
</div>
Note: Since ids are not unique in your example, you can use an index in v-for as the key. Also, to show the first name, you need to use the user object.
Another solution: Parse dt in the store and use Array#concat to add the elements as objects to the initial list:
let countLinks = [
{ "id":1, "firstname": "toto", "lastname": "titi" },
{ "id":2, "firstname": "one", "lastname": "two" }
];
function ADD_LINK(dt) {
countLinks = countLinks.concat(JSON.parse(dt));
}
const dt = '[{"id":1,"firstname":"xx","lastname": "yy"},{"id":2,"firstname": "one","lastname": "two"}]';
ADD_LINK(dt);
console.log(countLinks);
you have to store the data as is, rather than converting into string
addLink: function() {
var dt = [
{
"id":1,
"firstname": "xx",
"lastname": "yy"
},
{
"id":2,
"firstname": "one",
"lastname": "two"
}
];
// remove the single quote from the above array
this.ADD_LINK(dt)
this.newLink = '';
},
In case you are getting the var dt from external source then you should consider converting into valid js json format using this:
addLink: function() {
var dt = '[{"id":1,"firstname":"xx","lastname": "yy"},{"id":2,"firstname": "one","lastname": "two"}]';
// parse it to json format
var parsedDt = JSON.parse(dt);
// add the `parsedDt`
this.ADD_LINK(parsedDt)
this.newLink = '';
},

Add dynamically data-bound text in Vue.js

My case must be weird, but I have a good for it.
Here's my situation:
I have a Vue app that renders a form based on a json.
For example, the JSON:
{
"fields": [{
"name": "firstName",
"title": "Name"
}, {
"name": "lastName",
"title": "Last Name"
}, {
"title": "Hello {{ firstName }}!"
}]
}
From that json, the final render has to be:
<input type="text" name="firstName" v-model="firstName" />
<input type="text" name="lastName" v-model="lastName" />
<p>Hello {{ firstName }}</p>
I'm able to render all of that, except for the <p> which is rendered as raw {{ firstName }} and not data-bound/reactive.
My question is:
How do I insert dynamic templates (can come from a Rest API) into the component, and make them have the full power of the mustache expressions.
The component will have something like
{...firstName field...}
<dynamic template will be added here and update whenever firstName changes>
Please let me know if I'm not too clear on this issue
Thank you!!!
Is this the sort of thing you're trying to do? I've created a dynamic component whose template is generated from a JSON string which is editable.
new Vue({
el: '#app',
data: {
componentData: {
firstName: 'Jason',
lastName: 'Bourne',
},
jsonString: `
{
"fields": [{
"name": "firstName",
"title": "Name"
}, {
"name": "lastName",
"title": "Last Name"
}, {
"title": "Hello {{ firstName }}!"
}]
}`
},
computed: {
template() {
const json = JSON.parse(this.jsonString);
return json.fields.map((s) => {
if ('name' in s) {
return `<input type="text" name="${s.name}" v-model="${s.name}">`;
}
return s.title;
}).join('\n');
},
componentSpec() {
return {
template: `<div>${this.template}</div>`,
data: () => this.componentData
};
}
}
});
<script src="https://unpkg.com/vue#latest/dist/vue.js"></script>
<div id="app">
<textarea rows="16" cols="40" v-model.lazy="jsonString">
</textarea>
<component :is="componentSpec"></component>
</div>

Not able to access data variable in script but can in html

I have populated a data variable with an array, and can access its contents by using a v-for in the html, but I can't access any of the data in the variable within the script, and I don't know why.
var result = [{
"CatalogName": "Retro Doors",
"ItemName": "French Doors",
"ItemListPrice": "$461.00",
"ItemType": "Oak",
"ItemFeatures": [{
"Features": "Door Quantity",
"QTY": 2
},
{
"Features": "Door Hinges",
"QTY": 4
},
{
"Features": "Door Knobs",
"QTY": 1
},
{
"Features": "Door Looks",
"QTY": 1
},
{
"Features": "Glass Panes",
"QTY": 2
}
]
}];
new Vue({
el: '#app',
beforeCreate: function() {
console.log("Before Created");
},
created: function() {
console.log("Created");
this.GetItemsList();
},
beforeMount: function() {
console.log("Before Mount");
},
data: {
itemPriceList: []
},
methods: {
GetItemsList() {
this.itemPriceList = result;
}
},
mounted: function() {
console.log("Mounted");
console.log(this.ItemPriceList);
}
});
<script src="https://code.jquery.com/jquery-3.3.1.js" integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=" crossorigin="anonymous"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<div id="app">
{{ itemPriceList[0].CatalogName }}
<div v-for="item in itemPriceList">
{{ item.ItemName }}
<div v-for="items in item.ItemFeatures">
{{ items.Features }} : {{ items.QTY }}
</div>
</div>
</div>
You have a typo in a variable name inside mounted hook - used with capital I.
In data: itemPriceList
In mounted hook: this.ItemPriceList
Should be the same as defined inside data property.

Vue.js binding attribute with v-model [duplicate]

I have form and select components.
In fact things are simple: I need two binding model.
The parent component:
Vue.component('some-form', {
template: '#some-form',
data: function() {
return {
countryNameParent: ''
}
}
});
The child component with items:
Vue.component('countries', {
template: '#countries',
data: function () {
return {
items: {
"0": {
"id": 3,
"name": "Afghanistan"
},
"1": {
"id": 4,
"name": "Afghanistan2"
},
"2": {
"id": 5,
"name": "Afghanistan3"
}
},
countryName: ''
}
},
props: ['countryNameParent'],
created: function() {
var that = this;
this.countryName = this.countryNameParent;
},
methods: {
onChange: function (e) {
this.countryNameParent = this.countryName;
}
}
});
I'm using v-model to incorporate components above.
Templates like this:
<template id="some-form">
{{ countryNameParent }}
<countries v-model="countryNameParent"></countries>
</template>
<template id="countries">
<label for="">
<select name="name" #change="onChange" v-model="countryName" id="">
<option value="0">Select the country!</option>
<option v-for="item in items" v-bind:value="item.name">{{ item.name }}</option>
</select>
</label>
</template>
My target is getting data in parent component to send it to server (real form is much bigger), however I can't get the value of the countryName in countryNameParent. Moreover, Parent should setting data in successor if not empty.
Here you go link where I've been attempting to do it several ways (see commented part of it).
I know that I need to use $emit to set data correctly, I've even implemented model where I get image as base64 to send it by dint of the same form, hence I think solution is approaching!
Also: reference where I've built sample with image.
Here is your countries component updated to support v-model.
Vue.component('countries', {
template: `
<label for="">
<select v-model="countryName">
<option value="0">Select the country!</option>
<option v-for="item in items" v-bind:value="item.name">{{ item.name }}</option>
</select>
</label>
`,
data: function () {
return {
items: {
"0": {
"id": 3,
"name": "Afghanistan"
},
"1": {
"id": 4,
"name": "Afghanistan2"
},
"2": {
"id": 5,
"name": "Afghanistan3"
}
},
}
},
props: ['value'],
computed:{
countryName: {
get() { return this.value },
set(v) { this.$emit("input", v) }
}
},
});
v-model is just sugar for setting a value property and listening to the input event. So to support it in any component, the component needs to accept a value property, and emit an input event. Which property and event are used is configurable (documented here).

Plotting multiple Points from html spans in ArcGIS

I'm trying to plot multiple Points on an ArcGIS map using span#longitude and span#latitude in the HTML. I can get the very first point to plot, but not any subsequent points.
I'm new to ArcGIS, and my javascript knowledge is limited. Any help is appreciated!
<script>
var map, agraphicsLayer, symbol;
function addPointtoMap(x, y) {
require([
"esri/geometry/Point",
"esri/graphic",
"dojo/domReady!"],
function(Point, Graphic) {
var pt = new Point(x, y);
map.centerAt(pt);
agraphicsLayer.add(new Graphic(pt, symbol));
});
}
(function($) {
if($("div#mapDiv").length) {
$.getScript( "http://js.arcgis.com/3.14/" )
.done(function( script, textStatus ) {
require(["esri/map",
"esri/symbols/SimpleMarkerSymbol",
"esri/geometry/Point",
"esri/graphic",
"esri/Color",
"esri/layers/GraphicsLayer",
"dojo/domReady!"
],
function(
Map,
SimpleMarkerSymbol,
Point,
Graphic,
Color,
GraphicsLayer) {
map = new Map("mapDiv", {
center: [-56.049, 32.485],
zoom: 5,
basemap: "topo",
logo: false
});
map.on("load", function() {
map.disableScrollWheelZoom();
});
agraphicsLayer = new GraphicsLayer();
map.addLayer(agraphicsLayer);
symbol = new SimpleMarkerSymbol();
symbol.setColor(new Color("#00ADA1"));
var pt = new Point($("span#longitude").html(), $("span#latitude").html());
map.centerAt(pt);
agraphicsLayer.add(new Graphic(pt, symbol));
});
})
.fail(function( jqxhr, settings, exception ) { });
}
</script>
<div id="mapDiv"></div>
<span id="longitude">37.82</span>
<span id="latitude">-2.28</span>
<span id="longitude">34.82</span>
<span id="latitude">1.36</span>
<span id="longitude">34.31</span>
<span id="latitude">-0.67</span>
<span id="longitude">40.19</span>
<span id="latitude">.10</span>
in both the HTML 4.01 and HTML 5 specifications the "id" attribute must be unique among all the IDs in the document so
$("span#longitude").html()
is only ever going to give you the first longitude (or at least it's not going to give you what you want which is to loop through all the lat/longs)
There's are a lot of ways to accomplish your goal. One way is to store the lat/longs in your javascript instead of in the HTML.
you would do that like so
<script>
var map, agraphicsLayer, symbol,
data = {"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [37.82, -2.28]
}},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [34.82, 1.36]
}},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [34.31, -0.67]
}},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [40.19, 0.10]
}}]
};
...code snipped for brevity
//here you want to loop through the points
data.features.forEach(function(feature){
var pt = new Point(feature.geometry.coordinates, map.spatialReference);
agraphicsLayer.add(new Graphic(pt, symbol));
})
</script>
if you really want to store the data in spans like you are now then you need to change the "id" attribute to a "class" attribute and then wrap the lat/long spans in some grouping element like a div or another span
<div class="coordinate">
<span class="longitude">37.82</span>
<span class="latitude">-2.28</span>
</div>
and then in the javascript do something like this
$(".coordinate").each(function(){
//this refers to each "coordinate" div as we loop through them
var long = $(this).find(".longitude").html()
var lat = $(this).find(".lattitude").html()
var pt = new Point(long, lat);
//etc
})