I have this string of code from one of their examples that I'm trying to reverse engineer.
<script type="text/javascript">
function initialize() {
var map = new google.maps.Map(document.getElementById('map_canvas'), {
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: new google.maps.LatLng(36.018486,-86.787607),
zoom: 15
});
var frontline = new google.maps.LatLng(36.018486,-86.787607);
var request = {
reference: 'CnRkAAAAGnBVNFDeQoOQHzgdOpOqJNV7K9-c5IQrWFUYD9TNhUmz5-aHhfqyKH0zmAcUlkqVCrpaKcV8ZjGQKzB6GXxtzUYcP-muHafGsmW-1CwjTPBCmK43AZpAwW0FRtQDQADj3H2bzwwHVIXlQAiccm7r4xIQmjt_Oqm2FejWpBxLWs3L_RoUbharABi5FMnKnzmRL2TGju6UA4k'
};
var infowindow = new google.maps.InfoWindow();
var service = new google.maps.places.PlacesService(map);
service.getDetails(request, function(place, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
var marker = new google.maps.Marker({
map: map,
position: place.geometry.location
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(place.name);
infowindow.open(map, this);
});
}
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
I can't figure out how to find the reference for my location.
Also, how would I get multiple values into
infowindow.setContent()
I found that if you use the textSearch() method, that it provides the illusive reference string. I wrote a client side script that uses the textSearch() method to provide the reference string for the getDetails() method here.
The long encrypted string is the Place reference, but it should only be used to go back and find the same place. Since it can change slightly it shouldn't be used to group ratings, check-ins, or other activity.
From the Places API documentation:
http://code.google.com/apis/maps/documentation/places/
"reference contains a unique token that you can use to retrieve
additional information about this place in a Place Details request.
You can store this token and use it at any time in future to refresh
cached data about this Place, but the same token is not guaranteed to
be returned for any given Place across different searches."
To add multiple values into the infowindow you just add what details you want show. Like this:
infowindow.setContent(place.name + address + rating);
var request
Is where there are setting their data for the locations. Looks to be fairly encrypted.
Related
I'm trying to get the end part of this URL (in the sever side):
http://localhost:3000/insAds/D79htZY8DQ3YmcscE
I mean I want to get this string:
D79htZY8DQ3YmcscE
there is a similar question: How to get the query parameters in Iron-router?
but non of the answers can't help me! because I have no query params in the URL.
I know these codes gives me the string that I want:
this.params.id
and
Router.current().params.id
but these codes works only in client side! I want to get that string in the server side!
finally I'm trying to get that string and use here:
Ads.before.insert(function(userId, doc) {
//console.log(this.params.id);
doc._categoryId = this.params.id;
doc.createdAt = new Date();
doc.createdBy = Meteor.userId();
});
You can use Router.current().params or this.params like this
Router.route('/insAds/:id', function () {
console.log(this.params.id); // this should log D79htZY8DQ3YmcscE in console
});
Check the third example in Quick Start section of iron router documentation
EDIT: Based on our chat,
Your hook is
Ads.before.insert(function(userId, doc) {
//console.log(this.params.id);
doc._categoryId = this.params.id;
doc.createdAt = new Date();
doc.createdBy = Meteor.userId();
});
Change it to
Ads.before.insert(function(userId, doc) {
doc.createdAt = new Date();
doc.createdBy = Meteor.userId();
});
And then define meteor method in server like this
Meteor.methods({
'myInsertMethod': function (id) {
Ads.insert({
_categoryId: id
});
}
});
Call this from client side like this
Meteor.call('myInsertMethod', Router.params().id, function (err, res) {
console.log (err, res);
});
Is there a way (maybe using rules) to duplicate data on add/push to firebase?
What I want to archive is when I do an add to a firebase array I want to duplicate the data to another array.
So this is my firebase structure:
my-firebase: {
items: [ ... ],
queue: [ ... ]
}
And this is how I have my services defined:
.factory('Service1',['$firebaseArray', function($firebaseArray) {
var items = new Firebase('my-firebase.firebaseio.com/items');
return $firebaseArray(items);
}])
.factory('Service2',['$firebaseArray', function($firebaseArray) {
var queue = new Firebase('my-firebase.firebaseio.com/queue');
return $firebaseArray(queue);
}])
And here is how I use them:
.controller('controller', function($scope, Service1, Service2) {
$scope.save = function() {
Service1.$add({name: "test1"});
Service2.$add({name: "test1"});
}
};
And want I to have a single call not a duplicate call/code but having the result in both arrays (items and queue).
Thanks so much!
Always remember that AngularFire is a relatively thin wrapper around Firebase's JavaScript SDK that helps in binding data into your AngularJS views. If you're not trying to bind and something is not immediately obvious, you'll often find more/better information in the documentation of Firebase's JavaScript SDK.
The API documentation for $firebaseArray.$add() is helpful for this. From there:
var list = $firebaseArray(ref);
list.$add({ foo: "bar" }).then(function(ref) {
var id = ref.key();
console.log("added record with id " + id);
list.$indexFor(id); // returns location in the array
});
So $add() returns a promise that is fulfilled when the item has been added to Firebase. With that knowledge you can add a same-named child to the other list:
var queue = new Firebase('my-firebase.firebaseio.com/queue');
$scope.save = function() {
Service1.$add({name: "test1"}).then(function(ref) {
queue.child(ref.key().set({name: "test1"});
});
}
This last snippet uses a regular Firebase reference. Since AngularFire builds on top of the Firebase JavaScript SDK, they work perfectly together. In fact: unless you're binding these $firebaseArrays to the $scope, you're better off not using AngularFire for them:
var items = new Firebase('my-firebase.firebaseio.com/items');
var queue = new Firebase('my-firebase.firebaseio.com/queue');
$scope.save = function() {
var ref = queue.push();
ref.set({name: "test1"})
queue.child(ref.key().set({name: "test1"});
}
To my eyes this is much easier to read, because we're skipping a layer that wasn't being used. Even if somewhere else in your code, you're binding a $firebaseArray() or $firebaseObject() to the same data, they'll update in real-time there too.
Frank's answer is authoritative. One additional thought here is that AngularFire is extremely extensible.
If you want data pushed to two paths, you could simply override the $add method and apply the update to the second path at the same time:
app.factory('DoubleTap', function($firebaseArray, $q) {
var theOtherPath = new Firebase(...);
return $firebaseArray.$extend({
$add: function(recordOrItem) {
var self = this;
return $firebaseArray.prototype.$add.apply(this, arguments).then(function(ref) {
var rec = self.$getRecord(ref.key());
var otherData = ...do something with record here...;
return $q(function(resolve, reject) {
theOtherPath.push(rec.$id).set(otherData);
});
});
}
});
});
In my visits collection I have a geocodeVisit function which uses the Google geocoding service to gecode an address. The problem is that the meteor script is typically run before the google maps API is loaded, resulting in an Exception while invoking method 'visitInsert' ReferenceError: google is not defined error. So I need to wait with the inser till the geocoding has finished. How can I do this? This is the visits collection:
Meteor.methods({
visitInsert: function(visitAttributes) {
check(Meteor.userId(), String);
check(visitAttributes, {
nr: String,
visit_date: String
});
var properties = {
userId: Meteor.userId(),
position: geocodeVisit(visitAttributes.address)
};
var visit = _.extend(visitAttributes, properties);
var visitId = Visits.insert(visit);
return {
_id: visitId
};
}
});
geocodeVisit = function (address) {
this.unblock;
var geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
return results[0].geometry.location;
}
});
}
Instead of including the maps api using a script tag in the HTML code, you should download the file to your "/lib" directory. Everything in that directory is loaded before any Meteor code is run.
Also, you are going to run into an async problem with you code. You are trying to return the value from the success callback in the geocodeVisit function. The two approaches that I can see working are:
Figure out how to make synchronous requests using the maps api. Maybe this: Synchronous request in Node.js
Go ahead and insert the visit without the location info. Then make the geocode request to the maps api and update the entry once the response comes back. Personally, this is the approach I would take.
I am trying to generate a Flickr url based on a Flickr API call, and then return that result to a handlebars.js template. I am struggling to find a way around asynchronous processes.
I have tried to create a callback function, but I am still uncertain how to get a defined object or variable into the HTML template.
Here is the code for the Flickr API function:
var FlickrRandomPhotoFromSet = function(setID,callback){
Meteor.http.call("GET","http://api.flickr.com/services/rest/?method=flickr.photosets.getPhotos&api_key="+apiKey+"&photoset_id="+setID+"&format=json&nojsoncallback=1",function (error, result) {
if (result.statusCode === 200)
var photoResult = JSON.parse(result.content);
var photoCount = photoResult.photoset.total;
var randomPhoto = Math.floor((Math.random()*photoCount)+1);
var selectedPhoto = photoResult.photoset.photo[randomPhoto];
var imageURL = "<img src=http://farm"+selectedPhoto.farm+".staticflickr.com/"+selectedPhoto.server+"/"+selectedPhoto.id+"_"+selectedPhoto.secret+"_b.jpg/>";
FlickrObject.random = imageURL;
}
if (callback && typeof(callback)==="function") {
callback();
}
});};
My template code is this:
Template.backgroundImage.background = function(){
FlickrRandomPhotoFromSet(setID,function(){
return FlickrObject;
});
};
But this still leaves me stuck, not able to get a defined object into my HTML, which is coded as such:
<template name="backgroundImage">
<div id="background">
{{random}}
</div>
Use Session as an intermediary. It is reactive so as soon as its set it will change the template with the new data:
Template.backgroundImage.background = function(){
return Session.get("FlickrObject");
};
Template.backgroundImage.created = function() {
FlickrRandomPhotoFromSet(setID,function(){
Session.set("FlickrObject", FlickrObject)
});
}
So the created method will be run when the template is created to run FlickrRandomPhotoFromSet, when the result is returned it will set the Session hash which in turn will set the background as soon as the result is received.
Be careful with your FlickrRandomPhotoFromSet too, I didn't notice you had an argument for FlickrObject to pass to the callback.
Has anybody used Googlemaps V3 with something like require.js where it needs to be in AMD version? Is there one already done somewhere?
In require.js you can use the async plugin, then call it like such:
define([
'async!http://maps.google.com/maps/api/js?sensor=false'
], function(){
//Create your map.
});
You can also do it using jQuery.Deferred() and some global variables (not ideal, but I needed it so I could optimize my files using grunt rjs, which didn't work for async):
// gmapsDone.js
window._mapsLoaded = $.Deferred();
window.gmapsLoaded = function(data) {
delete window.gmapsLoaded;
_mapsLoaded.resolve();
};
define(["http://maps.google.com/maps/api/js?v=3&sensor=false&callback=gmapsLoaded"], function(gmaps) {
"use strict";
return window._mapsLoaded.done;
});
Then, to use it:
define(["gmapsDone"], function(gmapsDone) {
function load() {
// Do something
}
gmapsDone(load);
});
https://gist.github.com/taktran/5389668
Inspired by http://blog.pixelingene.com/2011/10/using-jquery-dot-deferred-and-requirejs-to-lazy-load-google-maps-api/
I recently helped a friend solve this issue with a take off on the $.Deferred approach mentioned above. This plays nice with the optimizer and doesn't cause multiple script loads.
The Module
var google_maps_loaded_def = null;
define(['jquery'],function($) {
if(!google_maps_loaded_def) {
google_maps_loaded_def = $.Deferred();
window.google_maps_loaded = function() {
google_maps_loaded_def.resolve(google.maps);
}
require(['http://maps.googleapis.com/maps/api/js?sensor=true&callback=google_maps_loaded'],function(){},function(err) {
google_maps_loaded_def.reject();
//throw err; // maybe freak out a little?
});
}
return google_maps_loaded_def.promise();
});
Available as a Gist:
https://gist.github.com/MattSurabian/7868115
Usage
To Use the above module and take advantage of the fact that the promise resolves with google.maps:
define([ 'app/lib/google-maps-loader' ], function(GoogleMapsLoader){
GoogleMapsLoader.done(function(GoogleMaps){
// your google maps code here!
var geocoder = new GoogleMaps.Geocoder();
}).fail(function(){
console.error("ERROR: Google maps library failed to load");
});
});
Alternatively, just reference the google.maps object normally
define([ 'app/lib/google-maps-loader' ], function(GoogleMapsLoader){
GoogleMapsLoader.done(function(){
// your google maps code here!
var geocoder = new google.maps.Geocoder();
}).fail(function(){
console.error("ERROR: Google maps library failed to load");
});
});
I wrote a short blog post about this method here, which may be of some use: RequireJS Projects and Asynchronously Loading the Google Maps API
I put together a Google Maps AMD loader plugin, which adds some functionality on top of the async! loader.
require.config({
googlemaps: {
params: {
key: 'abcd1234', // sets api key
libraries: 'geometry' // set google libraries
}
}
});
require(['googlemaps!'], function(gmaps) {
// google.maps available as gmaps
var map = new gmaps.Map('map-canvas');
});