ArcGIS JS API 3.21 InfoTemplate ZoomIn Button

2763
16
Jump to solution
08-08-2017 08:21 AM
MatthewDewell
New Contributor III

Has anyone had luck attaching a click event to a custom button built in the HTML of the InfoTemplate? Here's my InfoTemplate HTML:

uploadInfoTemplate = new InfoTemplate ({     title: "",     content: "<strong>Segment:</strong> ${segment}" +              "<hr/>" +              "<strong>Time:</strong> <i>${dateTime}</i>" +              "<div style='width: 100%; text-align:right;'>" +                  "<input class='zoomButton' type='button' value='Zoom to' />" +              "</div>" });

I then have hidden items on the default InfoTemplate, i.e. the zoomTo link. I want to simply replace the zoomTo's functionality with a button, to make it look a little nicer.

Tags (1)
0 Kudos
1 Solution

Accepted Solutions
MatthewDewell
New Contributor III

Hello Robert,

I may be looking for using featureLayers in a bit here, but I got the actionList button to work by using some of your suggestion's example:

var zoomButtonHTML = '<div style="width: 100%; text-align: right;"><input type="button" value="Zoom to" /></div>';

var zoomButton = domConstruct.create("div", {

    "class": "action",

    "id": "uploadLink",

    "innerHTML": zoomToButtonHTML

}, query(".actionList", this.map.infoWindow.domNode)[0]);

on(zoomButton, 'click', this._zoomToPoint);

My code then loops through all the points I have to plot, where I pass the zoom Button object to the _pointPlot function for each point.  Wherein, I define my uploadInfoTemplate:

uploadInfoTemplate = new InfoTemplate({

    domNode: zoomButton,

   title: "",

   content: content

});

I guess I'm lucky, I didn't have to go about creating a FeatureLayer, and it seems to have just used the InfoWindow/infoTemplate.  Now, it looks like I'm going to have to go about translating the x/y cords of the graphic to the actual lat/long.  Is that the WebMercator I use?  Oh well.

Thank You ... again,

Matt

Note: I got the idea from Robert's post about the example - Geoprocessing tool link in popup | ArcGIS API for JavaScript 3.21  above.

View solution in original post

0 Kudos
16 Replies
SteveCole
Frequent Contributor

I've done this. The key is making sure the event that gets referenced in the onClick event of the button has a global scope. Here's a screen shot of my infoWindow:

And the code for the infoWindow content formatting function:

SetSwmPopupInfo: function(graphic) {
 var fullAttr = graphic.attributes;
 var rptParam, content, theProjID, theTipType;
 var theCipID = fullAttr.SWM_PRJ_NO;
 
 var features = [];
 features.push(graphic);
 var fSet = new FeatureSet();
 fSet.features = features;
 app.curInfoGraphic = fSet;
 
 rptParam = "'" + graphic.attributes.OBJECTID + ',' + graphic.geometry.type + ',' + "SWM" + "'";
 rptProjectName = graphic.attributes.ProjectName_1;
 
 if (theCipID.length > 1) {
 theProjID = fullAttr.SWM_PRJ_NO;
 } else {
 theProjID = "Unknown";
 }
 
 content = '<table width=\"100%\"><tr><td valign=\'top\' style=\"font-weight:bold;padding-left:3px;padding-right:3px\">Project Name:</td><td valign=\'top\' style=\"padding-left:3px;padding-right:3px\">' + fullAttr.ProjectName_1 + '</td></tr>';
 content = content + '<tr><td valign=\'top\' style=\"font-weight:bold;padding-left:3px;padding-right:3px;vertical-align:top\">CIP Project ID:</td><td valign=\'top\' style=\"padding-left:3px;padding-right:3px;vertical-align:top\">' + theProjID + '</td></tr>';
 content = content + '<tr><td valign=\'top\' style=\"font-weight:bold;padding-left:3px;padding-right:3px;vertical-align:top\">Type of Project:</td><td valign=\'top\' style=\"padding-left:3px;padding-right:3px;vertical-align:top\">' + fullAttr.Category.toProperCase() + '</td></tr>'; 
 content = content + '<tr><td colspan=\"2\"><br/><div style=\"margin:0 auto;display:table;line-height:28px;\"><button id=\"reportButton\" type=\"button\" onclick=\"app.trf.getTractProjectReport(' + rptParam + ')\">View a Summary Demographic Report  (Census Tract Level)</button><br\>';
 content = content + '<button id=\"reportBlockButton\" type=\"button\" onclick=\"app.brf.getBlockProjectReport(' + rptParam + ')\">View a Summary Demographic Report  (Block Group Level)</button></div></td></tr></table><br/>';
 
 return content;
 }

In the onClick tag, I'm specifying app.brf.getBlockProjectReport(arg). App is simply a global array/collection that I use to store values or references to items that I'll need from time to time:

var app = {};

The actual function (getBlockProjectReport) is contained in a custom Dojo Module that I wrote named blockgroupReportFunctions:

require([
 "custom/mapHelp",
 "custom/printMapFunctions",
 "custom/postLoadMapFunctions", 
 "custom/tractReportFunctions", 
 "custom/blockgroupReportFunctions",
.....
], function (
   mapHelp, PrintMapFunctions, PostLoadMapFunctions, tractReportFunctions, blockgroupReportFunctions,.....
( {
    ready(function() {
             ....

when the Dojo Ready function gets triggered, I create a reference to that function inside of my global app collection:

app.pf = new PrintMapFunctions();
 app.mh = new mapHelp();
 app.plmf = new PostLoadMapFunctions();
 app.trf = new tractReportFunctions();
 app.brf = new blockgroupReportFunctions();

...and that finally brings me to the beginning of my response. Now I have a globally accessible reference to the function I want to trigger when the user clicks on the button I created on the fly within my infoWindow.

Steve

MatthewDewell
New Contributor III

Steve,


Thank you for the response.  This looks very promising, I'm using a Dijjit, so I'm not sure where to put this reference to the 'app' object.  The code I'm using goes a little like this:

define([
    "dojo/_base/declare",
    "dijit/_WidgetBase",
    ...a bunch more entries of library paths...
], function (
    declare,
     _WidgetBase,
    ...all the library path variables passed in...
) {
    return declare([_WidgetBase, a few more variable names passed in...],
    {
       ...a bunch of global variables defined...,
        uploadInfoTemplate: "",
        ...a bunch more global variables defined...,

       constructor: function (...) {
            ...
       },

       startup: function () {
           ...

           this.uploadInfoTemplate = new InfoTemplate({
               title: "",
               content: "<strong>Segment:</strong> ${segment}" +
                        "<hr/>" +
                        "<strong>Time:</strong> <i>${dateTime}</i>" +
                        "<div style='width: 100%; text-align:right;'>" +
                            "<input class='zoomButton' type='button' value='Zoom to' />" +
                        "</div>"
               });

        },

        ...

        _plotPoint: function(map, point, graphicsLyr) {

            sms = new SimpleMarkerSymbol()
                      .setStyle(point.symbol)
                      .setSize(point.size)
                      .setColor(point.color);

            if (!isNaN(point.outlineSize) ) {
                sms.Outline(point.outlineSize);
            }

            uploadInfoAttr = {
                "segment":point.data.segment,
                "dateTime":point.data.
            }

            var pinGraphic = new Graphic();
            pinGraphic.setGeometry(point.pt);
            pinGraphic.setSymbol(sms);
            pinGraphic.setAttributes(uploadInfoAttr);
            pinGraphic.setInfoTemplate(uploadInfoTemplate);

            graphicsLayr.add(pinGraphic);

        },
        ... more code
    });
});

I'm curious where I need to place the app._zoomTo definition to go to the _zoomTo: function(){}, and the call I put in the '<input ... onclick="app._zoomTo(' + lat + ',' + long + ')" ... />' to call the _zoom to function.  Any help would be greatly appreciated.

Thanks in advance,

Matt

0 Kudos
SteveCole
Frequent Contributor

The app line would be the first line in your main JS file (listed BEFORE the Dojo require() stuff. This is a technique I learned from this page under the "Avoid Cluttering the Global Namespace" section.

Using the app technique is a great way (for me, at least) to make sure things are accessible within custom modules and from one module to another since variable scope comes into play.

0 Kudos
MatthewDewell
New Contributor III

Hello Steve,

I'm not sure that's going to work in my Dijit, there is no 'require' statement in the 'js' file.  I can declare a global though, and call with a this.variableName, yet how do I call that form the html 'onclick' statement?

Thanks again

0 Kudos
SteveCole
Frequent Contributor

From what you've revealed, I think you're concerned with code related to a specifc DIJIT you're building but my solution lives at a much higher / overall level within an application. As a VERY simplistic example, consider this ESRI sample 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>Simple Map</title>
    <link rel="stylesheet" href="https://js.arcgis.com/3.21/esri/css/esri.css">
    <style>
      html, body, #map {
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
    <script src="https://js.arcgis.com/3.21/"></script>
    <script>
      var map;
      var app = {};

      require(["esri/map", "dojo/domReady!"], function(Map) {
        map = new Map("map", {
          basemap: "topo",  //For full list of pre-defined basemaps, navigate to http://arcg.is/1JVo6Wd
          center: [-122.45, 37.75], // longitude, latitude
          zoom: 13
        });
      });
    </script>
  </head>

  <body>
    <div id="map"></div>
  </body>
</html>‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

The declaration of the app object/collection is one of the first things that occurs within JS. That's what makes it truly global and accessible at any level within your application (even down within the code for your DIJIT). Using "this" only brings you up one coding level which would still be within the context of your DIJIT's JS code. At runtime, your browser wouldn't recognize app as a global variable.

0 Kudos
MatthewDewell
New Contributor III

Hello Steve,

Thanks again for your help on this. The code I'm working with has a lot of Dijits/Widgets and I need to get it going within the Dijit code.  Thus, I can't use a higher level script insert to get it going, I am sorry to say.  The 'onclick' works for just running a function, but it doesn't recognize the external Dijit function(s) I have created.  Is there a way I can access these external functions from with in my Dijit code by putting in a call to 'this._zoomTo' using the 'onclick' functionality?

Thanks in advance,

Matt

0 Kudos
MatthewDewell
New Contributor III

I guess my big question is, how can I attach an 'on' event to an InfoWindow object/button from within a dijit.  Is this possible?

0 Kudos
MatthewDewell
New Contributor III

Should I look into doing a popup? It just seems a bit difficult to implement, vs. the success I have had of getting an infoTemplate to show up.  I just need to know how to detect the action of the button being clicked within the infoTemplate so that I can add an action to it, that would call a function in the dijit.

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Matthew,

   You may want to completely re-think your workflow.

Here is a sample of how to add a custom link to the popup:

Geoprocessing tool link in popup | ArcGIS API for JavaScript 3.21 

In this sample the actionlist of the popup dijit is queried and the custom link is added. You can do the same thing adding a button instead.

0 Kudos