How can I output Google Places details into a JSON file? - loops

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>

Related

Getting Invalid Hook Call Warning when trying to integrate React with exiting web application

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.

Why print functionality in javascript is not working in edge, but works in chrome

Hi I have the below code to achieve print functionality . The code works fine in Chrome, but doesnt work in Edge. Getting the follwing error in edge.I am building the layout in javascript in generatePDF function.
Below is my JS code:
$scope.printRepayment = function() {
var documentDefinition = generatePDF(); pdfMake.createPdf(documentDefinition).print();
}
var generatePDF = function() {
var repayments = $scope.repayments;
var rows = [
[
{ text: "Payment No", style: "tableHeader" },
{ text: "Installment", style: "tableHeader" },
]
];
for (var i = 0; i < repayments.length; i++) {
rows.push([
{ text: i + 1, style: "tablefirst" },
{
text:
"AED " +
numberWithCommas(
parseFloat(repayments[i].installment).toFixed(2)
),
style: "tableOther"
},
]);
}
return {
content: [
{ text: "Repayment schedule", style: "subheader" },
{
style: "tableExample",
table: {
widths: ["*", "*", "*", "*", "*"],
body: rows
},
layout: {
vLineColor: function(i, node) {
return "#ECF3FE";
}
}
}
],
styles: {
tabletop: {
margin: [10, 0, 0, 10]
},
tabletopHeader: {
fontSize: 16,
bold: true
}
}
};
};
With refer to this article, we can see that the pdfMake print() method doesn't support Edge browser. So, as a workaround, I think you could create a web page which contains the display the pdf content, then, calling the window.print(); method to print this page. Otherwise, as Master Po said, you could download the pdf file first, then, print the pdf content.
Thanks a ton #Zhi Lv - MSFT, for giving the solution in plain english and then after having discovered how to do, this is what worked for me
var pdf = pdfMake.createPdf(doc);
pdf.getBuffer(function (buffer) {
var file = new Blob([buffer], {type: 'application/pdf'});
var fileURL = URL.createObjectURL(file);
window.location.href = fileURL;
}); // {autoPrint: true});
the pdf file generated is converted into a blob and the url of that file is then opened up as a new window, shows the pdf doc and can be printed
Yet not sure how autoPrint works, will need to work a bit more

How to split my JSON object in angularJS

I am trying to create pagination for my table that lists the objects returned from my DB as an object. My data structure will look something like:
$scope.myJSONObj = {
app1: {
id: 1,
appName: "appIntegrated1",
status: "Pending"
},
app2: {
id: 2,
appName: "appIntegrated2",
status: "Pending"
},
app3: {
id: 3,
appName: "appIntegrated3",
status: "Completed"
},
app4: {
id: 4,
appName: "appIntegrated4",
status: "Pending"
},
app5: {
id: 5,
appName: "appIntegrated5",
status: "Pending"
},
app6: {
id: 6,
appName: "appIntegrated6",
status: "Pending"
},
app7: {
id: 7,
appName: "appIntegrated7",
status: "Pending"
},
app8: {
id: 8,
appName: "appIntegrated8",
status: "Pending"
},
app9: {
id: 9,
appName: "appIntegrated9",
status: "Pending"
},
app10: {
id: 10,
appName: "appIntegrated10",
status: "Pending"
}
I am trying to split my structure in half, and display the first five results. I have a prev/next button, and when I click next, it should display the next 5 results (in this case the last 5). However, for everything to work, I need to be able to split my object, and so far every method I've researched involves arrays, and objects requiring some hack. I was wondering if I was missing something, or I have to create a solution to work with?
In pure JavaScript :
function getEntries(from, to) {
var entries = [];
for(var key in myJSONObj) {
// extract index after `app`
// var index = key.substring(3);
// Better way : extract index using regular expression, so it will match `something1`, `foo2`, `dummy3`
var index = parseInt(key.replace( /^\D+/g, ''));
if(index >= from && index <= to) {
entries.push(myJSONObj[key]);
}
}
return entries;
}
console.log(getEntries(0, 5));
Try _.chunk
https://lodash.com/docs/4.17.4#chunk
$scope.pages = _.chunk($scope.myJSONObj,5);
$scope.getPage = function( pageIndex ){
return $scope.pages[pageIndex];
}
It's untested - but I wrote a chunk method for you in vanilla JS since you can't use lodash.
function chunk(obj, chunkSize) {
var resultArray = [];
var resultArrayCurrentIndex = 0;
for (var key in obj) {
var item = obj[key];
if (resultArray[resultArrayCurrentIndex].length <= chunkSize) {
if (!resultArray[resultArrayCurrentIndex]) {
resultArray[resultArrayCurrentIndex] = [item];
} else {
resultArray[resultArrayCurrentIndex].push(item)
}
} else {
resultArrayCurrentIndex++
resultArray[resultArrayCurrentIndex] = [item];
}
}
return resultArray;
}
Then you can access it like this:
$scope.pages = chunk(yourObject, 5);
$scope.getPage = function(index){
return $scope.pages[index];
}
EDIT - changed it to accept an obj.
Used Object.keys, Array.prototype.slice and Array.prototype.reduce to solve your issue. Hope this helps
angular.module('app',[])
.controller('TestCtrl', function($scope){
$scope.myJSONObj = {"app1":{"id":1,"appName":"appIntegrated1","status":"Pending"},"app2":{"id":2,"appName":"appIntegrated2","status":"Pending"},"app3":{"id":3,"appName":"appIntegrated3","status":"Completed"},"app4":{"id":4,"appName":"appIntegrated4","status":"Pending"},"app5":{"id":5,"appName":"appIntegrated5","status":"Pending"},"app6":{"id":6,"appName":"appIntegrated6","status":"Pending"},"app7":{"id":7,"appName":"appIntegrated7","status":"Pending"},"app8":{"id":8,"appName":"appIntegrated8","status":"Pending"},"app9":{"id":9,"appName":"appIntegrated9","status":"Pending"},"app10":{"id":10,"appName":"appIntegrated10","status":"Pending"}};
$scope.currentPage = 0;
$scope.pageSize = 5;
$scope.totalPage = Math.ceil( Object.keys($scope.myJSONObj).length/$scope.pageSize);
//pageNumber starts from 0 here
$scope.goToPage = function(pageNumber) {
pageNumber = pageNumber>=0?pageNumber:0;
var from = pageNumber*$scope.pageSize;
var to = from + $scope.pageSize;
return Object.keys($scope.myJSONObj).slice(from,to).reduce(function(a,b){
a[b] = $scope.myJSONObj[b];
return a;
},{});
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="TestCtrl">
<button ng-disabled="currentPage===0" ng-click="currentPage = currentPage - 1">prev</button>
<button ng-disabled="currentPage===totalPage-1" ng-click="currentPage = currentPage + 1">next</button>
<b>Page: {{currentPage+1}}/{{totalPage}}</b>
<pre>{{goToPage(currentPage) | json}}</pre>
</div>

How to get state and city using placeid in Google Map Api in Angularjs

How to get state and city using place_id. I want to get state and city using place_id. t
Please see the following link Google_map, I want to get state and city of following place_id "place_id" : "ChIJLfyY2E4UrjsRVq4AjI7zgRY",
Google Place Details response contains address_components[] field which represents an array of separate address components used to compose a given address, you could extract city and state from this property.
According to Address Component Types:
administrative_area_level_1 - indicates a first-order civil entity below the country level. Within the United States, these
administrative levels are states. Not all nations exhibit these
administrative levels.
locality - indicates an incorporated city or town political entity.
Example
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 10
});
var infowindow = new google.maps.InfoWindow();
var service = new google.maps.places.PlacesService(map);
service.getDetails({
placeId: 'ChIJLfyY2E4UrjsRVq4AjI7zgRY'
}, function (place, status) {
if (status === google.maps.places.PlacesServiceStatus.OK) {
map.setCenter(place.geometry.location);
/*var marker = new google.maps.Marker({
map: map,
position: place.geometry.location
});*/
showPlaceDetails(map, place, infowindow);
}
});
}
function showPlaceDetails(map, place, infowindow) {
//parse address details
var info = '';
place.address_components.forEach(function (item) {
if (item.types.indexOf("administrative_area_level_1") > -1) {
info += '<div>State: ' + item.long_name + '</div>';
}
if (item.types.indexOf("locality") > -1) {
info += '<div>City: ' + item.long_name + '</div>';
}
});
infowindow.setContent(info);
infowindow.setPosition(place.geometry.location);
infowindow.open(map);
}
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
}
<div id="map"></div>
<script src="https://maps.googleapis.com/maps/api/js?libraries=places&callback=initMap" async defer></script>

How to select objects that have a certain atribute in a json file in an Angular JS project?

I have a link to an API which lists movies, each movie has title,id etc...
API: http://private-5d90c-kevinhiller.apiary-mock.com/angular_challenge/horror_movies
It also has an offers array inside which contains a 'provider_id' property.
I need to show how many movies are available at which provider.
But I dont know how, the best I came up with was:
{{movie.offers[0].provider_id}}
But that only shows the first provider on each movie.
What I want is to extract how many movies each provider has.
My Html:
<div ng-controller="ProviderController as provider">
<div ng-repeat="movie in provider.movies">
{{movie.offers[0].provider_id}}
</div>
</div>
My Main.js:
app.controller('ProviderController', function($http) {
var provider = this;
provider.movies = [];
$http({
url: 'some/path/horror_movies',
method: "GET",
}).success(function(data) {
provider.movies = data;
});
});
Also this is the structire of the json file:
[{
"id": 140524,
"title": "Dracula Untold",
"offers": [{
"provider_id": 2,
"retail_price": 14.99,
//...
}, {
"provider_id": 2,
"retail_price": 14.99,
}, {
"provider_id": 7,
"retail_price": 14.99,
}, ]
},
{
"id": 138993,
"title": "The Purge: Anarchy",
"offers": [
// ...
]
},
]
Any ideas ? Thanks.
You will need to change the structure of your database to have providers at the top level. A function achieving something like this should iterate over every movies offers, something like this:
function getProviders (movies) {
var providers = [],
movie = {},
offer = {};
for (var i = 0, max = movies.length; i < max; i += 1) {
movie = movies[i];
for (var j = 0; j < movies[i].offers.length; j += 1) {
offer = movie.offers[j];
if (typeof providers[offer.provider_id] === 'undefined') {
providers[offer.provider_id] = { movies: [] };
}
providers[offer.provider_id].movies.push(movie);
}
}
return providers;
}
I started a fiddle here: http://jsfiddle.net/d29tu8fg/1/
Before adding a movie to a provider, you might also want to check, if that movie already exists. You only need to do that though, if – like in your data – a movie can have two different offers from the same provider.
Add the providers to the $scope and in your view show the length:
<div ng-repeat="provider in providers track by $index">
{{provider.movies.length}}
</div>

Resources