I added a yandex.metrica script (w ecommerce layer) in my index.html
<!-- Yandex.Metrika counter -->
<script type="text/javascript" >
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
m[i].l=1*new Date();
for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
ym(id, "init", {
clickmap:true,
trackLinks:true,
accurateTrackBounce:true,
webvisor:true,
ecommerce: "dataLayer"
});
</script>
<!-- /Yandex.Metrika counter -->
I need to send some data-objects to ecommerce layer like this dataLayer.push({ ecommerce: "someData" }), but i dont understand how to do it correctly inside a react component...
it should work just like other events for YM
window.ym(yaCounterId, "reachGoal", eventName)
window.dataLayer.push({
ecommerce: {
currencyCode: 'RUB',
add: {
products: [
{
id: '43521',
name: 'Yandex bag',
price: 654.32,
brand: 'Yandex / Яndex',
category: 'Accessories/Bags',
quantity: 1,
},
],
},
},
});
just create wrapper function to make it look better
Related
We have a web application that is built using JSP pages. We are trying to migrate UI to React. Migration needs to be incremental as it's a huge application and we cannot migrate it completely in one go.
We are trying to run a poc to see how we will integrate react components in phased manner. We are able to integrate a vanilla react component (a static Select) following this React Docs page.
Problem comes when we started using useState hook. We started to get "Invalid Hook Call Warning".
We created a react app and created components there, it works as react application. We converted JSX components to plain JS using Babel cli (steps as mentioned on the React Doc Page).
Next we loaded React and React-DOM in the application through script tag as suggested on the page, except that we downloaded the script and referred from the file system.
<script src="https://unpkg.com/react#18/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#18/umd/react-dom.production.min.js" crossorigin></script>
<script type="text/javascript" src="<path to component JS>"></script>
When we tried to load the Select component in the target DIV element, we got the hook warning.
I extracted code into a sample html
<html>
<head>
<title>My Page</title>
</head>
<body>
<h1>Try React</h1>
<div id="targetDiv">
<h5>Place content here</h5>
</div>
<script type="text/javascript" src="./react/react.development.js"></script>
<script type="text/javascript" src="./react/react-dom.development.js"></script>
<script type="text/javascript" src="./react/components/core/coreSelect.js"></script>
<script type="text/javascript">
function getSelectOptions() {
const options = [];
options.push({ text: "Select...", value: "" });
options.push({ text: "Arizona", value: "AZ" });
options.push({ text: "Canada", value: "CA" });
options.push({ text: "Europe", value: "EU" });
options.push({ text: "Hawai", value: "HW" });
options.push({ text: "Mexico", value: "MX" });
options.push({ text: "New York", value: "NY" });
return options;
};
let selectArgs = {id:"mySelect", name: "mySelect", options: getSelectOptions(), value: "CA"};
let root = document.getElementById('targetDiv');
console.log({root});
ReactDOM.createRoot(root).render(Select(selectArgs));
</script>
</body>
</html>
Following is the content of coreSelect.js
var _slicedToArray = function () {
function sliceIterator(arr, i) {
var _arr = [];
var _n = true;
var _d = false;
var _e = undefined;
try {
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
_arr.push(_s.value);
if (i && _arr.length === i)
break;
}
} catch (err) {
_d = true; _e = err;
} finally {
try {
if (!_n && _i["return"])
_i["return"]();
} finally {
if (_d) throw _e;
}
}
return _arr;
}
return function (arr, i) {
if (Array.isArray(arr)) { return arr; }
else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); }
else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
};
}();
function Select(_ref4) {
var id = _ref4.id,
name = _ref4.name,
value = _ref4.value,
options = _ref4.options;
var optArray = options ? options : [{ text: 'Select', value: '' }];
console.log("Before useState7", {useState});
var _useState7 = React.useState(options ? options : [{ text: 'Select', value: '' }]),
_useState8 = _slicedToArray(_useState7, 2),
optArray = _useState8[0],
setOptArray = _useState8[1];
console.log("Before useState9");
var _useState9 = React.useState(value),
_useState10 = _slicedToArray(_useState9, 2),
selectedVal = _useState10[0],
setSelectedVal = _useState10[1];
console.log("Before useState11");
var _useState11 = React.useState(""),
_useState12 = _slicedToArray(_useState11, 2),
effectiveClasses = _useState12[0],
setEffectiveClasses = _useState12[1];
var disabled = options && options.length > 0 ? false : true;
var onFocusClass = "active";
function processOnClick() {
if (!effectiveClasses || effectiveClasses.search(onFocusClass) < 0) {
setEffectiveClasses(function (prevClasses) {
var newClasses = (prevClasses ? prevClasses.trim() + " " : "") + onFocusClass;
return newClasses;
});
} else {
setEffectiveClasses(function (prevClasses) {
var newClasses = prevClasses.replace(onFocusClass).trim();
return newClasses;
});
}
}
return React.createElement(
"select",
// { id: id, name: name, className: "active", defaultValue: value, onClick: processOnClick, disabled: disabled },
{ id: id, name: name, className: effectiveClasses, defaultValue: selectedVal, onClick: processOnClick, disabled: disabled },
optArray && optArray.map(function (opt) {
var optValue = opt.value;
var optText = opt.text;
return React.createElement(
"option",
{ key: optValue, value: optValue },
optText
);
})
);
};
I have modified the JS file as generated from babel cli to not use imports/exports. I have verified on browser console that React, ReactDOM and Select component are available.
As an experiment I tried to run the command
ReactDOM.createRoot(document.getElementById('targetDiv')).render(Select({id:"mySelect", name: "mySelect", options: getSelectOptions(), value: "CA"}));
from browser console and I still got the react hook error.
I have been trying to search internet to find a solution but all available posts work with npm and try to resolve issues with react version mismatch, but I could not find any that would discuss problem with react integration with existing non-react applications.
Any help in this regard would be greatly appreciated.
I'm trying to loop through Google Place IDs and gather data from each place and then output the place details into one single JSON file which could later be imported into a map. The importing stage is not a concern but I'm struggling to get the data into the JSON file to begin with. What I have currently is below.
<script src="https://maps.googleapis.com/maps/api/js?sensor=false&libraries=places&key=APIKEY"></script>
var placeid_list = [{
"placeid": 'ChIJryijc9s0K4gRG9aU7SDTXdA',
}, {
"placeid": 'ChIJaZ6Hg4iAhYARxTsHnDFJ9zE',
}, {
"placeid": 'ChIJl64IQXrYzUwR8CVOTRf_h3o',
}, {
"placeid": 'ChIJBTMkuph-zkwR9oEF8Nv3Z0o',
}, {
"placeid": 'ChIJ4QbSBj8IzkwRGi0ILu03_VA',
}, {
"placeid": 'ChIJc2nSALkEdkgRkuoJJBfzkUI',
}, {
"placeid": 'ChIJmzrzi9Y0K4gRgXUc3sTY7RU',
}];
function setPlaces() {
var json = placeid_list;
for (var i = 0, length = json.length; i < length; i++) {
var data = json[i];
createPlace(data);
}
}
function createPlace(data) {
var service = new google.maps.places.PlacesService();
service.getDetails({
placeId: data.placeid
}, function (result, status) {
if (status != google.maps.places.PlacesServiceStatus.OK) {
alert(status);
return;
}
placeResults(data, result);
});
}
function placeResults(data, result) {
console.log(result.name);
}
Currently I'm just trying to output each of the Place names into a console.log but nothing seems to be showing. It doesn't look like I'm getting any errors in the console either so I'm not too sure where I'm going wrong.
Looking at Google's documentation, I'm not sure if I have to make use of
console.log(JSON.stringify(response.data));
Would this help me to put the details of each of the places into one large JSON file? I'm not too sure how I can implement it with what I currently have. I don't have a great deal of expertise in using javascript but I'm hoping that I'm not too far away from a solution. Thanks
You a typo in youre code:
var service = new google.maps.places.PlacesService();
Per the documentation:
Constructor
PlacesService(attrContainer)
Parameters:
attrContainer: HTMLDivElement|Map
Creates a new instance of the PlacesService that renders attributions in the specified container.
The PlacesService constructor has a required argument, either a google.maps.Map object or an HTMLDivElement that can be used to render attributions.
So the referenced line should be:
var service = new google.maps.places.PlacesService(map);
Or:
var service = new google.maps.places.PlacesService(document.getElementById("attributionDiv");
// where attributionDiv is a div that is displayed on your page
Proof of concept fiddle
Outputs:
Alo
Ottawa International Airport
lastminute.com London Eye
Four Seasons Hotel San Francisco
CN Tower
Glenn P Cowan, Chartered Professional Accountant
KB Media Corp
code snippet:
// This example requires the Places library. Include the libraries=places
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places">
function initMap() {
const map = new google.maps.Map(document.getElementById("map"), {
center: {
lat: -33.866,
lng: 151.196
},
zoom: 15,
});
const request = {
placeId: "ChIJN1t_tDeuEmsRUsoyG83frY4",
fields: ["name", "formatted_address", "place_id", "geometry"],
};
const infowindow = new google.maps.InfoWindow();
const service = new google.maps.places.PlacesService(map);
var placeid_list = [{
"placeid": 'ChIJryijc9s0K4gRG9aU7SDTXdA',
}, {
"placeid": 'ChIJaZ6Hg4iAhYARxTsHnDFJ9zE',
}, {
"placeid": 'ChIJl64IQXrYzUwR8CVOTRf_h3o',
}, {
"placeid": 'ChIJBTMkuph-zkwR9oEF8Nv3Z0o',
}, {
"placeid": 'ChIJ4QbSBj8IzkwRGi0ILu03_VA',
}, {
"placeid": 'ChIJc2nSALkEdkgRkuoJJBfzkUI',
}, {
"placeid": 'ChIJmzrzi9Y0K4gRgXUc3sTY7RU',
}];
function setPlaces() {
var json = placeid_list;
for (var i = 0, length = json.length; i < length; i++) {
var data = json[i];
createPlace(data);
}
}
function createPlace(data) {
var service = new google.maps.places.PlacesService(map);
console.log(data);
service.getDetails({
placeId: data.placeid,
fields: ["name", "formatted_address", "place_id", "geometry"],
}, function(result, status) {
if (status != google.maps.places.PlacesServiceStatus.OK) {
alert(status);
return;
}
placeResults(data, result);
});
}
function placeResults(data, result) {
console.log(result.name);
document.getElementById("placeResults").innerHTML += result.name + "<br>";
}
setPlaces();
}
window.initMap = initMap;
/*
* Always set the map height explicitly to define the size of the div element
* that contains the map.
*/
#map {
height: 50%;
}
/*
* Optional: Makes the sample page fill the window.
*/
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
<!DOCTYPE html>
<html>
<head>
<title>Place Details</title>
<script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
<!-- jsFiddle will insert css and js -->
</head>
<body>
<div id="placeResults"></div>
<div id="map"></div>
<!--
The `defer` attribute causes the callback to execute after the full HTML
document has been parsed. For non-blocking uses, avoiding race conditions,
and consistent behavior across browsers, consider loading using Promises
with https://www.npmjs.com/package/#googlemaps/js-api-loader.
-->
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap&libraries=places&v=weekly" defer></script>
</body>
</html>
I am trying to filter an array using a computed property in vue.js. I would like to search on on multiple fields, name, state, tags etc.
My data:
events: [
{
id: 1,
name: 'Name of event',
url: '#',
datetime: '2017-05-10T00:00:00Z',
description: 'The full text of the event',
state: 'VIC',
tags: [
'ordinary',
'advanced'
]
},
{
id: 2,
name: 'Another event',
url: '#',
datetime: '2017-05-12T00:00:00Z',
description: 'The full text of the event',
state: 'VIC',
tags: [
'beginner'
]
},
{
id: 3,
name: 'Great event',
url: '#',
datetime: '2017-05-18T00:00:00Z',
description: 'The full text of the event',
state: 'NSW',
tags: [
'beginner'
]
}
]
},
The following function works as expected, however I cant work out how to have it search the items in 'tags' (commented out).
searchevents: function(){
let result = this.events
if (this.filterValue){
result = result.filter(event =>
event.name.toLowerCase().includes(this.filterValue.toLowerCase()) ||
event.state.toLowerCase().includes(this.filterValue.toLowerCase())
// event.tags.toLowerCase().values().includes(this.filterValue.toLowerCase())
)
}
return result
}
The following returns a blank array, this method works ok when i have done it in angular but not in vue.
searchevents2: function(){
var searchRegex = new RegExp(this.filterValue,'i')
this.events.filter(function(event){
return !self.filterValue || searchRegex.test(event.name) || searchRegex.test(event.state)
})
}
Ideally I would either like to be able to list array items to filter by or just filter by the entire array.
Appreciate any help, first post here so be gentle. I have a lot more experience with Python than Javascript so i may also use incorrect terminology at times.
You weren't too far off.
For your searchEvents filter, you just needed to add the tag filter. Here's how you might do that.
searchevents: function(){
let result = this.events
if (!this.filterValue)
return result
const filterValue = this.filterValue.toLowerCase()
const filter = event =>
event.name.toLowerCase().includes(filterValue) ||
event.state.toLowerCase().includes(filterValue) ||
event.tags.some(tag => tag.toLowerCase().includes(filterValue))
return result.filter(filter)
}
Array.some() is a standard array method that returns true if any element of the array passes your test.
searchevents2: function(){
const searchRegex = new RegExp(this.filterValue,'i')
return this.events.filter(event =>
!this.filterValue || searchRegex.test(event.name) || searchRegex.test(event.state))
}
With searchEvents2 you really only left an errant self in there. Either you needed to set self before you executed the filter, or, as I have done here, turned it into an arrow function.
Example.
const app = new Vue ({
el: '#app',
data: {
search: '',
userList: [
{
id: 1,
name: "Prem"
},
{
id: 1,
name: "Chandu"
},
{
id: 1,
name: "Shravya"
}
]
},
computed: {
filteredAndSorted(){
// function to compare names
function compare(a, b) {
if (a.name < b.name) return -1;
if (a.name > b.name) return 1;
return 0;
}
return this.userList.filter(user => {
return user.name.toLowerCase().includes(this.search.toLowerCase())
}).sort(compare)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<div id="app">
<div class="search-wrapper">
<input type="text" v-model="search" placeholder="Search title.."/>
<label>Search Users:</label>
</div>
<ul>
<li v-for="user in filteredAndSorted">{{user.name}}</li>
</ul>
</div>
I am using KendoUI and angular to implement a very similar scenario as in this example from Telerik website.
http://dojo.telerik.com/AreTa/2
This is what I have
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Kendo UI Snippet</title>
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.2.714/styles/kendo.common.min.css"/>
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.2.714/styles/kendo.rtl.min.css"/>
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.2.714/styles/kendo.silver.min.css"/>
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.2.714/styles/kendo.mobile.all.min.css"/>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://kendo.cdn.telerik.com/2016.2.714/js/kendo.all.min.js"></script>
</head>
<body>
<style>html { font: 12px sans-serif; }</style>
<div id="grid"></div>
<script>
var sampleData = [
{ProductName: "Sample Name", Description: "Sample Description"}
];
// custom logic start
var sampleDataNextID = sampleData.length + 1;
function getIndexByName(name) {
var idx,
l = sampleData.length;
for (var j=0; j < l; j++) {
if (sampleData[j].getIndexById == name) {
return j;
}
}
return null;
}
// custom logic end
$(document).ready(function () {
var dataSource = new kendo.data.DataSource({
transport: {
read: function (e) {
// on success
e.success(sampleData);
// on failure
//e.error("XHR response", "status code", "error message");
},
create: function (e) {
// assign an ID to the new item
//e.data.ProductName = e.data;
// save data item to the original datasource
sampleData.push(e.data);
// on success
e.success(e.data);
// on failure
//e.error("XHR response", "status code", "error message");
},
update: function (e) {
// locate item in original datasource and update it
sampleData[getIndexByName(e.data.ProductName)] = e.data;
// on success
e.success();
// on failure
//e.error("XHR response", "status code", "error message");
},
destroy: function (e) {
// locate item in original datasource and remove it
sampleData.splice(getIndexByName(e.data.ProductName), 1);
alert("Delete Success"+e.data.ProductName) ;
// on success
e.success();
// on failure
//e.error("XHR response", "status code", "error message");
}
},
error: function (e) {
// handle data operation error
alert("Status: " + e.status + "; Error message: " + e.errorThrown);
},
pageSize: 10,
batch: false,
schema: {
model: {
id: "ProductName",
fields: {
ProductName: { validation: { required: true } },
Description: { type: "text"}
}
}
}
});
$("#grid").kendoGrid({
dataSource: dataSource,
pageable: true,
toolbar: ["create"],
columns: [
{ field: "ProductName", title: "Mobile Phone" },
{ field: "Description", width: "120px" },
{ command: ["destroy"], title: "Action;", width: "200px" }
],
editable: "inline"
});
});
</script>
</body>
</html>
And it works, the way it is on Telerik website
The change I want to do is that upon "create", I want the ProductName field be a drop down, instead of textfield, populated with values I have in another json (not sampleData). That has a value (productName) and Description - description
Also, the Description field is not to be typeable, but rather "obtained" from the description of the selected in dropdown.
Can anyone help ?
Use a custom editor for the ProductName field:
http://docs.telerik.com/kendo-ui/api/javascript/ui/grid#configuration-columns.editor
http://demos.telerik.com/kendo-ui/grid/editing-custom
Attach a change handler to the DropDownList and set() the corresponding value to the Description field of the data item (which is a Kendo UI Model instance that you already have from the editor function's arguments).
http://docs.telerik.com/kendo-ui/api/javascript/ui/dropdownlist#events-change
http://docs.telerik.com/kendo-ui/api/javascript/data/observableobject#methods-set
You will also need to prevent direct editing of the Description field. This can be easily achieved if you use a custom "editor" for this field, which simply outputs the current value in a <span> element.
I am new to angularjs and I would like to understand what the directives do but I can't find a tutorial with different example by complexity and I was curios if I could move the following code in a directive.
This is my javascript file(controller.js):
function TestCtrl(){
var json = {
id:"judge_id",
name:"Test",
children: [ {
id:"filter_1",
name:'Filter 1',
children:[{id:"case_1",name:"CaseA",children:[]},{id:"case_2",name:"CaseB",children:[]},{id:"case_3",name:"CaseC",children:[]}]
},
{
id:"filter_2",
name:'Filter 2',
children:[]
},
{
id:"filter_3",
name:'Filter 3',
children:[]
},
{
id:"filter_4",
name:'Filter 4',
children:[]
},
{
id:"filter_5",
name:'Filter 5',
children:[]
},
{
id:"filter_6",
name:'Filter 6',
children:[]
}
]
};
var rgraph = new $jit.RGraph({
//Where to append the visualization
injectInto: 'infovis',
background: {
CanvasStyles: {
strokeStyle: '#555'
}
},
//Add navigation capabilities:
//zooming by scrolling and panning.
Navigation: {
enable: true,
panning: true,
zooming: 10
},
//Set Node and Edge styles.
Node: {
color: '#ddeeff'
},
Edge: {
color: '#C17878',
lineWidth:1.5
},
//Add the name of the node in the correponding label
//and a click handler to move the graph.
//This method is called once, on label creation.
onCreateLabel: function(domElement, node){
domElement.innerHTML = node.name;
domElement.onclick = function(){
rgraph.onClick(node.id, {
onComplete: function() {
Log.write("done");
}
});
};
},
//Change some label dom properties.
//This method is called each time a label is plotted.
onPlaceLabel: function(domElement, node){
var style = domElement.style;
style.display = '';
style.cursor = 'pointer';
if (node._depth <= 1) {
style.fontSize = "0.8em";
style.color = "#ccc";
} else if(node._depth == 2){
style.fontSize = "0.7em";
style.color = "#494949";
} else {
style.display = 'none';
}
var left = parseInt(style.left);
var w = domElement.offsetWidth;
style.left = (left - w / 2) + 'px';
}
});
//load JSON data
rgraph.loadJSON(json);
//trigger small animation
rgraph.graph.eachNode(function(n) {
var pos = n.getPos();
pos.setc(-200, -200);
});
rgraph.compute('end');
rgraph.fx.animate({
modes:['polar'],
duration: 2000
});
}
ANd my html file is like this:
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<script src="http://philogb.github.io/jit/static/v20/Jit/jit-yc.js"></script>
<script src="..js/controller.js"></script>
<link type="text/css" href="../base.css" rel="stylesheet" />
<title></title>
</head>
<body onload="TestCtrl();">
<div id="center-container">
<div id="infovis"></div>
</div>
</body>
</html>
Thanks
Sabbu