Pulling more information from Google Places API call - javascript

This is my working code: http://jsfiddle.net/spadez/5ntLetey/1/
It works perfectly but I'm trying to pull the remaining information into the fields. This is the code I had previously for the lat and long that I found online:
lat.val(results[0].geometry.location.lat());
lng.val(results[0].geometry.location.lng());
How can I pull the remaining information in? This is one example of what I tried and didn't work:
country_short.val(results[0].address_components.country());
Here is the API documentation, what am I doing wrong?

You're not doing anything particularly wrong, unfortunately the returned address components can vastly differ. For example if you were to geocode a coordinate set which might be in the middle of an ocean, you;'re not going to get many address components and perhaps nothing at all, whereas in the middle of somewhere like New York City there are many components that get returned.
What you need to do is to parse the returned response to find something you want like country and only insert that into your fields if and only if there is an address component that has a type of "country".
So for example to get country short and long you would do something like this:
// Get Country value.
var country = getCountry(results[0].address_components)
$('#country_long').val(country.long);
$('#country_short').val(country.short);
calling the function which looks something like this:
function getCountry(addressComponents) {
var returnCountry = {
'long': 'N/A',
'short': 'N/A'
};
// Loop through all address components and find country if possible.
$(addressComponents).each(function (componentIndex, component) {
// loop through all "types" of each component to find if there is a type of "country"
$(component.types).each(function (indexTypes, type) {
if (type == 'country') {
// Then return the long_name and short_name of the component
returnCountry.long = component.long_name;
returnCountry.short = component.short_name;
}
});
});
return returnCountry;
}
Demo: http://jsfiddle.net/5ntLetey/3/

Related

Getting API Parameter Data from Google Optimize

Is there a way to get Google Optimize to return specific data values or even JSON objects for use with experiment callbacks?
We are using Google Optimize without using the visual editor. Instead, we simply want it to indicate which layout pattern to request from a separate API we set up a long time ago.
function gtag() {dataLayer.push(arguments)}
function implementExperimentA(value) {
if (value == '0') {
// Provide code for visitors in the original.
} else if (value == '1') {
// Provide code for visitors in first variant.
} else if (value == '2') {
// Provide code for visitors in section variant.
}
...
}
gtag('event', 'optimize.callback', {
name: '<experiment_id_A>',
callback: implementExperimentA
});
This code example is everywhere and basically what I want to use, but instead of value==1 etc, I want to to be able to use value as a request parameter.
$.get(url, {layoutId: value});
LayoutIds are not integers however. They are unique strings. So again, my question: Is there a way to get Google Optimize to return specific data values or even JSON objects for use with experiment callbacks? Or do I need to map all the Experiment indexes to their correlating API parameter values within my javascript code?

Cannot get the full json with request json

When I am actually entering the XXXX YYYY, then I am getting the players json code in my html page (around 150 values).
But when I am trying to use a function on the players list it somewhy does not contain all the 150 values and the try throws me into the catch error part, where I can see that players json has only 100 players inside there.
Any idea what could be the problem?
if(yourID === "XXXX" && targetID === "YYYY"){
return players;
}
try{
if(isUserAlive(yourID)){
if(targetID === ""){
return userTargetInfo(yourID);
}
var checkForMatch = getUserTarget(yourID);
if(checkForMatch === targetID){
killTarget(targetID);
getUser(yourID).targetID = getTargetTarget(targetID);
addScore(yourID);
return userTargetInfo(yourID);
//return getTargetTargetStats(targetID);
}else{
return "INVALID";
}
}else{
return "DEAD"
}
}catch(err){
console.log("Error",console.log(players))
return "INVALID"
}
Edit: Since I had no time, I created 2 websites and divided the database into 2 different databases, so it would work under 100 people on each. Did not have time to fix the error at this point. So I won't be choosing the solution to that since I won't be trying that any time soon.
Thank you for all your help!
Check the link api that you are using , it might have pagination integrated with it . in that case i will return certain number of object 1st and then you can re-request to get next batch . Most likely they might have a option to change the no of object returned (sometimes with max value)
I'm pretty sure body is returned as a string. Try changing it to an object so you can work with it easier.
Change:
players = body;
to:
players = JSON.parse(body);
I'm not sure the rest of your code, but you may want to add var on your players variable declaration because this looks like the first time you are setting it.
Research: namespace collisions
If you are still having issues, edit your question to include the response you are getting from console.log(JSON.parse(body));. You will be able to get more helpful answers. Personally, I am curious to see the keys such as:
{ query:
{ count: 1,
created: '2017-04-23T22:03:31Z',
lang: 'en-US',
results: { channel: [Object] } } }
If it's paginated, you should see some kind of cursor key in there, or prev and next along with some kind of totalCount.
Hope this helps.

Two-way data binding for a Meteor app

I've built an app that is form-based. I want to enable users to partially fill out a form, and then come back to it at a later date if they can't finish it at the present. I've used iron router to create a unique URL for each form instance, so they can come back to the link. My problem is that Meteor doesn't automatically save the values in the inputs, and the form comes up blank when it is revisited/refreshes. I tried the below solution to store the data in a temporary document in a separate Mongo collection called "NewScreen", and then reference that document every time the template is (re)rendered to auto fill the form. However, I keep getting an error that the element I'm trying to reference is "undefined". The weird thing is that sometimes it works, sometimes it doesn't. I've tried setting a recursive setTimeout function, but on the times it fails, that doesn't work either. Any insight would be greatly appreciated. Or, if I'm going about this all wrong, feel free to suggest a different approach:
Screens = new Meteor.Collection('screens') //where data will ultimately be stored
Forms = new Meteor.Collection('forms') //Meteor pulls form questions from here
NewScreen = new Meteor.Collection('newscreen') //temporary storage collection
Roles = new Meteor.Collection('roles'); //displays list of metadata about screens in a dashboard
//dynamic routing for unique instance of blank form
Router.route('/forms/:_id', {
name: 'BlankForm',
data: function(){
return NewScreen.findOne({_id: this.params._id});
}
});
//onRendered function to pull data from NewScreen collection (this is where I get the error)
Template.BlankForm.onRendered(function(){
var new_screen = NewScreen.findOne({_id: window.location.href.split('/')[window.location.href.split('/').length-1]})
function do_work(){
if(typeof new_screen === 'undefined'){
console.log('waiting...');
Meteor.setTimeout(do_work, 100);
}else{
$('input')[0].value = new_screen.first;
for(i=0;i<new_screen.answers.length;i++){
$('textarea')[i].value = new_screen.answers[i];
}
}
}
do_work();
});
//onChange event that updates the NewScreen document when user updates value of input in the form
'change [id="on-change"]': function(e, tmpl){
var screen_data = [];
var name = $('input')[0].value;
for(i=0; i<$('textarea').length;i++){
screen_data.push($('textarea')[i].value);
}
Session.set("updateNewScreen", this._id);
NewScreen.update(
Session.get("updateNewScreen"),
{$set:
{
answers: screen_data,
first: name
}
});
console.log(screen_data);
}
If you get undefined that could mean findOne() did not find the newscreen with the Id that was passed in from the url. To investigate this, add an extra line like console.log(window.location.href.split('/')[window.location.href.split('/').length-1], JSON.stringify(new_screen));
This will give you both the Id from the url and the new_screen that was found.
I would recommend using Router.current().location.get().path instead of window.location.href since you use IR.
And if you're looking for two way binding in the client, have a look at Viewmodel for Meteor.

How do I make sorting work?

The pub/sub to pull all posts (geo tagged) within a certain distance is not working. The aim is to get user's current location and then use the pub (server calculation) to pull the relevant data + use sort on router to sort it.
Helpers/ Events in js (This portion, Im still tweaking it to see what works)
Template.postsList.onCreated(function() {
this.interval = Meteor.setInterval(function (){
var currentLocation = Geolocation.latLng();
if(currentLocation) {
Session.set('currentLocation', currentLocation);
}
}, 2000
);
Session.set('postSubmitErrors', {});
});
Template.postsList.helpers({
loc : function () {
return Session.get('currentLocation');... // may not be needed if get in router
Template.postsList.events({
postsByDistance : function() { // may not be needed if get in router
var loc = Session.get('currentLocation');...
The error given in the terminal is
Exception from sub postsByDistance id bsWXKgw5QboNzCRXw Error:
Exception while polling query
{"collectionName":"posts","selector":{"loc":{"$near":{"$geometry":{"type":"Point","coordinates":{"currentLocation":{"lat":xxx,"lng":xxx}}},"$maxDistance":500}}},"options":{"transform":null}}:
$near requires a point, given { type: "Point", coordinates: {
currentLocation: { lat: xxx, lng: xxx } } }
If I change pub line to [anything.lng, anything.lat] it says lat or lng of undefined
Occasionally I get a Exception while polling query meteor error when I change the argument in the function().
16 Aug 15 - Updates after suggestions:
new pub
Posts._ensureIndex({'loc' : '2dsphere'});
Meteor.publish('postsByDistance', function(options) {
check(options, Object);
return Posts.find({
loc: {
$near: {
$geometry: {
type: "Point",
coordinates: [currentLocation.lng, currentLocation.lat]
Error now says currentLocation is not defined. But I did define in the helper?
I also think within the error it says I have "options":{"transform":null}} which if correct is not supposed to appear?
In your mongo query the coordinates field should be definitely an array containing two numbers. But as I understand that's something you've already tried. It didn't work for a different reason.
It looks like your problem is caused by a simple "race condition". Namely, the first time you're subscribing to postsByDistance the session variable currentLocation is not yet set and that's the reason you may be getting undefined values for latitude and longitude.
Also - it's probably a typo error - looking at your code you pass an object with currentLocation filed to subscription. On the other hand in your corresponding publish function you are referring to the whole thing as currentLocation but it should be
currentLocation.currentLocation.lng
currentLocation.currentLocation.lat
with your current variables setup. I suggest you change those names because it may lead to a lot of unwanted errors.

Dynamically loading a database based on user text input

I have an autocomplete widget which needs to return options from a database of objects.
On doing so, once the user selects an item the widget will populate other hidden textfields with values from the particular object they chose. - All of this works and has been used on previous projects
However this particular database is far too big (44k+ objects, filesize is several mb and has taken far too long to load in practice) so we've tried various ways of splitting it up. So far the best has been by first letter of the object label.
As a result I'm trying to create a function which tracks the users input into a textfield and returns the first letter. This is then used to AJAX a file of that name (e.g. a.js).
That said I've never had much luck trying to track user input at this level and normally find that it takes a couple keystrokes for everything to get working when I'm trying to get it done on the first keystroke. Does anyone have any advice on a better way of going about this objective? Or why the process doesn't work straight away?
Here is my current non-working code to track the user input - it's used on page load:
function startupp(){
console.log("starting");
$("#_Q0_Q0_Q0").on("keyup", function(){
console.log("further starting!");
if($("#_Q0_Q0_Q0").val().length == 1){
console.log("more starting");
countryChange(($("#_Q0_Q0_Q0").val()[0]).toUpperCase());
}
else{
console.log("over or under");
}
});
}
And an example of the data (dummy values):
tags=[
{
label:"label",
code:"1",
refnum:"555555",
la:"888",
DCSF:"4444",
type:"Not applicable",
status:"Open",
UR:"1",
gRegion:"North West"
},
....
];
edit: fixes applied:
Changed startupp from .change(function) to .on("keyup", function) - keydown could also be used, this is personal preference for me.
Changed the autocomplete settings to have minLength: 4, - as the data starts loading from the first letter this gives it the few extra split ms to load the data before offering options and also cuts down how much data needs to be shown (helps for a couple of specific instances).
Changed how the source is gathered by changing the autocomplete setting to the following:
source: function(request, response) {
var results = $.ui.autocomplete.filter(tags, request.term);
response(results.slice(0, 20));
},
where tags is the array with the data.
all seems to be working now.
You should bind to keydown event:
function startupp(){
console.log("starting");
$("#_Q0_Q0_Q0").keydown(function(){
console.log("further starting!");
if($(this).length() == 1){
console.log("more starting");
countryChange(($(this).val()[0]).toUpperCase());
}
else{
console.log("over or under");
}
});
}

Categories