You’re not hallucinating - sometimes the map you see in your ArcGIS JavaScript application doesn’t look like the one you printed via the Print Service. There are many reasons why this might happen, and one is related to Group Layers.

App vs Printing Group Layers?

You may notice your group layers are working fine in your web application - automatically turning on/off the sub-layers as configured in the map service (for max/min scale dependant display).  Without specifying any additional settings in the web app this will display as it would in ArcGIS Pro/Desktop. However, the Print Service will not use the same approach for printing sub-layers. In short: It’s not always WYSIWYG.

Dynamic Map Service Layers Example Dynamic Map Service Layers Example

For web applications, turning on a group layer to make sub-layers visible is straight forward (if the group isn’t already visible by default). The code below would turn on the ”Points of Interest” and ”Roads” group layers based on the sample image:

DynMapService.setVisibleLayers([0,3]);

Since sub-layer min/max scales are set in this example [as noted in square brackets], as you zoom in/out, different sub-layers will toggle automatically based on their default settings. There is no need to determine which sub-layers are meant to be on/off in your application code.

However… the Print Service doesn’t exactly work the same way.

The Print Service will query the map service’s visible layers (DynMapService.visibleLayers) - in our case, layer 0 and 3 have been coded as the only visible layers. The result of this query will update the JSON web map parameter in the Export Web Map task. Since the sub-layers aren’t included in the JSON string, they will not be available in the export.

Not a Bug

To be clear, the ArcGIS JavaScript API Printing Group Layers issue is technically not a bug. More of a lesson learned and heads-up that you should keep this in mind when writing your application with potential printing requirements. You can completely work around this issue by specifying the sub-layers in your code as well:

DynMapService.setVisibleLayers([0,1,2,3,4,5,6]);

Turning on the sub-layers by code will not override the max/min settings. So specifying as visible should still give the desired results in both the application and printouts. Again, just like turning on/off a layer that is out of scale range in ArcMap will not visually show the layer if outside the min/max range.

Specifying the sub-layers is great if you are controlling the visibility in code, but what about users? If you have a more complicated scenario where you’ve created a Table of Contents only showing the group layers (for users to check on/off). If this is the case, you will need to programmatically find the sub-layers so the Print Service knows to request them. Here are a few ways to accomplish this:

Method 1: All layers and sub-layers in one request

Get the structure of all layers in the map service, including group layers and sub-layers (if exist). A benefit of this approach is that you can send one request to the service as the application loads and store the settings for future use. To get the details, use the following syntax:

http://domain/MapService/MapServer?f=json

The result is a JSON object of the entire service including the layers, and sub-layers for a parent (aka group). So we could find the layer ID for Roads (layer id 3), it will have the following sub-layer property:

subLayerIds:[4,5,6]

Method 2: Unique Layer Request for Sub-Layers

If you just want to get the details for a specific layer you can just send the request specifying the layer. This is great if you want to see what type of layer is it (group, feature, etc) and reduce the size of the response (if you have a large/complex map service). Just specify the layer ID including the JSON parameter:

http://domain/MapService/MapServer/3?f=pjson

The returned JSON data will look like the following (more info is available but not shown):

{
  "currentVersion": 10.3,
  "id": 3, "name": "Roads", "type": "Group Layer",
  "description": "", "geometryType": null,
  "copyrightText": "", "parentLayer": null,
  "subLayers":[
    {"id": 4,"name": "Roads - local"},
    {"id": 5,"name": "Roads - mid"},
    {"id": 6,"name": "Roads - overview"}
  ]
...}

Well, that’s about it. If you still think you are hallucinating, maybe ask your roommate what’s in those brownies sitting on the table!?