Select to view content in your preferred language

Navigation toolbar buttons work once only

3495
9
10-22-2010 07:16 AM
TimRourke
Emerging Contributor
My current customer uses jQuery as their standard for web scripting, so we try to use Dojo only when it's absolutely necessary for ArcGIS JavaScript API functions to work. I've implemented a toolbar with buttons for functions including pan, zoom in, zoom out, etc. The buttons' click events call functions in a map script; these functions look like this:

pan: function ()
{
    navToolbar.deactivate();
    activeToolButton = "pan";
    navToolbar.activate(esri.toolbars.Navigation.PAN);
},

zoomIn: function ()
{
    navToolbar.deactivate();
    activeToolButton = "zoomin";
    navToolbar.activate(esri.toolbars.Navigation.ZOOM_IN);
},

zoomOut: function ()
{
    navToolbar.deactivate();
    activeToolButton = "zoomout";
    navToolbar.activate(esri.toolbars.Navigation.ZOOM_OUT);
}
This works OK - the first time anyone uses the zoom in or zoom out. The second time they try to click, the map pans while they are drawing the zoom box; the map moves with the cursor and the box expands. When the mouse button is released, the maps zooms, but to the area centered on the first point that was clicked.

The map script does include lines to require the esri toolbar, dojo form Button and Toolbar.
I added the navToolbar.deactivate to try to force the API to act as it is supposed to act, but it hasn't much effect.
I also added a line in the map initialization function to disable the automatic pan but it has no effect at all - with or without the navToolbar.

Is the dojo toolbar required to make this work? Has anyone else seen this kind of behavior and found a workaround?

EDIT:
The workaround I'm using is shown below, but it would be nice to know why our map and toolbar don't behave like the one in the sample. In this workaround I added redundant activation calls to the map extent handler:

function mapExtentChangeHandler()
{
    mapExtentIsFirst = navToolbar.isFirstExtent();
    jQuery('#zoomPrevious').attr('disabled', mapExtentIsFirst);
    mapExtentIsLast = navToolbar.isLastExtent();
    jQuery('#zoomNext').attr('disabled', mapExtentIsLast);
    switch (activeToolButton)
    {
        case "zoomin":
            //navToolbar.activate(esri.toolbars.Navigation.ZOOM_IN);
            zoomInMap(_common.Map);
            break;
 
        case "zoomout":
            navToolbar.activate(esri.toolbars.Navigation.ZOOM_OUT);
            zoomOutMap(_common.Map);
            break;
 
        default:
            navToolbar.activate(esri.toolbars.Navigation.PAN);
            panMap(_common.Map);
            break;
    }
}
0 Kudos
9 Replies
ReneeMaxwell
Regular Contributor
Hello, I'm having exactly the same problem. Did you ever find a solution? I'm also using jQuery.
0 Kudos
TimRourke
Emerging Contributor
Renee,

Here are the functions I've been using successfully to get around this.

dojo.require("dojo.parser");
dojo.require("dojo.cookie");
dojo.require("dijit.form.Button");
dojo.require("dijit.Toolbar");
dojo.require("esri.map");
dojo.require("esri.toolbars.navigation");

/// <summary>Variable to store the keyword for the active button.</summary>
var activeToolButton = "pan";

/// <summary>Variable to hold full extent.</summary>
var _fullExtent;

/// <summary>Variable to hold esri.Map instance.</summary>
var _map;

/// <summary>Flag to indicate whether the current extent is the first in the extent history.</summary>
var mapExtentIsFirst = false;

/// <summary>Flag to indicate whether the current extent is the last in the extent history.</summary>
var mapExtentIsLast = false;
    
function map_Load()
{
    /// <summary>
    /// Function to initialize map, run on map Load event
    /// </summary>
    var startExtent = new esri.geometry.Extent(minX, minY, maxX, maxY, 
                        new esri.SpatialReference({ wkid: spatialReferenceId }));
    _fullExtent = startExtent;
    _map = new esri.Map(mapDivId, {
        extent: startExtent,
        showInfoWindowOnClick: true,
        logo: false
        });
    
    // Set up the navigation toolbar.
    navToolbar = new esri.toolbars.Navigation(map);
    // On each map extent change, call the handler to set the active navigation tool.
    dojo.connect(navToolbar, "onExtentHistoryChange", mapExtentChangeHandler);
}

function mapExtentChangeHandler()
{
    // Dis/enable the Zoom Previous button based on whether the current map 
    // extent is first in the history.
    mapExtentIsFirst = navToolbar.isFirstExtent();
    jQuery('#zoomPrevious').attr('disabled', mapExtentIsFirst);

    // Dis/enable the Zoom Next button based on whether the current map extent 
    // is last in the history.
    mapExtentIsLast = navToolbar.isLastExtent();
    jQuery('#zoomNext').attr('disabled', mapExtentIsLast);

    // Based on the active tool button variable, set the active tool again to 
    // ensure the map navigation functions do not become confused.
    switch (activeToolButton)
    {
        case "zoomin":
            zoomIn();
            break;

        case "zoomout":
            zoomOut();
            break;

        default:
            pan();
            break;
    }
}

function resetMapNavTools()
{
    navToolbar.deactivate();
    map.disablePan();
}

// Tools - these buttons should continue to operate until the user makes 
// another tool selection.
function pan()
{
    resetMapNavTools();
    activeToolButton = "pan";
    navToolbar.activate(esri.toolbars.Navigation.PAN);
}

function zoomIn()
{
    resetMapNavTools();
    activeToolButton = "zoomin";
    navToolbar.activate(esri.toolbars.Navigation.ZOOM_IN);
}

function zoomOut()
{
    resetMapNavTools();
    activeToolButton = "zoomout";
    navToolbar.activate(esri.toolbars.Navigation.ZOOM_OUT);
}

// Commands - these operations should be carried out immediately but not 
// change the active tool.
function zoomToFullExtent()
{
    _map.setExtent(_fullExtent);
}

function zoomToNextExtent()
{
    /// <summary>
    /// Moves the map window to the next extent in the extent history, 
    /// if one exists.
    /// </summary>
    if (!mapExtentIsLast)
    {
        navToolbar.zoomToNextExtent();
    }
}

function zoomToPreviousExtent()
{
    /// <summary>
    /// Moves the map window to the previous extent, if one exists.
    /// </summary>
    if (!mapExtentIsFirst)
    {
        navToolbar.zoomToPrevExtent();
    }
}
It seems that the esri navigation toolbar doesn't quite play well with jQuery and non-digit tools (although I tried using the regular esri toolbar and it didn't work either). What eventually worked was adding the two lines in the resetMapNavTools function above:

    navToolbar.deactivate();
    map.disablePan();
and then calling the command to activate the desired tool. I also set the activeButton variable so I know which one to set when the extent changes and the map seems to forget the active tool.

Hope that helps with your issue. Please let me know if you run into other issues.

Tim
0 Kudos
ReneeMaxwell
Regular Contributor
Tim,

Thanks for the code! I'm trying to implement your workaround but even that doesn't seem to be working for me. I can only get the zoom tools to work the first time. The map keeps trying to perform a simultaneous pan AND zoom with each click of the map.

I'm going to keep playing around with my code. I'll let you know if I find a solution. For some reason all my efforts to disable the Pan tool aren't working.
0 Kudos
ReneeMaxwell
Regular Contributor
I've been checking the value of map.isPan property on each extentChanged event, as well as each tool click and what I'm seeing is that even though that value always returns false (since I've explicitly disabled the pan tool), the zoom tool STILL tries to pan the map.

Pretty strange behavior.
0 Kudos
TimRourke
Emerging Contributor
Renee,

Are you sure the activeToolName is being set? I found that I had a mismatched name the first time I messed with this - because I set the default to pan if the activeToolName wasn't "zoomin" or "zoomout". Of course you can use any names you want for the activeToolName but I went with all lower case so I wouldn't make the mistake again.

Also, whenever I referenced isPan() it always said true, so I stopped using it. I have a superstitious idea that it sets the value to true instead of just returning it.

I see a couple of typos in my code. You may want to try a global replace of "map" with "_map", or vice versa.
0 Kudos
ReneeMaxwell
Regular Contributor
Yes, I checked that property as well and it also returns the correct value. But that doesn't eliminate the problem.

I'm still getting acquainted with the JS API after doing most of my development with the .NET ADF, and I'm really missing a lot of the basic object properties available in the ADF. For example, the Map control had a property for the current active tool. Pretty basic. Sure wish the JS API had it.

I'm very much underwhelmed by the JS API so far. Particularly unimpressed with Dojo, and now I'm becoming increasingly disappointed that the compact API doesn't play well with jQuery as promised.

Also, I haven't upgraded to ArcGIS 10 but I find it kind of unbelievable that a fully functional TOC with a legend isn't a basic feature. Even the new Legend widget in 10 leaves a lot to be desired.

Sorry, just had to vent a bit!
0 Kudos
TimRourke
Emerging Contributor
Renee,

I have to agree that the JSAPI is missing a lot, but I try to remember it's free and a new ESRI product. I expect if it survives it will develop more over time. Judging by the traffic on the web, the Flex and Google versions of the API are getting more attention (though I may just be jealous :)).

I'm struggling too with the API not playing well with jQuery and the lack of useful UI components. I've also found that functions that have worked for weeks will fail all of a sudden; then I'll mess with the code trying to get around whatever changed in the API, and then it will start working for a while again. I wonder if they're not tweaking the code that's live out on CDN. Meanwhile I've wasted almost half a day.

And obtuse error messages like "_59f is not defined" just seem to indicate a lack of consideration for the people who use the API.
0 Kudos
GlenRhea
Emerging Contributor
Regarding mixing js libraries like jquery and dojo, I use jquery on my website and dojo for all the esri stuff. When I have to mix them I put the esri stuff in an iframe, it just makes it so much easier.
0 Kudos
TimRourke
Emerging Contributor
Using an iframe can be easier to build, but some of my customers have network policies that flag iframe scripts as security violations. They see random errors that can't be reproduced off-site.

I've also seen the toolbar problem inside an iframe using nothing but Dojo and the JSAPI in prior versions of the JSAPI.

Despite the current issues, JSAPI 2.1 plays a lot better with jQuery than any previous versions. I've been able to remove several hacks from our script library.
0 Kudos