I am looking for a way to avoid being charged for
Places API Atmosphere Data
Places API Contact Data
I only need to reverse the place id to its formatted_address. Any idea about what changes I need to do in the code bellow?
Related question, although I am not using Autocomplete but PlacesService.
$('.company_location_id').each(function(i, obj) {
if ($(this).length > 0) {
if ($(this).val()) {
var request = {
placeId: $(this).val()
};
service = new google.maps.places.PlacesService(document.getElementsByClassName($(this).attr('class'))[0]);
service.getDetails(request, callback);
var new_text = $(this)
function callback(place, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
$(new_text).next().text(place.formatted_address);
}
}
}
}
});
In order to avoid charges for Atmosphere Data and Contact Data using the PlacesService, you should specify a list of fields to be retrieved in the PlaceDetailsRequest object that you pass as a first parameter in getDetails() function.
Have a look at the documentation of PlaceDetailsRequest interface:
https://developers.google.com/maps/documentation/javascript/reference/places-service#PlaceDetailsRequest
As you can see this interface has fields property
fields - Fields to be included in the details response. For a list of fields see PlaceResult. Nested fields can be specified with dot-paths (for example, "geometry.location").
So, you should define request in your code as
var request = {
placeId: $(this).val(),
fields: ["formatted_address"]
};
I hope this helps!
Related
this is a kind of embarrassing question but I'm stuck.
My background is managed code and I never learned JavaScript but yet I want to implement a tiny project.
The script is running on SharePoint 2010, queries items from a custom list using the JavaScript Object Model and populates a Google chart or table respectively.
With the help of MSDN and Google Developer I was able to query data from one list and visualize it.
However, I'm unable to transfer the concept to query multiple lists, combine result sets and finally pass to Google API.
In my code I created a chain of callbacks like showChart->loadListData->drawChart. This proves to be bad design since it's inflexible and cannot be extended. All API methods are asynchronous and don't have return values but expect method names to call once finished. This is what get's me stuck and where I lack knowledge.
I'm very happy for every comment and answer, also I can provide actual source code if requested. Thank you in advance, Toby
UPDATE as asked for by #Utkanos:
var listItems;
$(document).ready(function() {
ExecuteOrDelayUntilScriptLoaded(loadChartData, "sp.js");
});
function loadChartData() {
var camlQuery = SP.CamlQuery.createAllItemsQuery();
camlQuery.set_viewXml("<View><Query><Where><Eq><FieldRef Name='Year'/><Value Type='Text'>2015</Value></Eq></Where></Query></View>");
loadListData('CustomList', camlQuery, drawChart, readListItemFailed);
}
function loadListData(listTitle, camlQuery, onSuccess, onFail) {
context = SP.ClientContext.get_current();
var list = context.get_web().get_lists().getByTitle(listTitle);
var listItems = list.getItems(camlQuery);
context.load(listItems);
context.executeQueryAsync(function(sender, args){onSuccess(listItems);}, onFail);
}
function drawDpOverviewChart(listItems) {
var data;
var enumerator = listItems.getEnumerator();
data = new google.visualization.DataTable();
data.addColumn('string', 'Column1');
data.addColumn('number', 'Column2');
var listItem;
while (enumerator.moveNext()) {
listItem = enumerator.get_current();
data.addRow([listItem.get_item('Title'), Math.round(listItem.get_item('Balance')/10000)/100]);
}
var options = {'title':'Pretty Chart'};
var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
function readListItemFailed(sender, args) {
alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}
if using SP 2010 on a typical .aspx page, you have some tools available,
such as MicrosoftAjax.js and _spPageContextInfo
using the REST API, you can join lists on lookup fields and include fields from both lists in one query
following is an example url for a call to rest...
'/_vti_bin/ListData.svc/MI_Projects?$expand=ModifiedBy&$filter=ModifiedBy/Id eq 738'
this call actually "joins" the list MI_Projects to the UserInformationList by "expanding" ModifiedBy
so when the data returns, you can access any of the user info fields, i.e.
row.ModifiedBy.Name
this can be done with lookup fields on custom lists as well
to make the call, you can use the Sys.Net.WebRequest class from MicrosoftAjax
this class also allows you to pass variables to the callback
see following snippet...
function makeCall() {
// Sys.Net.WebRequest is from MicrosoftAjax.js
var webRequest = new Sys.Net.WebRequest();
webRequest.get_headers()['Cache-Control'] = 'no-cache';
webRequest.get_headers()['Accept'] = 'application/json';
webRequest.get_headers()['Content-Type'] = 'application/json';
webRequest.set_url(_spPageContextInfo.webServerRelativeUrl + '/_vti_bin/ListData.svc/MI_Projects?$expand=ModifiedBy&$filter=ModifiedBy/Id%20eq%20738');
// use the 'user context' to pass variables you want available in the callback
webRequest.set_userContext({
Title: 'variable to pass to completed callback'
});
webRequest.add_completed(restComplete);
webRequest.invoke();
}
// the first argument of callback is the Sys.Net.WebRequestExecutor class
function restComplete(executor, eventArgs) {
if (executor.get_responseAvailable()) {
if (executor.get_statusCode() === 200) {
// get variable passed via user context
var variablePassed = executor.get_webRequest().get_userContext().Title;
// i.e. -- build google table
// add rows received from rest (forEach is from MicrosoftAjax.js)
// list results array = executor.get_object().d.results
Array.forEach(executor.get_object().d.results, function (row) {
data.addRow(row.Title, row.Id, row.ModifiedBy.Name);
}, this);
}
}
}
I need to get an attribute value ("val_index") of an entity which is selected in lookup.
function onLookupChange(){
var entityName, entityId, entityLabel, lookupFieldObject;
lookupFieldObject = Xrm.Page.data.entity.attributes.get('my_attribute');
if (lookupFieldObject.getValue() != null) {
entityId = lookupFieldObject.getValue()[0].id;
entityName = lookupFieldObject.getValue()[0].entityType;
entityLabel = lookupFieldObject.getValue()[0].name;
}
// here I need to get an attribute value of a selected entity. Attribute's name is "val_index"
}
How can I do that?
Use the SDK.REST.js library which ships with the CRM SDK to do this. Include this as a script in your form entity and you can reference the functions to make REST calls.
An example call might look like this:
// Assume we are working with the account entity.
// This call is asynchronous.
SDK.REST.retrieveRecord(entityId, "Account", "val_index", null,
// Success.
function (result) {
var value = result.val_index;
// Do something.
},
// Error retrieving the value.
function (error) {
// Notify the user...
});
I have a filtration function, a lot of checkboxes and dropdowns. When user selects multiple check boxes and selects the dropdown values they click on the "Filter Now" button.
That button then carries out a POST request to my API and pass along the filtration options as the parameters and return the data from MongoDB.
Heres my code:
factory.getFilteredProjects = function(regions, services, sector){
return $http.post('/user/test',{
region: regions,
sol: services,
sec: sector
}).
success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
console.log("this is the response data " + data);
}).
error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
};
return factory;
});
In the above code you can see I have 3 parameters (regions, services, sector)
Now the user only might want to filter the data by:
Regions or Sector
Just Regions
Just Services
Services and Regions
And So On!
My question:
How can I pass options parameters with my POST regions. At the moment I have to send all 3 parameters to get data back. If I don't send all 3 then I don't get any data back. Only the ones the user actually interacted with so basically something like:
// This is just to get my point across.
function(a || b || c){
}
UPDATE:
Testing my API through POSTMan. As you can see I only sent 2 parameters and got a 200 status back and i am also getting the correct data back.
Thanks.
You can just give an object in parameter instead of three string. Like this you can control the number of POST parameters instead of have some of them undefined.
EDIT : I suggest to do the filtering in your service. Like this, you don't have to complexify your code on each controller :
factory.getFilteredProjects = function(params){
// remove empty value or empty array
angular.forEach(params, function(value, key) {
if( ! value || value.length === 0 ) {
delete params[key];
}
})
return $http.post('/user/test', params).
success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
console.log("this is the response data " + data);
}).
error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
};
return factory;
});
getFilteredProjects({ region: 'test', sec: 'sector' })
so after doing some research, a few cups of coffee and couple of swear words later I got this working.
But heres a note:
First thanks to Yoann Prot your suggestion was a huge help!
This is my initial solution, I will NOT be accepting my own answer. Because there might be a better solution to this and I would like someone to post an answer/comment if they think it can be improved
So my if you read the comments above you know my API was able to handle multiple or flexible number parameters. The issue was my HTTP Post function required all parameters to be present.
As Alex Blex suggested in the comments that:
Then you just need to detect which ones the user actually interacted, and send only them
And thats exactly what I did.
I created a filter object to which I added key/value pairs of only the options that the user interacted with and passed that whole filter object as the parameter. This made my parameters for the HTTP Post request much more flexible.
Heres the code:
var filterObj = {};
var form = document.getElementById("regionPicker");
var servicesForm = document.getElementById("servicesPicker");
var inputs = form.getElementsByTagName("input");
var arr = [];
var servicesInput = servicesForm.getElementsByTagName("input");
var servicesArr = [];
for (var i = 0; i < inputs.length; i += 1) {
// Take only those inputs which are checkbox
if (inputs[i].type === "checkbox" && inputs[i].checked) {
arr.push(inputs[i].value);
}
}
for (var i = 0; i < servicesInput.length; i += 1) {
// Take only those inputs which are checkbox
if (servicesInput[i].type === "checkbox" && servicesInput[i].checked) {
servicesArr.push(servicesInput[i].value);
}
}
// here arr contains an array of filter options selected by user
filterObj.region = (arr.length > 0) ? arr:"";
// here serviceArr contains an array of another filter options selected by user
filterObj.sol = (servicesArr.length > 0) ? servicesArr:"";
And finally pass the filterObj as the parameter:
factory.getFilteredProjects = function(filterObj){
return $http.post('/user/test',filterObj)
.success(function(data, status, headers, config) {
console.log("this is the response data " + data.length);
})
.error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
};
So far all the tests have been successful. But I repeat if you know a better solution please let me know or if you think this solution has drawbacks or issues or is just bad practice please let me know.
Thanks!
I've created a couple of services that grab data from a REST API. These services return objects with names, ids, and some unique keys pertaining to a foo or a bar name. I also have a service doing the same for businesses, also with names, ids, and what foo/bar is tied to that business.
Unfortunately, the data model for this is...not ideal. Rather than just showing which foo/bar is attached to that business, it has every single foo or bar for every single business with a published: true/false key/val pair.
What I'm attempting to do is grab the URL name, loop through my foo object, check to see if the name from the current URL and the data match, and if they do store that object in $scope.results. From here, I want to loop through my businesses object and check to see if its conditionData id matches that of the new $scope.results array's id. Once this condition is met, I want to store those businesses in a $scope.businesses array. As it stands right now, I'm getting all businesses returned, rather than just the ones that have the same id as the current $scope.results id. I suspect the issue is either a) I'm a noob (most likely) or b) the published: true/false is creating issues.
Thanks in advance for any help, let me know if I need to clarify anything else. I'm still pretty new to Angular and JS as a whole, so I'm not sure if how I'm attempting to do this is super optimal. I'm open to better ideas if anyone has any.
.controller('ResultsController', function($scope, $location, getData) {
$scope.businesses = [];
$scope.results = [];
var url = $location.path().split('/')[2]; // we do this because it's always going to follow a pattern of /:base/:name
function init() {
getData.getConditions().success(function(data) {
var tempCondition = data;
var tempData;
for (var condition in tempCondition) {
tempData = tempCondition[condition];
if (url === tempData.name) {
$scope.results = tempData;
}
}
})
.error(function(data, status, headers, config) {
console.log('err: ' + data);
});
getData.getBusinesses().success(function(data) {
var tempBusinesses = data,
tempConditionData;
for (var business in tempBusinesses) {
tempConditionData = tempBusinesses[business].conditionData;
for (var condition in tempConditionData) {
if (tempConditionData[condition].id === $scope.results.id) {
$scope.businesses.push(tempBusinesses[business]);
}
}
}
})
.error(function(data, status, headers, config) {
console.log('err: ' + data);
});
}
init();
});
I find myself using SO as a rubber duck most of the time, I figured it out basically as soon as I finished typing the question. It was due to the published: true/false key/val pair.
All I had to do was change
for (var condition in tempConditionData) {
if (tempConditionData[condition].id === $scope.results.id) {
$scope.businesses.push(tempBusinesses[business]);
}
}
to
for (var condition in tempConditionData) {
if (tempConditionData[condition].id === $scope.results.id && tempConditionData[condition].published === true ) {
$scope.businesses.push(tempBusinesses[business]);
}
}
The two http calls you are using may also be problematic as they depend one each other. what if the first calls takes some time, your second http call returns first.
I'm developing with Nokia Maps (a wonderful option I really love them) but I'm only able to get the location (latitude and longitude) with HTML5 but I can't the name where I am :/, maybe somebody could give an idea, how to do it, thank you very mach for your help.
Maps API for JavaScript 3.x
The current 3.x JavaScript API offers a thin wrapper around the REST Geocoder API. You need to make a ReverseGeocode search, and then extract the data from the Location object(s) found in the result.
A fully working reverse geocoding example can be found here, but the important bit (getting the address) can be see below:
function reverseGeocode(platform) {
var geocoder = platform.getGeocodingService(),
reverseGeocodingParameters = {
prox: '52.5309,13.3847,150', // Location
mode: 'retrieveAddresses',
maxresults: '1',
jsonattributes : 1
};
geocoder.reverseGeocode(
reverseGeocodingParameters,
function (result) {
var locations = result.response.view[0].result;
// ... etc.
},
function (error) {
alert('Ooops!');
}
);
}
Maps API for JavaScript 2.x (deprecated)
With the recently deprecated 2.x JavaScript API, again you need to make a ReverseGeocode search, and then extract the data from the Address object found in the result.
The code is a bit longer, but the important bit (getting the address) can be seen below:
// Function for receiving search results from places search and process them
var processResults = function (data, requestStatus, requestId) {
var i, len, locations, marker;
if (requestStatus == "OK") {
// The function findPlaces() and reverseGeoCode() of return results in slightly different formats
locations = data.results ? data.results.items : [data.location];
// We check that at least one location has been found
if (locations.length > 0) {
for (i = 0, len = locations.length; i < len; i++) {
alert(locations[i].address.street);
alert(locations[i].address.state);
}
} else {
alert("Your search produced no results!");
}
} else {
alert("The search request failed");
}
};
/* We perform a reverse geocode search request: translating a given
* latitude & longitude into an address
*/
var reverseGeoCodeTerm = new nokia.maps.geo.Coordinate(
52.53099,
13.38455
);
nokia.places.search.manager.reverseGeoCode({
latitude: reverseGeoCodeTerm.latitude,
longitude: reverseGeoCodeTerm.longitude,
onComplete: processResults
});