Select to view content in your preferred language

Default Attribute Inspector Dropdownlists too narrow.. how to set width wider?

2624
7
01-20-2011 08:28 AM
RoyceSimpson
Frequent Contributor
I've got an attribute inspector with some default dropdownlists that list preset domain values (stored in the geodatabase).  For whatever reason, those dropdownlists aren't wide enough and cut off the ends of the domain values and add a horizontal scroll bar in the actual dropdownlist of choices.

I'd like to get that component width to be wider and currently have created a separate "dropDownListField" component where I set the width to what I want.  Then I did:

var classFactory:ClassFactory = new ClassFactory(ResourceStatusRenderer);
resourceStatusFI.renderer = classFactory;

resourceStatusFI is the fieldInspector which has the dropdown list.

All works well with the width part of this but now I've lost the actual domain values in the dropdownlist.

I notice that the DropDownListField has a "dataprovider" property but I'm not sure how to set that in this context (or even if I need to).

What am I missing here?
Tags (2)
0 Kudos
7 Replies
RoyceSimpson
Frequent Contributor
I resorted to the following code but can't seem to figure out how to hook up the result to the DropDownListField dataprovider...
    var details:LayerDetails = resourceStatusFI.featureLayer.layerDetails;
    var resourceSatusField:Field;
    
    for each (var field:Field in details.fields)
    {
     if (field.name == "RESOURCESTATUS")
     {
      resourceSatusField = field;
      break;
     }
    }
    
    var resourceStatusDomain:CodedValueDomain = resourceSatusField.domain as CodedValueDomain;
    
    var resourceStatusDataProvider:ArrayCollection = new ArrayCollection(resourceStatusDomain.codedValues);
0 Kudos
RoyceSimpson
Frequent Contributor
So, maybe the best question to ask here is:

How to set the dataprovider of a custom DropDownListField when the field in question is associated to a geodatabase domain?

If the only way to set the renderer for a custom FieldInspector is to do:
var classFactory:ClassFactory = new ClassFactory(DropDownListFieldRenderer);
fieldInspector.renderer = classFactory;

How does the DropDownListFieldRender get its dataprovider set to the desired gdb domain?
0 Kudos
MansourRaad
Esri Contributor
try setting the typicalItem property on your custom drop down list.
0 Kudos
RoyceSimpson
Frequent Contributor
try setting the typicalItem property on your custom drop down list.


Thanks, that actually does a better job of setting the width of the dropdowlistfield than just setting the width explicitly.

I'm still stumped though regarding how to get the dropdownlistfield re-populated.  It seems that when you create a custom renderer, the default dataprovider goes away.  In my case, these dropdownlistfields access the gdb coded value domains associated with the field.

After creating this custom renderer based on the DropDownListField, how can I relink back up the domain values as the dataprovider?
0 Kudos
by Anonymous User
Not applicable
I've been wrestling around with this same problem for a couple of days and I have finally managed to bend this part of the Edit Widget to my will.  It's done through the use of custom skin components.  It gets round the problem of creating renderers for the FieldInspectors and loading them with the domain values at runtime. 

The actual problem ended up being that the component used for the domain dropdown lists is not the DropDownListField as you would expect, but is actually the undocumented CodedValueDomainField (I only found this out because I was stepping though the debug). 

You can create a skin class for this component (even though it doesn't appear in the api documentation or in the IntelliSense), then modify it to alter the width of the dropdown.  I've attached the code for the dropdown that I created below.  It formats the button to the width i wanted (in this case 250).  It also sets the dropdown to 300 (wider than the button) to make sure all the text is displayed (you do this by changing the popUpWidthMatchesAnchorWidth tag in the popUpAnchor to "false").

<?xml version="1.0" encoding="utf-8"?>
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:fb="http://ns.adobe.com/flashbuilder/2009" alpha.disabled=".5"> 
    <fx:Metadata>[HostComponent("com.esri.ags.components.supportClasses.CodedValueDomainField")]</fx:Metadata>

    <!-- host component -->
    <fx:Script fb:purpose="styling">
        <![CDATA[            
            
            /* Define the content fill items that should be colored by the "contentBackgroundColor" style. */
            static private const contentFill:Array = ["bgFill"];
            
            /**
             * @private
             */
            override public function get contentItems():Array {return contentFill};
                        /**
             * @private
             */
            override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
            {
                if (getStyle("borderVisible") == false)
                {
                    if (border)
                        border.visible = false;
                    if (background)
                    {
                        background.left = background.top = background.right = background.bottom = 0;
                    }
                    if (scroller)
                        scroller.minViewportInset = 0;
                }
                else
                {
                    if (border)
                        border.visible = true;
                    if (background)
                    {
                        background.left = background.top = background.right = background.bottom = 1;
                    }
                    if (scroller)
                        scroller.minViewportInset = 1;
                }
                
                if (dropShadow)
                    dropShadow.visible = getStyle("dropShadowVisible");
                
                openButton.setStyle("cornerRadius", getStyle("cornerRadius"));
                
                if (borderStroke)
                {
                    borderStroke.color = getStyle("borderColor");
                    borderStroke.alpha = getStyle("borderAlpha");
                }
                super.updateDisplayList(unscaledWidth, unscaledHeight);
            }
        ]]>
    </fx:Script>
    
    <s:states>
        <s:State name="normal" />
        <s:State name="open" />
        <s:State name="disabled" />
    </s:states>
    
    <s:PopUpAnchor id="popUp"  displayPopUp.normal="false" displayPopUp.open="true" includeIn="open"
        left="0" right="0" top="0" bottom="0" itemDestructionPolicy="auto"
        popUpPosition="below" popUpWidthMatchesAnchorWidth="false">
        
        <s:Group id="dropDown" maxHeight="134" minHeight="22" >
        
            <!--- @private -->
            <s:RectangularDropShadow id="dropShadow" blurX="20" blurY="20" alpha="0.45" distance="7" 
                 angle="90" color="#000000" left="0" top="0" right="0" bottom="0"/>
        
            <!--- @private -->
            <s:Rect id="border" left="0" right="0" top="0" bottom="0">
                <s:stroke>
                    <!--- border stroke @private -->
                    <s:SolidColorStroke id="borderStroke" weight="1"/>
                </s:stroke>
            </s:Rect>
            
            <!-- fill -->
            <!--- Defines the appearance of drop-down list's background fill. -->
            <s:Rect id="background" left="1" right="1" top="1" bottom="1" >
                <s:fill>
                    <s:SolidColor id="bgFill" color="0xFFFFFF" />
                </s:fill>
            </s:Rect>
            
            <!--- @private -->
   <s:Scroller id="scroller" left="0" top="0" width="300" bottom="0" hasFocusableChildren="false" minViewportInset="1">
                <!--- @copy spark.components.SkinnableDataContainer#dataGroup-->
                <s:DataGroup id="dataGroup" itemRenderer="spark.skins.spark.DefaultItemRenderer">
                    <s:layout>
                        <s:VerticalLayout gap="0" horizontalAlign="contentJustify"/>
                    </s:layout>
                </s:DataGroup> 
            </s:Scroller>
        </s:Group>
    </s:PopUpAnchor>
    
    <s:Button id="openButton" left="0" width="250" top="0" bottom="0" focusEnabled="false"
        skinClass="spark.skins.spark.DropDownListButtonSkin" />  
        
    <s:Label id="labelDisplay" verticalAlign="middle" maxDisplayedLines="1" 
        mouseEnabled="false" mouseChildren="false"
        left="7" right="30" top="2" bottom="2" width="75" verticalCenter="1" /> 

</s:SparkSkin>


To apply it to the attribute inspector, there are a couple of techniques I tried that worked.  The first one was to add a style reference to the global CSS file that use this skin class for all TextFields.

What i ended up doing was create a function that I attached to the Show_feature event of the Attribute Inspector in the editor component of the widget.  The key was to look at the form rather than the field inspectors.  The function loops through each of the FormItems, checks the kind of edit component being used to edit it, and applies a skin appropriate to that field editor component.  This is the code I'm using to apply skins that I have created to each of the common editors.


// This adds the event listener to update the editor skins on the form.  I've added it to the WidgetConfigLoaded function

// Add a listener to update the styles on the edit boxes when the records are shown.
editor.attributeInspector.addEventListener(AttributeInspectorEvent.SHOW_FEATURE, setFieldInspectorSkins);



// Applies the Field Editor skins to the edit objects.  Looks directly at the form in the attribute inspector
// then looks at each for the formitems and check the component type e.g. TextField, StringField, CodedValueDomainField.
// Finally applies a custom skin to each component based on  the type.
private function  setFieldInspectorSkins(event:AttributeInspectorEvent):void
{
 // Get the number of formitems in the form
 var numRecs:int = editor.attributeInspector.form.numChildren;
 var disp:DisplayObject;
 var chld:DisplayObject;
    
 for (var i:int = 0; i < numRecs; i++)
 {
  disp = editor.attributeInspector.form.getChildAt(i);
  if (disp is FormItem)
  {
   var itm:FormItem = disp as FormItem;
   for (var j:int = 0; j < itm.numChildren; j++)
   {
    chld = itm.getChildAt(j);
    if (chld is StringField)
    {
     var sFld:StringField = chld as StringField;
    sFld.setStyle("skinClass",widgets.EditEnhanced.EditWidgetStringFieldSkin);
     break;
    }
    
    if (chld is com.esri.ags.components.supportClasses.TextField)
    {
     var tFld:com.esri.ags.components.supportClasses.TextField = chld as com.esri.ags.components.supportClasses.TextField;
     tFld.setStyle("skinClass",widgets.EditEnhanced.EditWidgetTextFieldSkin);
     break;
    }
       
    if (chld is com.esri.ags.components.supportClasses.CodedValueDomainField)
    {
     var cFld:CodedValueDomainField = chld as CodedValueDomainField;
     cFld.setStyle("skinClass",widgets.EditEnhanced.EditWidgetCodedValueDomainFieldSkin);
     break;
    }
    
    if (chld is com.esri.ags.components.supportClasses.RangeDomainField)
    {
     var rFld:RangeDomainField = chld as RangeDomainField;
     rFld.setStyle("skinClass",widgets.EditEnhanced.EditWidgetRangeDomainFieldSkin);
     break;
    }

   }
  }
 }
}
0 Kudos
RoyceSimpson
Frequent Contributor
Wow, alrighty then. 
I've actually got a working kludge which involves recreating the dataprovider programatically for the dropdownlistfield.  I had to rebuild the coded value domain list by hand from the layer infos then set the selected index to 0 if it's a new feature or to whatever the current value for that field is, if it's an existing but updated feature.

I don't like that route so I'll certainly explore your solution. 

esri dev, what's your take on this?

Thanks for the input,
-Royce
0 Kudos
RoyceSimpson
Frequent Contributor
And yet, implementing undocumented features has bitten me time and time again. 

com.esri.ags.components.supportClasses.CodedValueDomainField does however explain a lot.

-r
0 Kudos