Menu

Simple or Complex Content Values

SourceForge Editorial Staff

Simple or Complex Content Values

Closed: 1/13/09

The Problem

A couple of components in the Gumbo SDK support data properties that translate into visual content in the component's skin. In many of these cases, we'd like to support a few different uses out of the box. Specifically:

  1. Allow the user to set the value to a simple string which turns into a piece of text in the UI. For example:

    <button content="hello, world">
    </button><button>
    <content>
    Hello, World
    </content>
    </button>

  2. Allow the user to set the value to a single visual component (UIComponent or GraphicElement) which gets placed directly in the UI, like so:

    <button>
    <content>

    </content>
    </button>

    <button content="@Embed('...')">

    </button>
  3. Allow the user to set the value to an array of visual components which get directly placed in the UI, like so:

    <button>
    <content>


    </content>
    </button>

  4. lastly, allow the user to set the value to a mix of visual components and simple data:

    <button>
    <content>

    Hello, World
    </content>
    </button>

initial possible solutions

multiple optional parts

Pro: easy to implement
Con: complicates des/dev contract
Con: requires additional code, parts on every data
Con: requires different skins to support different simple data vs. complex content

single part of type group, component converts data.

have the component convert data into visual content before assigning it as the content pushed into the group.

Pro: single skin can support all use cases
Con: puts an extra overhead on every component, since a simple piece of text becomes a group and text.
Con: simple skin development is complicated, since thermo users have to understand they must create a group as the label of a button, not text.
Con: every component that wants to support this functionality needs to reproduce this code.

single part of type DataGroup (or extended Group)

have Group and/or DataGroup accept data as content and automatically turn it into a text component.

Pro: single skin can support all use cases.
Pro: functionality becomes free for any component that wants it.
Con: puts an extra overhead on every component, since a simple piece of text becomes a group and text.
Con: simple skin development is complicated, since thermo users have to understand they must create a group as the label of a button, not text.
Con: either buttons become dependant on DataGroup, or Group becomes more complicated because it's not so simple anymore to just say that Group can only support visual elements.

single property of type IDataRenderer.

Group/DataGroup, text, and other data based components (numericStepper, e.g.) will implement IDataRenderer.

  • probably need additional metadata for Thermo to 'suggest' a part type.
  • if we want support for single unified skin, would still require either string->text component support in Group, DataGroup, or doing the conversion in the component.

Pro: single skin can support all use cases.
Pro: Thermo user can create simple text based skins.
Con: single unified skins puts an extra overhead on every component, since a simple piece of text becomes a group and text. But it's possible to create simplified skins.
Con: either buttons become dependant on DataGroup, or Group becomes more complicated because it's not so simple anymore to just say that Group can only support visual elements.

Do not support this

Don't support complex content in our default components and skins. Supply base classes that make no assumptions about part types, and allow customers (and ourselves) to create alternate implementations that support complex content.

  • would probably require us to add icon support to button.

'placeholder' support in MXML

  • add specific support for a 'content' tag in MXML. The content tag is not a component in its own right, but a placeholder for where a value should be inserted into the hierarchy.
  • either have support for converting a string into a text component in Group/Skin, or have the component convert the string into a text component before passing it off to the mxml.

binding support into the middle of a content array.

  • instead of a content tag, allow a developer to put binding in the middle of the content of a skin or Group. Otherwise, the same as the previous example.\

Summary of Meeting and Conclusion 1/13/2009

\

1) our general policy when it comes to parts is that a component should identify the minimum contract it requires with the part,  find the most generic type that implements that contract, and define that part as that type.

2) there are a few places in our components where we've identified a particular pattern: the component is passing through a particular piece of data to a particular part in order to render (and possibly edit?) it in the UI, but the component has no particular contract with the part other than it be able to accept a generic piece of data. Specifically, the component doesn't particularly care what the type of the data is.

3) we currently don't have any particular type that can support this generic contract.  I.e., there is no way for a component to say 'my part must be something that can render data.'  Or even 'my part must be something that can render strings' or 'render numbers', etc. IDataRenderer could surve this purpose, but our components that typically serve as parts don't implement this interface.  So our components are forced to choose a more restrictive type than they need to for their part.

4) in places where we've run into this problem (specifically: the label of a button, the header of a panel), the best solution we've come up with so far is:
    - the component exposes a generic, untyped property that a developer can set.
    - the component also exposes a specific, typed property that represents the 80% use case (a button exposes a label property, which is of type string).
    - the component requires a part of the most generic type it can define for the 80% use case. The part is optional. If set, the component passes the property into the part, otherwise it's a no-op.
    - for the 20% use case, a developer is free to not define the optional part, and use binding to assign the generic untyped property to some other piece of the skin.

5) a better solution would be:
    - have all of our component which can render some piece of data implement IDataRenderer.
    - have our components gracefully degrade when their data property is assigned some type they don't recognize.
    - have our components that run into this pattern define a part typed as IDataRenderer.  It automatically assigns the generic data field to the data property of the part.
    - add some metadata to hint to the tool what component should be used to fulfill the part contract in the 80% use case.
    - Roughly speaking, text components, buttons, ranges, Groups, and dataGroups would all implement IDataRenderer.
    - we know components with more complex data models, like checkboxes that have both a boolean and a label, or a range that has min,max, and current, would present a problem.  Ideally, if we had a full data story, those components could accept complex structs as the value of their data property that encompassed everything in their datamodel.

6) the problem with this use case is that it means the data property will be assymetrical.  If you assign the data property of a TextGraphic a string, you might get back a TextFlow.

7) This solution allows us to have a simpler API, and a more consistent way to pass data from the component to the skin, regardless of the type.  It also potentially scales in the future to scenarios where more than just a value is being passed…when the value can be modified and needs to be committed, when validation errors need to be propegated to the UI, etc.

The solution does _not_ allow us to have a single skin that can handle arbitrary types.  To do that, we would need some polymorphic component that could render arbitrary data types in different ways.  I.e., a component that acted as a group when handed visual elements, or as a TextBox when handed a string.  That is something that could be added later.

8) generally speaking, we don't think the solution is justified based on its use cases, the amount of work required, and our current schedule. The down side, unfortunately, is that if we want to add support for this in the future, we may need to change some APIs in an incompatible way. Specifically, the part responsible for rendering the label of a button would need its type broadened.

Conclusion:\

We will continue with the current plan of defining optional text control parts to render the data from a button or a panel according to the 80% use case. 
in the meantime, We should remove the content property of button, since it is redundant with the data property. Data should be bindable, and label should be a bindable façade on the data property.


Related

Wiki: Flex 4

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.