Edit related records?

3521
15
Jump to solution
12-06-2013 11:18 AM
ionarawilson1
Occasional Contributor III
I need to be able to edit records in a standalone table, so I want to use related records. I am trying to combine the related records sample with the edit attributes sample. However from what I understand I need to use a link to a featureServer to be able to edit records and the example with the related records uses a link to a mapServer. Is it possible to combine both samples to be able to edit records in the related table or is there a better way to edit related records? Thank you for any help!!!

Here are the links to the samples

https://developers.arcgis.com/en/flex/sample-code/attributetable.htm

https://developers.arcgis.com/en/flex/sample-code/related-records.htm
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
BenjaminMercier
New Contributor III
Yes at the origin, the related table is a "Table" and not a "Layer" that's why in the updateFeatureHandler you can't find the objectIdField, because layerDetails = null.
You should use this :
const objectIdField:String = event.featureLayer.tableDetails.objectIdField;


Don't forget to mark the post as answered if you get your answer 😉

Ben

View solution in original post

0 Kudos
15 Replies
BenjaminMercier
New Contributor III
Hi Ionara,

If you really want to use the Attribute table to edit related table in a non spatial table here is some things you could do:
You could cast your standalon table as a Feature Layer:
var url:String = "theURLpathToYourStandaloneTable" //or you can use your feature layer layerDetails informations to get the related table Id.
var yourTable:FeatureLayer = new FeatureLayer(url, null, null) as FeatureLayer ; //Here you're casting the table as a FeatureLayer so it's editable


Then you can use the attribute table sample on the "yourTable" feature layer. In the query you should add a "where clauses" to link the displayed feature layer with the attribute table as :
query.where = "yourTable_displayFeatureLayerID = yourDisplayedFeatureLayerID"; 
where yourTable_displayFeatureLayerID is the foreign key in your standalone table.

If you don't have yet this foreign key, don't forget to make a relationship when you are publishing your service.

Hope this help,
Ben
0 Kudos
ionarawilson1
Occasional Contributor III
Thank you so much for your help Benjamin. I am trying to figure this out and will come back with a few questions. Thank you!
0 Kudos
BenjaminMercier
New Contributor III
Hi,

1 - If you want to edit it, you should use FeatureServer link
2 - If you want you can use AttributeTable. Just put your "yourTable" between <fx:Declarations> :
<fx:Declarations>
 <esri:FeatureLayer id="yourTable" outFields="*" url="http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/FeatureServer/1"/>    
</fx:Declarations>  


3 - Here : http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/FeatureServer/1,
look at the fields, Objectid is the primary key of the related table, sf_311_serviceoid is the foreign key equal to the incidents table objectid

4 - I add some code which select the row in attribute table if there are some rows related to the incidents entity you clicked on the map.

Take a look at the code

<?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:esri="http://www.esri.com/2008/ags"
    pageTitle="Attribute Table">    
            

  <s:layout>
   <s:VerticalLayout gap="0"/>
  </s:layout>
            
  <fx:Script>
   <![CDATA[
   import com.esri.ags.Graphic;
   import com.esri.ags.events.AttributeTableEvent;
   import com.esri.ags.events.FeatureLayerEvent;
   import com.esri.ags.layers.supportClasses.FeatureEditResult;
   import com.esri.ags.layers.supportClasses.FeatureEditResults;
   import com.esri.ags.layers.supportClasses.Field;
   import com.esri.ags.tasks.supportClasses.Query;
   
   import mx.controls.Alert;
   import mx.events.FlexEvent;
   import mx.rpc.AsyncResponder;
   import mx.rpc.Fault;
   
  /* [Bindable] 
   private var urltable:String = "http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/MapServer/1" //or you can use your feature layer layerDetails informations to get the related table Id.
   private var yourTable:FeatureLayer; //Here you're casting the table as a FeatureLayer so it's editable
   
   protected function application1_initializeHandler(event:FlexEvent):void
   {
    yourTable = new FeatureLayer(urltable, null, null) as FeatureLayer;
   }*/
   protected function myMap_clickHandler(event:MouseEvent):void
   {
    if (event.target is Graphic || event.target.parent is Graphic)                
    {                    
     var graphic:Graphic = event.target is Graphic ? Graphic(event.target) : Graphic(event.target.parent);
       var query:Query = new Query;
            query.objectIds = [graphic.attributes[myFeatureLayer.layerDetails.objectIdField]];
     myFeatureLayer.selectFeatures(query, FeatureLayer.SELECTION_NEW);
     myFeatureLayer.addEventListener(FeatureLayerEvent.SELECTION_COMPLETE,myFeatureLayer_SelectionCompleteHandler);
      }
    else
    {
     myFeatureLayer.clearSelection();
     yourTable.clearSelection();
      }
   }
   
   protected function myFeatureLayer_SelectionCompleteHandler(event:FeatureLayerEvent):void
   {
    var query:Query = new Query;
    query.where = "sf_311_serviceoid  = " + myFeatureLayer.selectedFeatures[0].attributes.objectid;
    yourTable.selectFeatures(query, FeatureLayer.SELECTION_NEW);
   }
   
   protected function fdg_updateFeatureHandler(event:AttributeTableEvent):void
   {
   //TODO
   }
   
   protected function fdg_deleteFeaturesHandler(event:AttributeTableEvent):void
   {                
    //TODO
   }
   
   private function featureLayer_editsCompleteHandler(featureEditResults:FeatureEditResults, token:Object = null):void            
   {               
            //TODO
   }
   
   private function featureLayer_faultHandler(fault:Fault, token:Object = null):void
   {                
    Alert.show(fault.faultString, "Fault");
    myAttributeTable.refresh();
   }        
   

  ]]>    
   

</fx:Script>

<fx:Declarations>
 
 <esri:FeatureLayer id="yourTable" outFields="*" url="http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/FeatureServer/1"/>    
</fx:Declarations>            
            
  <s:controlBarContent>        
   <s:RichText width="100%">
    This sample demonstrates how to use the AttributeTable component which allows viewing and editing feature atttributes.
     The component uses a data grid where the columns correspond to the fields of a feature layer.
     The application also allows user to click on a feature and select it. The AttributeTable then displays the selection
     by highlighting the corresponding row in the grid.
          
   </s:RichText>    
  </s:controlBarContent>
  <esri:Map id="myMap"
   width="100%" height="60%"
   click="myMap_clickHandler(event)">        
   <esri:extent>            
    <esri:Extent id="sheepfire" xmin="-13638587" ymin="4543797" xmax="-13620242" ymax="4549912">                
     <esri:SpatialReference wkid="102100"/>            
    </esri:Extent>        
   </esri:extent>        
   <esri:ArcGISTiledMapServiceLayer url="http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"/>        
   <esri:FeatureLayer id="myFeatureLayer" mode="onDemand" outFields="*" url="http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/FeatureServer/0"/>    
       
  </esri:Map>
  <s:Line width="100%">        
   <s:stroke>            
    <s:SolidColorStroke color="0x000000" weight="1"/>        
   </s:stroke>    
  </s:Line>
  <s:BorderContainer width="100%" height="40%"
      backgroundColor="0xEEEEEE"
      borderVisible="false">        
   <s:layout>            
    <s:HorizontalLayout paddingLeft="5" paddingRight="5" paddingTop="2"/>        
   </s:layout>        
   <esri:AttributeTable 
    id="myAttributeTable"
    width="100%" height="100%"
    deleteFeatures="fdg_deleteFeaturesHandler(event)"
    featureLayer="{yourTable}"
    updateFeature="fdg_updateFeatureHandler(event)">            
   </esri:AttributeTable>    
  </s:BorderContainer>
           
 </s:Application>
0 Kudos
ionarawilson1
Occasional Contributor III
This is great Benjamin. Thank you so much. Do you know why the changes are not being saved (displayed on the table)?
<?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:esri="http://www.esri.com/2008/ags"
    pageTitle="Attribute Table">    
  
  
  <s:layout>
   <s:VerticalLayout gap="0"/>
  </s:layout>
  
  <fx:Script>
   <![CDATA[
    import com.esri.ags.Graphic;
    import com.esri.ags.events.AttributeTableEvent;
    import com.esri.ags.events.FeatureLayerEvent;
    import com.esri.ags.layers.supportClasses.FeatureEditResult;
    import com.esri.ags.layers.supportClasses.FeatureEditResults;
    import com.esri.ags.layers.supportClasses.Field;
    import com.esri.ags.tasks.supportClasses.Query;
    
    import mx.controls.Alert;
    import mx.events.FlexEvent;
    import mx.rpc.AsyncResponder;
    import mx.rpc.Fault;
    
    /* [Bindable] 
    private var urltable:String = "http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/MapServer/1" //or you can use your feature layer layerDetails informations to get the related table Id.
    private var yourTable:FeatureLayer; //Here you're casting the table as a FeatureLayer so it's editable
    
    protected function application1_initializeHandler(event:FlexEvent):void
    {
    yourTable = new FeatureLayer(urltable, null, null) as FeatureLayer;
    }*/
    protected function myMap_clickHandler(event:MouseEvent):void
    {
     if (event.target is Graphic || event.target.parent is Graphic)                
     {                    
      var graphic:Graphic = event.target is Graphic ? Graphic(event.target) : Graphic(event.target.parent);
      var query:Query = new Query;
      query.objectIds = [graphic.attributes[myFeatureLayer.layerDetails.objectIdField]];
      myFeatureLayer.selectFeatures(query, FeatureLayer.SELECTION_NEW);
      myFeatureLayer.addEventListener(FeatureLayerEvent.SELECTION_COMPLETE,myFeatureLayer_SelectionCompleteHandler);
     }
     else
     {
      myFeatureLayer.clearSelection();
      yourTable.clearSelection();
     }
    }
    
    protected function myFeatureLayer_SelectionCompleteHandler(event:FeatureLayerEvent):void
    {
     var query:Query = new Query;
     query.where = "sf_311_serviceoid  = " + myFeatureLayer.selectedFeatures[0].attributes.objectid;
     yourTable.selectFeatures(query, FeatureLayer.SELECTION_NEW);
    }
    
    protected function fdg_updateFeatureHandler(event:AttributeTableEvent):void
    {
     const attributes:Object = {};
     const objectIdField:String = event.featureLayer.layerDetails.objectIdField;
     attributes[objectIdField] = event.feature.attributes[objectIdField];
     attributes[event.field.name] = event.newValue;
     
     // change the attributes on client right away
     event.feature.attributes[event.field.name] = event.newValue;
     
     const feature:Graphic = new Graphic(null, null, attributes);
     const updates:Array = [ feature ];
     event.featureLayer.applyEdits(null, updates, null, false,
      new AsyncResponder(featureLayer_editsCompleteHandler, featureLayer_faultHandler,
       { feature: event.feature, field: event.field, oldValue: event.oldValue }));
    }
    
    protected function fdg_deleteFeaturesHandler(event:AttributeTableEvent):void
    {
     const deletes:Array = event.features;
     event.featureLayer.applyEdits(null, null, deletes, false,
      new AsyncResponder(featureLayer_editsCompleteHandler, featureLayer_faultHandler));
    }
    
    private function featureLayer_editsCompleteHandler(featureEditResults:FeatureEditResults, token:Object = null):void
    {
     var doRefresh:Boolean = false;
     
     for each (var deleteResult:FeatureEditResult in featureEditResults.deleteResults)
     {
      if (deleteResult.success === false)
      {
       Alert.show("Could not delete feature");
       doRefresh = true;
      }
     }
     
     for each (var updateResult:FeatureEditResult in featureEditResults.updateResults)
     {
      const feature:Graphic = token.feature;
      if (updateResult.success === false)
      {
       Alert.show("Could not update feature, Restoring old value", "Error");
       
       const field:Field = token.field;
       feature.attributes[field.name] = token.oldValue;
       doRefresh = true;
      }
      else
      {
       feature.refresh();
      }
     }
     
     if (doRefresh)
     {
      myAttributeTable.refresh();
     }
    }
    
    private function featureLayer_faultHandler(fault:Fault, token:Object = null):void
    {
     Alert.show(fault.faultString, "Fault");
     myAttributeTable.refresh();
    }
    
    
   ]]>    
   
   
  </fx:Script>
  
  <fx:Declarations>
   
   <esri:FeatureLayer id="yourTable" outFields="*" url="http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/FeatureServer/1"/>    
  </fx:Declarations>            
  
  <s:controlBarContent>        
   <s:RichText width="100%">
    This sample demonstrates how to use the AttributeTable component which allows viewing and editing feature atttributes.
    The component uses a data grid where the columns correspond to the fields of a feature layer.
    The application also allows user to click on a feature and select it. The AttributeTable then displays the selection
    by highlighting the corresponding row in the grid.
    
   </s:RichText>    
  </s:controlBarContent>
  <esri:Map id="myMap"
   width="100%" height="60%"
   click="myMap_clickHandler(event)">        
   <esri:extent>            
    <esri:Extent id="sheepfire" xmin="-13638587" ymin="4543797" xmax="-13620242" ymax="4549912">                
     <esri:SpatialReference wkid="102100"/>            
    </esri:Extent>        
   </esri:extent>        
   <esri:ArcGISTiledMapServiceLayer url="http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"/>        
   <esri:FeatureLayer id="myFeatureLayer" mode="onDemand" outFields="*" url="http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/FeatureServer/0"/>    
   
  </esri:Map>
  <s:Line width="100%">        
   <s:stroke>            
    <s:SolidColorStroke color="0x000000" weight="1"/>        
   </s:stroke>    
  </s:Line>
  <s:BorderContainer width="100%" height="40%"
      backgroundColor="0xEEEEEE"
      borderVisible="false">        
   <s:layout>            
    <s:HorizontalLayout paddingLeft="5" paddingRight="5" paddingTop="2"/>        
   </s:layout>        
   <esri:AttributeTable 
    id="myAttributeTable"
    width="100%" height="100%"
    deleteFeatures="fdg_deleteFeaturesHandler(event)"
    featureLayer="{yourTable}"
    updateFeature="fdg_updateFeatureHandler(event)">            
   </esri:AttributeTable>    
  </s:BorderContainer>
            
</s:Application>
0 Kudos
BenjaminMercier
New Contributor III
Yes I add the function to do that. You have to fill them.

Substitute the //TODO commentary by the code to do that. I didn't give a look to this code but I guess it should be really close to the one in the attributeTable sample except that you should applyEdits on yourTable and not on myFeatureLayer.

I'm glad that I can help you.
Don't forget to mark the post as "Answered" if you get your answer.

Thanks,

Ben
0 Kudos
ionarawilson1
Occasional Contributor III
yes, I will definitelly need to mark the question as answered. You've been of great help. However, the table is not saving the updates even with the code. It should know which feature layer to update since the event is in the myAttributeTable and the the feature layer for that is "yourTable", right? But it is not being saved. I will start a new thread with this question. Thank you so much again!

<?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:esri="http://www.esri.com/2008/ags"
    pageTitle="Attribute Table">    
  
  
  <s:layout>
   <s:VerticalLayout gap="0"/>
  </s:layout>
  
  <fx:Script>
   <![CDATA[
    import com.esri.ags.Graphic;
    import com.esri.ags.events.AttributeTableEvent;
    import com.esri.ags.events.FeatureLayerEvent;
    import com.esri.ags.layers.supportClasses.FeatureEditResult;
    import com.esri.ags.layers.supportClasses.FeatureEditResults;
    import com.esri.ags.layers.supportClasses.Field;
    import com.esri.ags.tasks.supportClasses.Query;
    
    import mx.controls.Alert;
    import mx.events.FlexEvent;
    import mx.rpc.AsyncResponder;
    import mx.rpc.Fault;
    
    /* [Bindable] 
    private var urltable:String = "http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/MapServer/1" //or you can use your feature layer layerDetails informations to get the related table Id.
    private var yourTable:FeatureLayer; //Here you're casting the table as a FeatureLayer so it's editable
    
    protected function application1_initializeHandler(event:FlexEvent):void
    {
    yourTable = new FeatureLayer(urltable, null, null) as FeatureLayer;
    }*/
    protected function myMap_clickHandler(event:MouseEvent):void
    {
     if (event.target is Graphic || event.target.parent is Graphic)                
     {                    
      var graphic:Graphic = event.target is Graphic ? Graphic(event.target) : Graphic(event.target.parent);
      var query:Query = new Query;
      query.objectIds = [graphic.attributes[myFeatureLayer.layerDetails.objectIdField]];
      myFeatureLayer.selectFeatures(query, FeatureLayer.SELECTION_NEW);
      myFeatureLayer.addEventListener(FeatureLayerEvent.SELECTION_COMPLETE,myFeatureLayer_SelectionCompleteHandler);
     }
     else
     {
      myFeatureLayer.clearSelection();
      yourTable.clearSelection();
     }
    }
    
    protected function myFeatureLayer_SelectionCompleteHandler(event:FeatureLayerEvent):void
    {
     var query:Query = new Query;
     query.where = "sf_311_serviceoid  = " + myFeatureLayer.selectedFeatures[0].attributes.objectid;
     yourTable.selectFeatures(query, FeatureLayer.SELECTION_NEW);
    }
    
    protected function fdg_updateFeatureHandler(event:AttributeTableEvent):void
    {
     const attributes:Object = {};
     const objectIdField:String = event.featureLayer.layerDetails.objectIdField;
     attributes[objectIdField] = event.feature.attributes[objectIdField];
     attributes[event.field.name] = event.newValue;
     
     // change the attributes on client right away
     event.feature.attributes[event.field.name] = event.newValue;
     
     const feature:Graphic = new Graphic(null, null, attributes);
     const updates:Array = [ feature ];
     event.featureLayer.applyEdits(null, updates, null, false,
      new AsyncResponder(featureLayer_editsCompleteHandler, featureLayer_faultHandler,
       { feature: event.feature, field: event.field, oldValue: event.oldValue }));
    }
    
    protected function fdg_deleteFeaturesHandler(event:AttributeTableEvent):void
    {
     const deletes:Array = event.features;
     event.featureLayer.applyEdits(null, null, deletes, false,
      new AsyncResponder(featureLayer_editsCompleteHandler, featureLayer_faultHandler));
    }
    
    private function featureLayer_editsCompleteHandler(featureEditResults:FeatureEditResults, token:Object = null):void
    {
     var doRefresh:Boolean = false;
     
     for each (var deleteResult:FeatureEditResult in featureEditResults.deleteResults)
     {
      if (deleteResult.success === false)
      {
       Alert.show("Could not delete feature");
       doRefresh = true;
      }
     }
     
     for each (var updateResult:FeatureEditResult in featureEditResults.updateResults)
     {
      const feature:Graphic = token.feature;
      if (updateResult.success === false)
      {
       Alert.show("Could not update feature, Restoring old value", "Error");
       
       const field:Field = token.field;
       feature.attributes[field.name] = token.oldValue;
       doRefresh = true;
      }
      else
      {
       feature.refresh();
      }
     }
     
     if (doRefresh)
     {
      myAttributeTable.refresh();
     }
    }
    
    private function featureLayer_faultHandler(fault:Fault, token:Object = null):void
    {
     Alert.show(fault.faultString, "Fault");
     myAttributeTable.refresh();
    }
    
    
   ]]>    
   
   
  </fx:Script>
  
  <fx:Declarations>
   
   <esri:FeatureLayer id="yourTable" outFields="*" url="http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/FeatureServer/1"/>    
  </fx:Declarations>            
  
  <s:controlBarContent>        
   <s:RichText width="100%">
    This sample demonstrates how to use the AttributeTable component which allows viewing and editing feature atttributes.
    The component uses a data grid where the columns correspond to the fields of a feature layer.
    The application also allows user to click on a feature and select it. The AttributeTable then displays the selection
    by highlighting the corresponding row in the grid.
    
   </s:RichText>    
  </s:controlBarContent>
  <esri:Map id="myMap"
   width="100%" height="60%"
   click="myMap_clickHandler(event)">        
   <esri:extent>            
    <esri:Extent id="sheepfire" xmin="-13638587" ymin="4543797" xmax="-13620242" ymax="4549912">                
     <esri:SpatialReference wkid="102100"/>            
    </esri:Extent>        
   </esri:extent>        
   <esri:ArcGISTiledMapServiceLayer url="http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"/>        
   <esri:FeatureLayer id="myFeatureLayer" mode="onDemand" outFields="*" url="http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/FeatureServer/0"/>    
   
  </esri:Map>
  <s:Line width="100%">        
   <s:stroke>            
    <s:SolidColorStroke color="0x000000" weight="1"/>        
   </s:stroke>    
  </s:Line>
  <s:BorderContainer width="100%" height="40%"
      backgroundColor="0xEEEEEE"
      borderVisible="false">        
   <s:layout>            
    <s:HorizontalLayout paddingLeft="5" paddingRight="5" paddingTop="2"/>        
   </s:layout>        
   <esri:AttributeTable 
    id="myAttributeTable"
    width="100%" height="100%"
    deleteFeatures="fdg_deleteFeaturesHandler(event)"
    featureLayer="{yourTable}"
    updateFeature="fdg_updateFeatureHandler(event)">            
   </esri:AttributeTable>    
  </s:BorderContainer>
            
</s:Application>
0 Kudos
BenjaminMercier
New Contributor III
Yes at the origin, the related table is a "Table" and not a "Layer" that's why in the updateFeatureHandler you can't find the objectIdField, because layerDetails = null.
You should use this :
const objectIdField:String = event.featureLayer.tableDetails.objectIdField;


Don't forget to mark the post as answered if you get your answer 😉

Ben
0 Kudos
ionarawilson1
Occasional Contributor III
Cool, it worked, thank you so much for your help and expertise!!!
0 Kudos
ionarawilson1
Occasional Contributor III
Hi Benjamin,

A quick question:  I am  using a feature layer from my server so I know the records are related. Is the selection  complete handler supposed to show only the records that are related to that point? Because I changed the function to use my own data but nothing changes in the table when I click the point. All records are being displayed on the table. Is it possible to change the function to make that work? Thank you!!!

 protected function myFeatureLayer_SelectionCompleteHandler(event:FeatureLayerEvent):void
   {
    var query:Query = new Query;
    query.where = "Office = " + myFeatureLayer.selectedFeatures[0].attributes.NAME_SH;
    
    yourTable.selectFeatures(query, FeatureLayer.SELECTION_NEW);
     
    
    
   }
0 Kudos