Global variable not accessible to ViewModel in KnockoutJS - javascript

I am working on a simple Google Maps app using the KnockoutJS library - or at least it seemed simple enough in concept.
After reading up on KnockoutJS and working out some examples, I put together the initial parts. The html so far is just the map, I aim to populate the list as soon as I get over the first hurdle. The hurdle is in the Javascript. Here is the code for reference:
"use strict";
var map;
var center;
var defaultBounds;
var placesServices;
//LocationObject created to hold data for locations generated from google.places.nearbySearch
var LocationObject = function(data){
this.position = data.geometry.location;
this.lat = data.geometry.location.lat;
this.lng = data.geometry.location.lng;
this.name = data.name;
this.placeID = data.place_id;
this.rating = data.rating;
this.types = data.types;
this.linkToPhoto = data.html_attributions;
};
function initMap(){
map = new google.maps.Map(document.getElementById('map'), {
center: center,
zoom: 17,
mapTypeId: 'satellite',
draggable: true,
zoomControl: false,
scrollwheel: true,
disableDoubleClickZoom: true
});
defaultBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(47.614217, -122.317981),new google.maps.LatLng(47.612975, -122.316291));
map.fitBounds(defaultBounds);
placesServices = new google.maps.places.PlacesService(map);
}
//ViewModel created to observe changes on the map
var MapViewModel = function(){
var self = this;
self.testarr = ko.observableArray([
{ firstName: 'Bert', lastName: 'Bertington' },
{ firstName: 'Charles', lastName: 'Charlesforth' },
{ firstName: 'Denise', lastName: 'Dentiste' }
]);
self.locations = ko.observableArray([]);
self.markers = [];
this.getNearbyLocations = function(){
if(placesServices === undefined){
placesServices = new google.maps.places.PlacesService(map);
}
var request = {
location: center,
radius: getBoundsRadius(defaultBounds),
type: ['establishment']
};
placesServices.nearbySearch(request, function(results, status) {
if (status === google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i <= 18; i++) {
var marker = new google.maps.Marker({
map: map,
position: results[i].geometry.location,
animation: google.maps.Animation.DROP
});
self.locations.push(new LocationObject(results[i]));
self.markers.push(marker);
}
} else{
alert("We were not able to find any nearby locations in this Neighbourhood.");
}
});
};
this.init = function(){
self.getNearbyLocations();
};
};
var myMapViewModel = new MapViewModel();
myMapViewModel.init();
ko.applyBindings(myMapViewModel);
/* Utility Functions */
function getBoundsRadius(bounds){....}
The error is:
Uncaught ReferenceError: google is not defined
at MapViewModel.getNearbyLocations
and I don't get why it's not being recognized here, when the map itself loads first without issue but here it get's hung up.
Here is the html for reference, but there shouldn't be an issue there:
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Per Google guideline scheduled for the M65 release, css has been moved to an importer -->
<link rel="import" href="importer.htm"></link>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-xs-12 col-md-4">
<!-- List goes in this column. -->
</div>
</div>
<div class="col-xs-12 col-md-8">
<!-- Map goes into this column. -->
<div id="map" style="width:100%;height:100vh;"></div>
</div>
</div>
</div>
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
<!-- Optional JavaScript -->
<script src="js/knockout.js" ></script>
<script src="js/app.js"></script>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyC-1EdIyUOb74oGG_mEoPvJTAGCSJvSQms&callback=initMap&libraries=places"></script>
</body>

I also thought that the error was because your app.js is being called before the maps script. But I tried changing it, same error, and I also tried removing the async parameter (as suggested by user3297291's comment), still the same error. Theoretically it should have worked.
But this worked - wrap the last 3 lines of your app.js code inside a ready() function:
$(document).ready(function(){
var myMapViewModel = new MapViewModel();
myMapViewModel.init();
ko.applyBindings(myMapViewModel);
});

Related

Leaflet-search on multiplelayers won't work

Hey guys i got some problems with searching multiplelayers in leaflet-search by Stefano Cudini. First i will explain my problem and add the complete code at the end.
I already tried this:
var barLayer= new L.geoJson(bar).addTo(map);
var attraktionenLayer= new L.geoJson(attraktionen).addTo(map);
L.control.search({
layer: L.layerGroup([barlayer, attraktionenlayer]),
initialize: false,
propertyName: 'name',
buildTip: function(text, val) {
var type = val.layer.feature.properties.amenity;
return ''+text+'<b>'+type+'</b>';
}
}).addTo(map);
I also tried to combine my layers before using L.control.search like this:
var poiLayers = L.layerGroup().addTo(map);
poiLayers.addLayer(barLayer);
poiLayers.addLayer(attraktionenLayer);
//also tried this in a single command like
var poiLayers = L.layerGroup([barLayer,attraktionenLayer]).addTo(map);
But everytime i try to search something i get the following error in console:
Uncaught TypeError: m.getLatLng is not a function
at leaflet-search.js:571
at eachLayer (leaflet.js:7)
at e.<anonymous> (leaflet-search.js:570)
at eachLayer (leaflet.js:7)
at e._recordsFromLayer (leaflet-search.js:522)
at e._fillRecordsCache (leaflet-search.js:715)
at leaflet-search.js:677
For single layers the search is working and also if i get the arrays from my FeatureCollections and concat them like this:
var barsarray = bar.features;
var restaurantsarray = attraktionen.features;
var poiarray = barsarray.concat(restaurantsarray);
var poiLayer = new L.geoJson(poiarray);
But with this workaround i get all my markers on the map twice and if i want to hide the single layers with L.control.layers the poilayer will always be shown.
Any suggestions?
Complete Codeexample:
<head>
<link rel="stylesheet" href="../src/leaflet.css" />
<link rel="stylesheet" href="../src/leaflet-search.css" />
<script src="../src/leaflet.js"></script>
<script src="../src/leaflet-search.js"></script>
<script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
<div id="map" style="width: 1600px; height: 400px;"></div>
<script src="../data/Bars.js"></script>
<script src="../data/Attraktionen.js"></script>
<script>
var map = L.map('map', {
zoom: 14,
center: new L.latLng(50.957703,6.967322),
layers: L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png')
});
var barLayer= new L.geoJson(bar).addTo(map);
var attraktionenLayer= new L.geoJson(attraktionen).addTo(map);
var barsarray = bar.features;
var restaurantsarray = attraktionen.features;
var poiarray = barsarray.concat(restaurantsarray);
var poiLayer = new L.geoJson(poiarray);
var poiLayers = L.layerGroup().addTo(map);
poiLayers.addLayer(barLayer);
poiLayers.addLayer(attraktionenLayer);
L.control.search({
layer: poiLayers,
initialize: false,
propertyName: 'name',
buildTip: function(text, val) {
var type = val.layer.feature.properties.amenity;
return ''+text+'<b>'+type+'</b>';
}
}).addTo(map);
var baseLayers = {
//"Bars": barsLayer,
//"Restaurants": restaurantsLayer
};
var overlays = {
"Bars": barLayer,
"Attraktionen": attraktionenLayer
};
L.control.layers(baseLayers, overlays).addTo(map);
</script>
</body>

Trouble adding search widget to ArcGIS Shortlist Story App

I 'm having issues adding in a search widget to a shortlist application. I have included the code below. The search bar shows up, but is not functional.
I am needing to have this to where it can search business names that are included within the application.
<html>
<head>
<title>ChahtaPreneur</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link type="image/ico" rel="shortcut icon" href="//resources.esri.com/favicon.ico">
<link type="image/ico" rel="icon" href="//resources.esri.com/favicon.ico">
<link rel="stylesheet" href="https://js.arcgis.com/3.18/esri/css/esri.css">
<script src="https://js.arcgis.com/3.18/"></script>
<link rel="stylesheet" href="https://js.arcgis.com/3.18/esri/css/esri.css">
<link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/3.2/js/dojo/dijit/themes/claro/claro.css">
<link rel="stylesheet" href="http://serverapi.arcgisonline.com/jsapi/arcgis/3.5/js/esri/css/esri.css">
<link rel="stylesheet" type="text/css" href="colorbox/colorbox.css">
<link rel="stylesheet" type="text/css" href="css/style.css">
<script type="text/javascript" src="lib/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="lib/common/helper_functions.js"></script>
<script type="text/javascript">var djConfig = {parseOnLoad: true};</script>
<script type="text/javascript" src="colorbox/jquery.colorbox-min.js"></script>
<script type="text/javascript" src="lib/jquery.animate-colors-min.js"></script>
<script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/3.5/"></script>
<style>
html,body,
#mapDiv,.map.container{
padding:0;
margin:0;
height:100%;
}
#search {
display: block;
position: absolute;
z-index: 2;
top: 20px;
left: 720px;
}
</style>
<script src="https://js.arcgis.com/3.18/"></script>
<!--
To correctly reference your Shortlist in search engine:
- create and fill out extensively an ArcGIS Online item that link to your final application
- edit the following four tags as well as the title tag above on line 4
-->
<meta name="description" content="This story map was created with the Story Map Shortlist application in ArcGIS Online.">
<!-- Facebook sharing -->
<meta property="og:type" content="article"/>
<meta property="og:title" content="Story Map Shortlist"/>
<meta property="og:description" content="This story map was created with the Story Map Shortlist application in ArcGIS Online."/>
<meta property="og:image" content="resources/common/icons/esri-globe.png"/>
<!--
This application is released under the Apache License V2.0 by Esri http://www.esri.com/
Checkout the project repository on GitHub to access source code, latest revision, developer documentation, FAQ and tips
https://github.com/Esri/shortlist-storytelling-template-js
-->
<script type="text/javascript">
//-------------------------------------------------------------------------------------------
// Application configuration (ignored on ArcGIS Online, Portal and during development)
//-------------------------------------------------------------------------------------------
var configOptions = {
// Enter an application ID created through the Shortlist builder
appid: "f8c9b5d9a2c64703bb72910f46f59d7c",
// Optionally to secure Shortlist's access, use an OAuth application ID (example: 6gyOg377fLUhUk6f)
// User will need to sign-in to access the viewer even if your application is public
oAuthAppId: "",
// Optionally to be able to use the appid URL parameter, configure here the list of application author
// whose application are allowed to be viewed by this Shortlist deployment
// This is the Portal username of the Shortlist owner (e.g. ["user1"], ["user1", "user2"])
authorizedOwners: ["*"]
};
// Optionally sharing and proxy URLs can be configured in app/config.js. This is only required
// when the webmap is not hosted on ArcGIS Online or a Portal for ArcGIS instance and the application isn't deployed as /home/Shortlist/ or /apps/Shortlist/.
// Optionally Bing Maps key, Geometry and Geocode service's URLs can be configured in app/config.js. This is only required
// if the Organization or Portal for ArcGIS instance default configuration has to be overwritten.
</script>
<script type="text/javascript">
dojo.require("dijit.dijit");
dojo.require("dijit.layout.BorderContainer");
dojo.require("dijit.layout.ContentPane");
dojo.require("esri.map");
dojo.require("esri.arcgis.utils");
dojo.require("esri.dijit.Geocoder");
/******************************************************
******************** config section ******************
*******************************************************/
var WEBMAP_ID = "6b3d1da24e5841f1b8d47de63b7be7a4";
var BOOKMARKS_ALIAS = "Zoom";
var COLOR_ORDER = "green,red,blue,purple"; // will only use as many colors as you have content (point) layers
var BINGMAPS_KEY = "";
/******************************************************
******************** app variables ********************
*******************************************************/
var _contentLayers = [];
var _isMobile = isMobile();
var _map;
var _bookmarks;
var _layerCurrent;
var _selected;
var _initExtent;
var _dojoReady = false;
var _jqueryReady = false;
var geocoder;
var locatorUrl = "http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/";
/******************************************************
************************* init ************************
*******************************************************/
dojo.addOnLoad(function() {_dojoReady = true;init()});
jQuery(document).ready(function() {_jqueryReady = true;init()});
/* init comes in two parts because of async call to
createMap. */
function init() {
if (!_jqueryReady) return;
if (!_dojoReady) return;
if (getParameterByName("webmap") != "") {
WEBMAP_ID = getParameterByName("webmap");
}
if (getParameterByName("bookmarks_alias") != "") {
BOOKMARKS_ALIAS = getParameterByName("bookmarks_alias");
}
if (getParameterByName("color_order") != "") {
COLOR_ORDER = getParameterByName("color_order")
}
$("#bookmarksTogText").html(BOOKMARKS_ALIAS+' ▼');
$(this).resize(handleWindowResize);
$("#zoomIn").click(function(e) {
_map.setLevel(_map.getLevel()+1);
});
$("#zoomOut").click(function(e) {
_map.setLevel(_map.getLevel()-1);
});
$("#zoomExtent").click(function(e) {
_map.setExtent(_initExtent);
});
$(document).bind('cbox_complete', function(){
$(".details .rightDiv").height($(".details").height() - 65);
});
$("#bookmarksToggle").click(function(){
if ($("#bookmarksDiv").css('display')=='none'){
$("#bookmarksTogText").html(BOOKMARKS_ALIAS+' ▲');
}
else{
$("#bookmarksTogText").html(BOOKMARKS_ALIAS+' ▼');
}
$("#bookmarksDiv").slideToggle();
});
var mapDeferred = esri.arcgis.utils.createMap(WEBMAP_ID, "map", {
mapOptions: {
slider: false,
wrapAround180:false
},
ignorePopups: true,
bingMapsKey: BINGMAPS_KEY
});
mapDeferred.addCallback(function(response) {
document.title = response.itemInfo.item.title;
$("#title").html(response.itemInfo.item.title);
$("#subtitle").html(response.itemInfo.item.snippet);
_map = response.map;
//resize the map when the browser resizes
dojo.connect(dijit.byId('map'), 'resize', _map,_map.resize);
dojo.connect(_map, 'onExtentChange', refreshList);
// click action on the map where there's no graphic
// causes a deselect.
dojo.connect(_map, 'onClick', function(event){
if (event.graphic == null) {
unselect();
}
});
_bookmarks = response.itemInfo.itemData.bookmarks;
if (_bookmarks) {
loadBookmarks();
$("#bookmarksCon").show();
}
var layers = response.itemInfo.itemData.operationalLayers;
if(_map.loaded){
initMap(layers);
} else {
dojo.connect(_map,"onLoad",function(){
initMap(layers);
});
}
});
mapDeferred.addErrback(function(error) {
console.log("Map creation failed: ", dojo.toJson(error));
});
}
function initMap(layers) {
var supportLayers = [];
var pointLayers = [""];
$.each(layers,function(index,value){
if (value.url == null) {
if (value.featureCollection.layers[0].featureSet.geometryType == "esriGeometryPoint") {
pointLayers.push(value);
} else {
supportLayers.push(value);
}
} else {
// if the layer has an url property (meaning that it comes from a service), just
// keep going...it will remain in the map, but won't be query-able.
}
});
_initExtent = _map.extent;
var supportLayer;
$.each(supportLayers,function(index,value) {
supportLayer = findLayer(_map,value.title);
if (supportLayer == null) return;
$.each(supportLayer.graphics,function(index,value) {
value.attributes.getValueCI = getValueCI; // assign extra method to handle case sensitivity
});
dojo.connect(supportLayer, "onMouseOver", baselayer_onMouseOver);
dojo.connect(supportLayer, "onMouseOut", baselayer_onMouseOut);
dojo.connect(supportLayer, "onClick", baselayer_onClick);
});
if (COLOR_ORDER.split(",").length < pointLayers.length) {
// you have supplied fewer colors than point layers and
// therefore have lost your sorting privileges...
colorschemes = COLOR_SCHEMES;
} else {
// sort the colors
var colorschemes = getSortedColorSchemes();
// burn off any extra colors, if you have more colors
// than points.
while (pointLayers.length < colorschemes.length) {
colorschemes.shift()
};
}
var contentLayer;
$.each(pointLayers,function(index,value) {
_map.removeLayer(findLayer(_map,value.title));
if (index <= 4) { // maximum of 4 point layers.
$.each(value.featureCollection.layers[0].featureSet.features,function(index,value) {
value.attributes.getValueCI = getValueCI; // assign extra method to handle case sensitivity
});
contentLayer = buildLayer(
value.featureCollection.layers[0].featureSet.features.sort(SortByID),
colorschemes[index].iconDir,
colorschemes[index].iconPrefix
);
contentLayer.color = colorschemes[index].color;
contentLayer.title = value.title;
dojo.connect(contentLayer, "onMouseOver", layer_onMouseOver);
dojo.connect(contentLayer, "onMouseOut", layer_onMouseOut);
dojo.connect(contentLayer, "onClick", layer_onClick);
_map.addLayer(contentLayer);
_contentLayers.push(contentLayer);
}
});
_contentLayers.reverse();
$.each(_contentLayers,function(index,value){
$("#tabs").append('<div class="tab" onclick="activateLayer(_contentLayers['+index+'])">'+value.title+'</div>');
});
activateLayer(_contentLayers[0]);
dojo.connect(_map.infoWindow,"onHide",infoWindow_onHide);
handleWindowResize();
$("#zoomToggle").css("visibility","visible");
// Solomon Additions
// add a graphics layer for geocoding results
_map.addLayer(new esri.layers.GraphicsLayer({
id: "results"
}));
var myGeocoders = [{
url: locatorUrl,
name: "Single_Line"
}];
// create the geocoder
geocoder = new esri.dijit.Geocoder({
autoComplete : true,
autoNavigate: true,
localSearchOptions : {
minScale : 3,
distance : 4000},
maxLocations : 20,
arcgisGeocoder: false,
geocoders:myGeocoders,
value:'Search by Name',
map : _map
}, "search");
geocoder.startup();
geocoder.focus();
var symbol = new esri.symbol.PictureMarkerSymbol({
"angle":0,
"xoffset":0,
"yoffset":10,
"type":"esriPMS",
"url":"http://static.arcgis.com/images/Symbols/Shapes/BluePin1LargeB.png",
"contentType":"image/png",
"width":24,
"height":24
});
var template = new esri.InfoTemplate("${NAME}", "${*}");
dojo.connect(geocoder, "onFindResults", function(response) {
//STEVE CHANGES
//Use first match
//var name = response.results[0].name;
//Match name with locations layer and selected that index
//for(i in _locations){
//if(name === _locations[i].attributes.getName()){
//preSelection()
//_selected = _locations[i];
//postSelection();
//}
//}
//STEVE CHANGES END
console.log("find results: ", response);
var l = _map.getLayer("shortlistlayer");
l.clear();
_map.infoWindow.hide();
dojo.forEach(response.results, function(r) {
r.feature.attributes.NAME = r.NAME;
r.feature.setSymbol(symbol);
r.feature.setInfoTemplate(template);
l.add(r.feature);
});
});
// solomon Addition Ends
}
/******************************************************
******************** event handlers *******************
*******************************************************/
function tile_onMouseOver(e) {
$(this).stop().animate({'background-color' : COLOR_FULL});
}
function tile_onMouseOut(e) {
if (_selected != null) {
// does this tile represent the selected graphic?
var id = parseInt($(this).attr("id").substring(4));
if (_selected.attributes.getValueCI("Number") == id) {
return;
}
}
$(this).stop().animate({'background-color' : COLOR_DIM});
}
function tile_onClick(e) {
// turn off the last selected tile...
if (_selected != null) {
var tile = $.grep($("ul.tilelist li"),function(n,i){return n.id == "item"+_selected.attributes.getValueCI("Number")})[0];
if ($(tile).attr("id") != $(this).attr("id")) $(tile).stop().animate({'background-color' : COLOR_DIM});
}
$(this).stop().animate({'background-color' : COLOR_FULL});
var id= $(this).attr("id").substring(4);
_selected = $.grep(_layerCurrent.graphics,function(n,i){return n.attributes.getValueCI("Number") == id})[0];
postSelection();
}
function infoWindow_onHide(event) {
unselect();
}
function baselayer_onMouseOver(event)
{
if (_isMobile) return;
_map.setMapCursor("pointer");
var graphic = event.graphic;
$("#hoverInfo").html(graphic.attributes.getValueCI("Title"));
var pt = event.screenPoint;
hoverInfoPos(pt.x,pt.y);
}
function baselayer_onMouseOut(event)
{
if (_isMobile) return;
_map.setMapCursor("default");
$("#hoverInfo").hide();
}
function baselayer_onClick(event) {
var feature = event.graphic;
_map.infoWindow.setTitle(event.graphic.attributes.getValueCI("NAME"));
_map.infoWindow.setContent(event.graphic.attributes.getValueCI("CAPTION")+"<p><span class='infoWindowLink'>Details >></span></p>");
_map.infoWindow.show(event.mapPoint);
$(".infoWindowLink").click(function(e) {
showDetails(feature);
});
$("#hoverInfo").hide();
}
function layer_onClick(event)
{
var tile;
if (_selected != null) {
tile = $.grep($("ul.tilelist li"),function(n,i){return n.id == "item"+_selected.attributes.getValueCI("Number")})[0]
$(tile).stop().animate({'background-color' : COLOR_DIM});
}
_selected = event.graphic;
tile = $.grep($("ul.tilelist li"),function(n,i){return n.id == "item"+_selected.attributes.getValueCI("Number")})[0]
$(tile).stop().animate({'background-color' : COLOR_FULL});
postSelection();
}
function layer_onMouseOver(event)
{
if (_isMobile) return;
_map.setMapCursor("pointer");
var graphic = event.graphic;
if (graphic == _selected) return;
graphic.setSymbol(graphic.symbol.setHeight(30).setWidth(24));
$("#hoverInfo").html(graphic.attributes.getValueCI("NAME"));
var pt = _map.toScreen(graphic.geometry);
hoverInfoPos(pt.x,pt.y);
}
function layer_onMouseOut(event)
{
if (_isMobile) return;
_map.setMapCursor("default");
var graphic = event.graphic;
graphic.setSymbol(graphic.symbol.setHeight(28).setWidth(22));
$("#hoverInfo").hide();
}
/******************************************************
****************** other functions ********************
*******************************************************/
function unselect() {
if (_selected != null) {
tile = $.grep($("ul.tilelist li"),function(n,i){return n.id == "item"+_selected.attributes.getValueCI("Number")})[0]
$(tile).stop().animate({'background-color' : COLOR_DIM});
}
_selected = null;
postSelection();
}
// sort items by numeric ID
function SortByID(a, b){
var aID = a.attributes.getValueCI("Number");
var bID = b.attributes.getValueCI("Number");
return ((aID < bID) ? -1 : ((aID > bID) ? 1 : 0));
}
function loadBookmarks() {
$.each(_bookmarks,function(index,value){$("#bookmarksDiv").append("<p><a>"+value.name+"</a></p>")});
$("#bookmarksDiv a").click(function(e) {
var name = $(this).html();
var extent = new esri.geometry.Extent($.grep(_bookmarks,function(n,i){return n.name == name})[0].extent);
_map.setExtent(extent);
$("#bookmarksTogText").html(BOOKMARKS_ALIAS+' ▼');
$("#bookmarksDiv").slideToggle();
});
}
function activateLayer(layer) {
_selected = null;
postSelection();
_layerCurrent = layer;
var tab = $.grep($(".tab"),function(n,i){return $(n).html() == _layerCurrent.title})[0];
$(".tab").removeClass("tab-selected");
$(tab).addClass("tab-selected");
$.each(_contentLayers,function(index,value){
value.setVisibility(value == _layerCurrent);
});
$("#myList").empty();
var display;
var tile;
var img;
var footer;
var num;
var title;
$.each(_layerCurrent.graphics,function(index,value){
if (_map.extent.contains(value.geometry)) {
display = "visible"
} else {
display = "none";
}
tile = $('<li id="item'+value.attributes.getValueCI("Number")+'" style="display:'+display+'">');
img = $('<img src="'+value.attributes.getValueCI("THUMB_URL")+'">');
footer = $('<div class="footer"></div>');
num = $('<div class="num" style="background-color:'+_layerCurrent.color+'">'+value.attributes.getValueCI("Number")+'</div>');
title = $('<div class="blurb">'+value.attributes.getValueCI("Name")+'</div>');
$(footer).append(num);
$(footer).append(title);
$(tile).append(img);
$(tile).append(footer);
$("#myList").append(tile);
});
// event handlers have to be re-assigned every time you load the list...
$("ul.tilelist li").mouseover(tile_onMouseOver);
$("ul.tilelist li").mouseout(tile_onMouseOut);
$("ul.tilelist li").click(tile_onClick);
$("ul.tilelist").animate({ scrollTop: 0 }, { duration: 200 } );
}
function refreshList() {
var tile;
$.each(_layerCurrent.graphics,function(index,value){
//find the corresponding tile
tile = $.grep($("ul.tilelist li"),function(n,i){return n.id == "item"+value.attributes.getValueCI("Number")})[0];
if (_map.extent.contains(value.geometry)) {
if ($(tile).css("display") == "none") $(tile).stop().fadeIn();
} else {
if ($(tile).css("display") != "none") $(tile).stop().fadeOut(1000);
}
});
}
function buildLayer(arr,iconDir,root) {
var layer = new esri.layers.GraphicsLayer();
var pt;
var sym;
$.each(arr,function(index,value){
pt = new esri.geometry.Point(value.geometry.x,value.geometry.y,value.geometry.spatialReference);
sym = new esri.symbol.PictureMarkerSymbol("images/icons/"+iconDir+"/"+root+value.attributes.getValueCI("Number")+".png",22,28);
layer.add(new esri.Graphic(pt,sym,value.attributes));
});
return layer;
}
function getValueCI(field) {
var found;
$.each(this,function(index,value){
if (index.toUpperCase() == field.toUpperCase()) {
found = index;
return false;
}
});
return this[found];
}
function handleWindowResize() {
var heightDoc = getViewportDimensions()[1];
$("#mainWindow").height(heightDoc - ($("#header").height()));
dijit.byId("mainWindow").layout();
$("#paneLeft").height($("#mainWindow").height() - 35);
$(".tilelist").height($("#paneLeft").height() - 20);
$("#map").height($("#mainWindow").height() - 35);
Well, I went though your code the major error i can see is that multiple define error.
Root Cause:
The main reason for it you are loading those libraries more than once who expose define.
Solution:
In your case i noticed you have loaded ArcGIS JS Api more than once.
Just load only one source of ArcGIS it should work.
One more thinh in attached code you are using multiple versions of CSS.
you are suppose to use same version of ESRI CSS which you are using for JS.
As per your code you are using legacy model of coding style so go for arcgis js api's that version only.
Code without multiple define error: https://jsfiddle.net/vikash2402/362ft9g7/
Hoping this will help you :)
Well, Here is the working code for esri search widget.
Just require the needed libraries and plugin the code.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no" />
<title>Search with Suggestion Template</title>
<link rel="stylesheet" href="https://js.arcgis.com/3.18/dijit/themes/claro/claro.css">
<link rel="stylesheet" href="https://js.arcgis.com/3.18/esri/css/esri.css">
<style>
html,
body,
#map {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
#search {
display: block;
position: absolute;
z-index: 2;
top: 20px;
left: 74px;
}
</style>
<script src="https://js.arcgis.com/3.18/"></script>
<script>
require([
"esri/map", "esri/dijit/Search", "esri/layers/FeatureLayer", "esri/InfoTemplate", "dojo/domReady!"
], function (Map, Search, FeatureLayer,InfoTemplate) {
var map = new Map("map", {
basemap: "gray",
center: [-82.93, 42.5], // lon, lat
zoom: 10
});
var search = new Search({
sources: [{
featureLayer: new FeatureLayer("https://services.arcgis.com/b6gLrKHqgkQb393u/arcgis/rest/services/TaxParcelQuery/FeatureServer/0", {
outFields: ["*"],
infoTemplate: new InfoTemplate("Parcels", "Owner name: ${OWNERNME1}</br>Parcel ID: ${PARCELID}</br>Site address: ${SITEADDRESS}")
}),
outFields: ["OWNERNME1","PARCELID","SITEADDRESS"],
displayField: "OWNERNME1",
suggestionTemplate: "${PARCELID}: ${SITEADDRESS}",
name: "Parcels",
placeholder: "example: Shawn Smith",
enableSuggestions: true
}],
map: map
}, "search");
search.startup();
});
</script>
</head>
<body>
<div id="search"></div>
<div id="map"></div>
</body>
</html>
Hoping this will help you :)

Uncaught TypeError: Cannot read property 'html' of undefined

I am trying to have a google map display on my webpage using backbone.js and handlebars.js, but I can't get it to display. When I load the page, I get this error in my javascript console:
Uncaught TypeError: Cannot read property 'html' of undefined
Does anyone know what I am doing wrong? Any and all suggestions welcome.
index.html
<!DOCTYPE html>
<html>
<head>
{% load staticfiles %}
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta http-equiv="cleartype" content="on">
<link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.css' %}">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="{% static 'bootstrap/js/bootstrap.js' %}"></script>
<script src="http://ajax.cdnjs.com/ajax/libs/underscore.js/1.1.4/underscore-min.js"></script>
<script src="http://ajax.cdnjs.com/ajax/libs/backbone.js/0.3.3/backbone-min.js"></script>
<script src="{% static 'django_project/js/handlebars.js' %}"></script>
<link href="https://fonts.googleapis.com/css?family=Raleway:400,700,200" rel="stylesheet" type="text/css">
<script src="https://maps.googleapis.com/maps/api/js?v=3&sensor=false"></script>
</head>
<body>
<script type="text/x-mustache-template" id="grid-12-template">
<div id="googleMapBox" class="box-content"></div>
</script>
<script src="{% static 'django_project/js/django_project.js' %}"></script>
<script>
var GoogMap = new GoogleMap;
GoogMap.render();
</script>
</body>
</html>
django_project.js
var template = function (name) {
var source = $('#' + name + '-template').html();
return Handlebars.compile(source);
};
var GoogleMap = Backbone.View.extend({
template: template('grid-12'),
initialize: function() {},
activate: function() {
var mapOptions = {
zoom: 8,
center: new google.maps.LatLng(-34.397, 150.644),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var domElement = this.$('#googleMapBox');
this.map = new google.maps.Map(domElement.get(0), mapOptions);
},
render: function() {
this.$el.html(this.template(this));
this.activate();
return this;
}
});
for some reason this.$el.html(...) was causing the problem. Even if I specified el in the view it wouldn't work. this is the code that worked.
django_project.js
var template = function (name) {
var source = $('#' + name + '-template').html();
return Handlebars.compile(source);
};
var GoogleMap = Backbone.View.extend({
el: $('#map-canvas'),
template: template('grid-12'),
initialize: function () {
this.render();
},
activate: function () {
var mapOptions = {
zoom: 8,
center: new google.maps.LatLng(-34.397, 150.644),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var domElement = $('#googleMapBox');
this.map = new google.maps.Map(domElement.get(0), mapOptions);
},
render: function () {
$('#map-canvas').html(this.template(this));
this.activate();
return this;
}
});
$(function () {
var GoogMap = new GoogleMap();
});
index.html
...
<div id="map-canvas"></div>
<script type="text/x-mustache-template" id="grid-12-template">
<div id = "googleMapBox"
class = "box-content"
style = "height: 600px; background-color: #b0c4de;" > </div >
</script>
...

How pass data from parent page to popup?

I have following code:
parent page:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<a href=# onclick='showMap()'>show map <a>
<div id="map-canvas"></div>
</body>
<script>
function showMap(){
window.open('map.html','map','width=600,height=400');
}
</script>
</html>
map.html:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Info windows</title>
<style>
html, body, #map-canvas {
height: 100%;
margin: 0px;
padding: 0px
}
</style>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp"></script>
<script>
function initialize() {
var myLatlng = new google.maps.LatLng(-25.363882,131.044922);
var mapOptions = {
zoom: 4,
center: myLatlng
};
var map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: 'Uluru (Ayers Rock)'
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="map-canvas"></div>
</body>
</html>
As you can see I use hardcode values for map marker rendering:
var myLatlng = new google.maps.LatLng(-25.363882,131.044922);
Can I pass these values from parent page to popup?
Since you asked just how to pass from parent to pop up an option would be querystring parameters:
<a href=# onclick='showMap(-25.363882,131.044922)'>show map <a>
function showMap(lat,lng){
window.open('map.html?lat='+lat+'&lng ='+lng,'map','width=600,height=400');
}
Then in map.html collect those values and use..
Update: Collecting query string values can be done in a lot of ways see the options with a quick search
function getParameterByName(name) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(location.search);
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}
var lat = getParameterByName('lat');
var lon = getParameterByName('lon');
taken from : https://stackoverflow.com/a/901144/306921
You can also take a look at: Get query string parameters with jQuery
I tested and its all working:
resulting index.html:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<a href=# onclick='showMap(-25.363882,131.044922)'>show map <a>
<div id="map-canvas"></div>
</body>
<script>
function showMap(lat,lng){
window.open('map.html?lat='+lat+'&lng ='+lng,'map','width=600,height=400');
}
</script>
</html>
and the resulting map.html:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Info windows</title>
<style>
html, body, #map-canvas {
height: 100%;
margin: 0px;
padding: 0px
}
</style>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp"></script>
<script>
function getParameterByName(name) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(location.search);
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}
var lat = getParameterByName('lat');
var lon = getParameterByName('lon');
function initialize() {
var myLatlng = new google.maps.LatLng(lat, lon);
var mapOptions = {
zoom: 4,
center: myLatlng
};
var map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: 'Uluru (Ayers Rock)'
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="map-canvas"></div>
</body>
</html>
QueryString is a good way. However based on your requirement, You can also store it in parent page and read via javascript.
Storing value in parent page using dom:
<input type="hidden" id="lat" value="...."/>
You can also google to find how to store the data with window object itself(e.g window.myVar='xxx') and reading it from pop-up.
Accessing value in pop-page opened via window.open
var lat =window.opener.getElementById("lat").value;//use window.parent if opened as iframe

hide Bing Maps AJAX v7 DirectionsManager infoboxes

I'm using for first time the DirectionsManager to create routes in Bing Maps AJAX v7. The route is created correctly, but comes with two small "infoboxes" showing "A" at the start of the route, and "B" at the final. I want to remove those infoboxes, but honestly, after reading all the documentation (http://msdn.microsoft.com/en-us/library/hh312832.aspx) and "Binging/Googling" a while, I can't found anything helpful. Also, I tried every option inside setRenderOptions. Any ideas?
directionsManager = new Microsoft.Maps.Directions.DirectionsManager(map);
directionsManager.resetDirections();
directionsManager.setRenderOptions({autoDisplayDisambiguation: false,
autoUpdateMapView: true, displayManeuverIcons: false, displayPreItineraryItemHints: false, displayPostItineraryItemHints: false, displayRouteSelector: false, displayStepWarnings: false, drivingPolylineOptions: { strokeColor: new Microsoft.Maps.Color(150, 255, 51, 51), strokeThickness: 8 }
});
directionsManager.setRequestOptions({ routeMode: Microsoft.Maps.Directions.RouteMode.driving });
var seattleWaypoint = new Microsoft.Maps.Directions.Waypoint({ address: '000 fake street, Houston TX 77000' });
directionsManager.addWaypoint(seattleWaypoint);
var tacomaWaypoint = new Microsoft.Maps.Directions.Waypoint({ address: '111 fake street, Houston TX 77111' });
directionsManager.addWaypoint(tacomaWaypoint);
directionsManager.calculateDirections();
One possible solution is to customize the pushpin to display blank pushpin with a small size (I've tried with another pushpin with 15x15 pixels size):
// Set the render options
directionsManager.setRenderOptions({
itineraryContainer: document.getElementById('itineraryDiv'),
displayWalkingWarning: false,
walkingPolylineOptions:{strokeColor: new Microsoft.Maps.Color(200, 0, 255, 0)},
waypointPushpinOptions: {icon:'pin_blank.png', height:1, width:1}
});
The other way might consist in calling the service by yourself and handling the request and response in your code. Here is an example: http://msdn.microsoft.com/en-us/library/gg427607.aspx
Here is the code that might be what you will help you:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
<script type="text/javascript">
var map = null;
function GetMap()
{
// Initialize the map
map = new Microsoft.Maps.Map(document.getElementById("mapDiv"),{credentials:"Your Bing Maps Key", mapTypeId: Microsoft.Maps.MapTypeId.road });
}
function ClickRoute(credentials)
{
map.getCredentials(MakeRouteRequest);
}
function MakeRouteRequest(credentials)
{
var routeRequest = "http://dev.virtualearth.net/REST/v1/Routes?wp.0=" + document.getElementById('txtStart').value + "&wp.1=" + document.getElementById('txtEnd').value + "&routePathOutput=Points&output=json&jsonp=RouteCallback&key=" + credentials;
CallRestService(routeRequest);
}
function RouteCallback(result) {
if (result &&
result.resourceSets &&
result.resourceSets.length > 0 &&
result.resourceSets[0].resources &&
result.resourceSets[0].resources.length > 0) {
// Set the map view
var bbox = result.resourceSets[0].resources[0].bbox;
var viewBoundaries = Microsoft.Maps.LocationRect.fromLocations(new Microsoft.Maps.Location(bbox[0], bbox[1]), new Microsoft.Maps.Location(bbox[2], bbox[3]));
map.setView({ bounds: viewBoundaries});
// Draw the route
var routeline = result.resourceSets[0].resources[0].routePath.line;
var routepoints = new Array();
for (var i = 0; i < routeline.coordinates.length; i++) {
routepoints[i]=new Microsoft.Maps.Location(routeline.coordinates[i][0], routeline.coordinates[i][1]);
}
// Draw the route on the map
var routeshape = new Microsoft.Maps.Polyline(routepoints, {strokeColor:new Microsoft.Maps.Color(200,0,0,200)});
map.entities.push(routeshape);
}
}
function CallRestService(request)
{
var script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.setAttribute("src", request);
document.body.appendChild(script);
}
</script>
</head>
<body onload="GetMap();">
<div id='mapDiv' style="position:relative; width:400px; height:400px;"></div>
<input id="txtStart" type="text" value="Seattle"/>
<input id="txtEnd" type="text" value="Portland"/>
<input type="button" value="Calculate Route" onclick="ClickRoute()"/>
</body>
</html>

Categories

Resources