Clone a Server-based FeatureLayer to a local one?

1347
11
10-08-2010 06:34 AM
CharlieRichman
New Contributor
I'd like to populate a new local FeatureLayer (via its featureCollection) to match the features in a server-based FeatureLayer.  Any suggestions on a clean way do that? 

Clearly you can't grab the featureCollection from the source layer -- it's null.  Am I better off running a query against the source layer, or grabbing its graphicsProvider info?  (And how do you create a query that returns all records, anyway?)

Ideally I'd preserver symbology as well...

Thanks, folks.

Charlie Richman
DC Office of Planning
Tags (2)
0 Kudos
11 Replies
DasaPaddock
Esri Regular Contributor
You could create a FeatureCollection with a FeatureSet that gets its features from another layer's graphicProvider and the layerDefinition from the other layer's layerDetails property. Could you explain the use case?
0 Kudos
CharlieRichman
New Contributor
You could create a FeatureCollection with a FeatureSet that gets its features from another layer's graphicProvider and the layerDefinition from the other layer's layerDetails property.


That's exactly what I've been trying to do, but I obviously don't have all the right pieces just yet.  (Actually, it's not clear if I should grab the features from the graphicProvider or just run a query to fetch all of the records directly.)

Our jurisdiction has somewhat atypical redistricting needs.  I'd like to create a simple app that lets decisionmakers experiment with assignments of census geographies to Wards.  It would not do to have a shared featureclass editable by all participants with last-one-wins results, and it's not practical to create separate services for each scenario and each participant.  Instead, I'd like to give each participant their own locally-editable clone of our standard distribution dataset.  After they develop a set of assignments that they like, I'd then propose to export those to a server-based scenario archive.

Thanks for your help!

Charlie Richman
DC Office of Planning
0 Kudos
DasaPaddock
Esri Regular Contributor
Here's a sample that I think meets your needs. It creates a FeatureLayer that can be edited without effecting the server since it's using a FeatureCollection.

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:mx="library://ns.adobe.com/flex/mx"
               xmlns:esri="http://www.esri.com/2008/ags">

    <fx:Script>
        <![CDATA[
            import com.esri.ags.SpatialReference;
            import com.esri.ags.events.FeatureLayerEvent;
            import com.esri.ags.events.LayerEvent;
            import com.esri.ags.layers.supportClasses.FeatureCollection;
            import com.esri.ags.tasks.supportClasses.Query;

            protected function fl1_loadHandler(event:LayerEvent):void
            {
                var query:Query = new Query();
                query.outSpatialReference = new SpatialReference(102100);
                query.where = "1 = 1";
                fl1.queryFeatures(query);
            }

            protected function fl1_queryFeaturesCompleteHandler(event:FeatureLayerEvent):void
            {
                var featureCollection:FeatureCollection = new FeatureCollection();
                featureCollection.featureSet = event.featureSet;
                featureCollection.layerDefinition = event.featureLayer.layerDetails;
                fl2.featureCollection = featureCollection;
            }
        ]]>
    </fx:Script>

    <fx:Declarations>
        <esri:FeatureLayer id="fl1"
                           load="fl1_loadHandler(event)"
                           queryFeaturesComplete="fl1_queryFeaturesCompleteHandler(event)"
                           url="http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Earthquakes/EarthquakesFromLastSevenDays/MapServer/0"/>
    </fx:Declarations>

    <esri:Map id="map">
        <esri:ArcGISTiledMapServiceLayer url="http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"/>
        <esri:FeatureLayer id="fl2"/>
    </esri:Map>

</s:Application>
0 Kudos
CharlieRichman
New Contributor
Thanks.  This is very promising.

Much like the complaint in http://forums.arcgis.com/threads/14836-Feature-Layers-do-not-have-all-attributes, though, I don't seem to be getting all the attributes back that I expect from my query.  I have tried setting query.outFields=["TRACTCE00","BG","persons", "hispanic","black","Ward"] and also omitting that statement; it makes no difference in the outcome.  I've also tried pointing at both map service and feature services.  The specified fields ARE present in the source data -- here are extracts from the service descriptions:

Map service

�?� OBJECTID (Type: esriFieldTypeOID, Alias: OBJECTID)
�?� FID_1 (Type: esriFieldTypeInteger, Alias: FID_1)
�?� STATEFP (Type: esriFieldTypeString, Alias: STATEFP, Length: 2 )
�?� STATENS (Type: esriFieldTypeString, Alias: STATENS, Length: 8 )
�?� COUNTYFP (Type: esriFieldTypeString, Alias: COUNTYFP, Length: 3 )
�?� STATEFP00 (Type: esriFieldTypeString, Alias: STATEFP00, Length: 2 )
�?� COUNTYFP00 (Type: esriFieldTypeString, Alias: COUNTYFP00, Length: 3 )
�?� TRACTCE00 (Type: esriFieldTypeString, Alias: TRACTCE00, Length: 6 )
�?� BLOCKCE00 (Type: esriFieldTypeString, Alias: BLOCKCE00, Length: 4 )
�?� SUFFIX1CE (Type: esriFieldTypeString, Alias: SUFFIX1CE, Length: 1 )
�?� BLKIDFP (Type: esriFieldTypeString, Alias: BLKIDFP, Length: 17 )
�?� NAME (Type: esriFieldTypeString, Alias: NAME, Length: 11 )
�?� MTFCC (Type: esriFieldTypeString, Alias: MTFCC, Length: 5 )
�?� UR (Type: esriFieldTypeString, Alias: UR, Length: 1 )
�?� UACE (Type: esriFieldTypeString, Alias: UACE, Length: 5 )
�?� FUNCSTAT (Type: esriFieldTypeString, Alias: FUNCSTAT, Length: 1 )
�?� ALAND (Type: esriFieldTypeDouble, Alias: ALAND)
�?� AWATER (Type: esriFieldTypeDouble, Alias: AWATER)
�?� INTPTLAT (Type: esriFieldTypeString, Alias: INTPTLAT, Length: 11 )
�?� INTPTLON (Type: esriFieldTypeString, Alias: INTPTLON, Length: 12 )
�?� BG (Type: esriFieldTypeString, Alias: BG, Length: 12 )
�?� persons (Type: esriFieldTypeInteger, Alias: persons)
�?� hispanic (Type: esriFieldTypeInteger, Alias: hispanic)
�?� black (Type: esriFieldTypeSmallInteger, Alias: black)
�?� Count_ (Type: esriFieldTypeInteger, Alias: Count_)
�?� Sum_H_HL (Type: esriFieldTypeDouble, Alias: Sum_H_HL)
�?� Ward2002 (Type: esriFieldTypeSmallInteger, Alias: Ward2002)
�?� Ward (Type: esriFieldTypeSmallInteger, Alias: Ward)
�?� Shape (Type: esriFieldTypeGeometry, Alias: Shape)
�?� Shape.area (Type: esriFieldTypeDouble, Alias: Shape.area)
�?� Shape.len (Type: esriFieldTypeDouble, Alias: Shape.len)


Feature service

Global ID Field:

Type ID Field: Ward

Fields:
�?� OBJECTID (Type: esriFieldTypeOID, Alias: OBJECTID, Editable: False)
�?� FID_1 (Type: esriFieldTypeInteger, Alias: FID_1, Editable: True)
�?� STATEFP (Type: esriFieldTypeString, Alias: STATEFP, Length: 2, Editable: True)
�?� STATENS (Type: esriFieldTypeString, Alias: STATENS, Length: 8, Editable: True)
�?� COUNTYFP (Type: esriFieldTypeString, Alias: COUNTYFP, Length: 3, Editable: True)
�?� STATEFP00 (Type: esriFieldTypeString, Alias: STATEFP00, Length: 2, Editable: True)
�?� COUNTYFP00 (Type: esriFieldTypeString, Alias: COUNTYFP00, Length: 3, Editable: True)
�?� TRACTCE00 (Type: esriFieldTypeString, Alias: TRACTCE00, Length: 6, Editable: True)
�?� BLOCKCE00 (Type: esriFieldTypeString, Alias: BLOCKCE00, Length: 4, Editable: True)
�?� SUFFIX1CE (Type: esriFieldTypeString, Alias: SUFFIX1CE, Length: 1, Editable: True)
�?� BLKIDFP (Type: esriFieldTypeString, Alias: BLKIDFP, Length: 17, Editable: True)
�?� NAME (Type: esriFieldTypeString, Alias: NAME, Length: 11, Editable: True)
�?� MTFCC (Type: esriFieldTypeString, Alias: MTFCC, Length: 5, Editable: True)
�?� UR (Type: esriFieldTypeString, Alias: UR, Length: 1, Editable: True)
�?� UACE (Type: esriFieldTypeString, Alias: UACE, Length: 5, Editable: True)
�?� FUNCSTAT (Type: esriFieldTypeString, Alias: FUNCSTAT, Length: 1, Editable: True)
�?� ALAND (Type: esriFieldTypeDouble, Alias: ALAND, Editable: True)
�?� AWATER (Type: esriFieldTypeDouble, Alias: AWATER, Editable: True)
�?� INTPTLAT (Type: esriFieldTypeString, Alias: INTPTLAT, Length: 11, Editable: True)
�?� INTPTLON (Type: esriFieldTypeString, Alias: INTPTLON, Length: 12, Editable: True)
�?� BG (Type: esriFieldTypeString, Alias: BG, Length: 12, Editable: True)
�?� persons (Type: esriFieldTypeInteger, Alias: persons, Editable: True)
�?� hispanic (Type: esriFieldTypeInteger, Alias: hispanic, Editable: True)
�?� black (Type: esriFieldTypeSmallInteger, Alias: black, Editable: True)
�?� Count_ (Type: esriFieldTypeInteger, Alias: Count_, Editable: True)
�?� Sum_H_HL (Type: esriFieldTypeDouble, Alias: Sum_H_HL, Editable: True)
�?� Ward2002 (Type: esriFieldTypeSmallInteger, Alias: Ward2002, Editable: True)
�?� Ward (Type: esriFieldTypeSmallInteger, Alias: Ward, Editable: True)


I set a breakpoint in your _queryFeaturesCompleteHandler and inspected the event object.  Although event.featureLayer.layerDetails.fields shows the full collection of fields I am interested in, event.FeatureLayer.features.attributes contains only Name, OBJECTID, and Ward. Of course, once those features are assigned to the local target layer the missing attributes remain missing.


protected function sourceBlock_loadHandler(event:LayerEvent):void
{
  var query:Query = new Query();
  query.outSpatialReference = new SpatialReference(26985);
  query.where = "1 = 1";
  query.outFields=["TRACTCE00","BG","persons", "hispanic","black","Ward"];
  query.returnGeometry = true;
  sourceBlockFeatureLayer.queryFeatures(query);
}
  
protected function sourceBlock_queryFeaturesCompleteHandler(event:FeatureLayerEvent):void
{
  var featureCollection:FeatureCollection = new FeatureCollection();
  featureCollection.featureSet = event.featureSet;
  featureCollection.layerDefinition = event.featureLayer.layerDetails;
  blocks.featureCollection = featureCollection;
  // more code omitted
}
  
 
    <fx:Declarations>
        <!-- s:TraceTarget/ -->
         <esri:FeatureLayer id="sourceBlockFeatureLayer"
     load="sourceBlock_loadHandler(event)"
     queryFeaturesComplete="sourceBlock_queryFeaturesCompleteHandler(event)"
     url="http://opnas01.op.dcgov.priv/ArcGIS/rest/services/webtest/MapServer/3"
  />
    </fx:Declarations>


Regards,

Charlie Richman
DC Office of Planning
0 Kudos
DasaPaddock
Esri Regular Contributor
Try setting the outFields on the sourceBlockFeatureLayer instead. The Query.outFields are not used when querying via a FeatureLayer. If you want all fields, you can use [ "*" ]. If you use a tool like HttpFox, you can verify the outFields parameter in the HTTP request.
0 Kudos
CharlieRichman
New Contributor
That worked, Dasa.  Thanks.

I do see that queryByGeometry doesn't seem to work on that layer.  It might be good to enhance the documentation on that score.  (Right now it only says "Does not support queries that need to be performed on the server, e.g. queries with a where clause.")

  protected function map_mapClickHandler(event:MapMouseEvent):void
            {
                // set the selection query based on the click
                queryByGeometry.geometry = event.mapPoint;
                blocks.selectFeatures(queryByGeometry);
            }

I imagine that I can replicate that functionality by querying the original source layer instead, inspecting the attributes of the feature selected there, and then selecting the features in the locally-hosted featureLayer.  Before I go that route: (1) What are the limitations in the types of selections I can do against the locally-hosted featureLayer?  I wouldn't want to be restricted to selecting by IDs, because as I understand it the local layer gets all new IDs.  (2) Am I right in assuming that the AttributeInspector won't work on a locally-hosted featureLayer?  I can certainly get by without it, but I'll miss the convenience of it.

Many thanks for your very timely assistance!

Charlie Richman
DC Office of Planning
0 Kudos
DasaPaddock
Esri Regular Contributor
1.) You can select features in a FeatureLayer that's using a FeatureCollection using an Extent geometry, objectIds or timeExtent.

2.) The AttributeInspector should work with a FeatureLayer that's using a FeatureCollection.
0 Kudos
CharlieRichman
New Contributor
Thanks again.  Just to clarify, are you saying that I can use the selectFeatures method on my locally-populated featurelayer with a spatial query based on a polygon geometry (that has an extent) but not one based on a point geometry?  If so, I'd probably create an extremely tiny rectangular polygon surrounding my desired search point.  (Also, if so I'd like to suggest enhancing the documentation.)

Charlie Richman
DC Office of Planning
0 Kudos
DasaPaddock
Esri Regular Contributor
Almost... you should use an actual Extent, not a Polygon:
http://help.arcgis.com/en/webapi/flex/apiref/com/esri/ags/geometry/Extent.html
0 Kudos