I'm trying to implement Google maps in a Jade template. Using KeystoneJS as a CMS, I have a number of "profiles" (basically people with their addresses) that I want to add to a map as markers.
block js
script.
var map;
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(51.0360272, 3.7359072),
zoom: 8
};
map = new google.maps.Map(document.getElementById("map-canvas"),
mapOptions);
}
google.maps.event.addDomListener(window, 'load', initialize);
block content
.container
script(src='=<GOOGLE_API_KEY>&sensor=false')
if data.profiles
each profile in data.profiles
#{new google.maps.Marker({position: new google.maps.LatLng(profile.address.geo[1], profile.address.geo[0]), map: map, title: profile.name.full})}
div(id="map-canvas", style="width:100%; height:700px;")
The map shows correctly but when I add the 'each' code block I get an error "Cannot read property 'maps' of undefined".
How can I add a piece of js code that executes on 'each' in Jade?
I'm trying to implement Google maps in a Jade template. Using KeystoneJS as a CMS, I have a number of "profiles" (basically people with their addresses) that I want to add to a map as markers.
block js
script.
var map;
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(51.0360272, 3.7359072),
zoom: 8
};
map = new google.maps.Map(document.getElementById("map-canvas"),
mapOptions);
}
google.maps.event.addDomListener(window, 'load', initialize);
block content
.container
script(src='https://maps.googleapis./maps/api/js?key=<GOOGLE_API_KEY>&sensor=false')
if data.profiles
each profile in data.profiles
#{new google.maps.Marker({position: new google.maps.LatLng(profile.address.geo[1], profile.address.geo[0]), map: map, title: profile.name.full})}
div(id="map-canvas", style="width:100%; height:700px;")
The map shows correctly but when I add the 'each' code block I get an error "Cannot read property 'maps' of undefined".
How can I add a piece of js code that executes on 'each' in Jade?
Share Improve this question edited Mar 7, 2014 at 16:53 Kara 6,22616 gold badges53 silver badges58 bronze badges asked Mar 7, 2014 at 14:17 VentisVentis 4887 silver badges22 bronze badges2 Answers
Reset to default 6You're really close, the only problem is that the inside of the variable, i.e. #{this_stuff}
is all executed in jade's context (which won't have the google
object, as this is client-side).
It's a bit tricky because you're dealing with two pletely different javascript environments here: server side and client side.
So you need to output server-side variables in your jade, into javascript code that will be executed client-side.
On a related note, you can use Jade variable syntax in script blocks, but can't do other things (like loops).
Firstly, let's clean it up so all your script
tags are in the js
block (which, assuming you're using the example KeystoneJS templates would be down the bottom of the <body>
tag) and get those profiles being generated correctly:
block js
script(src='https://maps.googleapis./maps/api/js?key=<GOOGLE_API_KEY>&sensor=false')
script.
var map;
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(51.0360272, 3.7359072),
zoom: 8
};
map = new google.maps.Map(document.getElementById("map-canvas"),
mapOptions);
}
google.maps.event.addDomListener(window, 'load', initialise);
if data.profiles
each profile in data.profiles
script.
new google.maps.Marker({
position: new google.maps.LatLng(#{profile.address.geo[1]}, #{profile.address.geo[0]}),
map: map,
title: "#{profile.name.full}"
});
block content
.container
div(id="map-canvas", style="width:100%; height:700px;")
This is getting closer (and the Jade will generate what you're expecting now), but it won't work (yet) because you're potentially adding the markers to the map before the initialize
function has run.
It's also not escaping the values, so things like a "
character in the name would cause a syntax error.
A more robust way of doing it would be to populate a client-side array then loop over that after the map has been created. We'll also use JSON.stringify
to make sure the values are escaped properly.
block js
script(src='https://maps.googleapis./maps/api/js?key=<GOOGLE_API_KEY>&sensor=false')
script.
var map,
profiles = [];
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(51.0360272, 3.7359072),
zoom: 8
};
map = new google.maps.Map(document.getElementById("map-canvas"),
mapOptions);
for (var i = 0; i < profiles.length; i++) {
new google.maps.Marker({
position: new google.maps.LatLng(profiles[i].geo[1], profiles[i].geo[0]),
map: map,
title: profiles[i].name
});
}
}
google.maps.event.addDomListener(window, 'load', initialise);
if data.profiles
each profile in data.profiles
script.
profiles.push({
geo: !{JSON.stringify(profile.address.geo)},
name: !{JSON.stringify(profile.name.full)}
});
block content
.container
div(id="map-canvas", style="width:100%; height:700px;")
Note the change to !{variable} so the JSON isn't escaped
Finally, I'd remend building up the profiles
array in your route .js
file for the view, rather than doing it in the jade template. It's a lot cleaner, and you won't end up with heaps of <script>
tags in your page.
So your route would look something like this (I am assuming a fair bit to give you the idea, and using underscore to make the code neater than vanilla javascript)
var keystone = require('keystone'),
_ = require('underscore');
exports = module.exports = function(req, res) {
var view = new keystone.View(req, res),
locals = res.locals;
// Load the profiles
view.query('profiles', keystone.list('Profile').model.find());
// Create the array of profile markers
view.on('render', function(next) {
locals.profileMarkers = locals.profiles ? _.map(locals.profiles, function(profile) {
return { geo: profile.address.geo, name: profile.name.full };
}) : [];
next();
});
// Render the view
view.render('profiles');
}
Then in your view template:
block js
script(src='https://maps.googleapis./maps/api/js?key=<GOOGLE_API_KEY>&sensor=false')
script.
var profileMarkers = !{JSON.stringify(profileMarkers)},
map;
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(51.0360272, 3.7359072),
zoom: 8
};
map = new google.maps.Map(document.getElementById("map-canvas"),
mapOptions);
_.each(profileMarkers, function(profile) {
new google.maps.Marker({
position: new google.maps.LatLng(profile.geo[1], profile.geo[0]),
map: map,
title: profile.name
});
});
}
google.maps.event.addDomListener(window, 'load', initialise);
block content
.container
div(id="map-canvas", style="width:100%; height:700px;")
"Cannot read property 'maps' of undefined"
Cannot help with this, seems that google maps fail to initialize or something like that.
But I can tell you that if you want to execute JavaScript in your Jade template, you just need to start the line with a dash: var x = Math.random()
I think there is (another) error in the line which starts with #{new google.maps.Maker...
.
This is not JS, it's Jade, and the result the the constructor would be used as HTML tag, I think you don't want that.
Here is an example, you can paste it into this online editor on http://jade-lang./demo/
- var ar = [1,2,3]
ul
each item in ar
- var x = Math.random()*item
li= x
You can check out my gist for some Jade syntax hints: https://gist.github./timaschew/7543cf3d0c455f686784