An issue that has come up a few times when talking to developers using the Oracle JET Composite Component Architecture (CCA) , is that of how to design your properties. You do have a (fairly) free hand when it comes to deciding which properties you want to expose as attributes for your components, but I though that it would be handy to provide some guidance to help steer you in the correct direction.
So let's have a look at the two key areas; naming and sub-properties:
First I wanted to re-itereate the hard requirements that component authors must adhere to as part of the Web-Components standards:
- Custom properties should not redefine any of the global HTMLElement properties (as listed here), this includes properties such as id, title, style etc. Component consumers may still apply those properties to your components when using them, and if needed, you can obtain the applied value from the context.element reference passed into your CCA lifecycle methods.
- You should not define custom properties with the prefix of on* as these may be confused with standard HTMLElement event handlers.
- The first character of your property name should be a lowercase letter and not a number or punctuation character
You'll also want to think about the soft requirements around naming. What I mean here is the process of managing consistency across all the components that you create. I won't mandate any particular set of standards here, but all I would urge is that you look at every new property you add and ask the question does this meet user expectations? A trivial example might be two components both of which have range based properties. If you created one with a property called max and the the other with a property called maximum then you're just a) Making your compoent set look sloppy and b) Requiring consumers to keep checking the doc because they just don't have a predictable pattern to follow.
The Art of Sub-Properties
Sub-properties provide a convenient way for component authors to provide a cleaner API to the component consumers by "hiding" properties under a top level parent property. Needless to say there are some rules to follow in order to use this capability correctly
When To Use Sub-Properties v's Top Level Properties
- Where the relegated sub-properties are infrequently used and have applicable defaults, for example, if a component wants to offer string overrides to the consumer these would be exposed through the translations super-property. The component will function correctly without any of the sub-property values being supplied.
- Where the property value required by the component is a (moderately) complex object, but where the object is still usable if only some key attributes are set. A contrived example of this might be a component that needs to be sent a server reference. That server reference being an object with three attributes: protocol, host and port. We would assume that sensible defaults are in place for protocol and port and so the use of sub-properties allows the consumer to specifically just supply the variant information e.g. server-ref.host="oracle.com". This approach allows your consumers to provide either an object binding for serverRef as a whole, or to cherry-pick the sub-properties that actually need to be set. You should only use sub-properties in this way when there is this semi-default behaviour. Forcing a consumer to enter values for every attribute of a complex object through sub-properties is going to be counter productive and in that case just a single object based property should be used.
What Not to do with Sub-Properties
- As mentioned don't create super-properties that require the consumer to supply a value for every sub-property under the parent - these are verbose to use and you can't have automatic enforcement of required as this applies at the top level object only
- Don't hide important properties within a sub-property. You rule should be that if the setting of a particular property is required to make the component function then it's probably important enough to expose as a top level property. By all means though, hide second level properties as sub-properties as long as they have defined defaults. For example, if you have a complex component with a large number of configuration switches to show or hide various toolbar options, then grouping these under a common super-property would be ideal.
Multiple Sub-properties or a Single Complex Property?
When is it correct to use sub-properties to configure a component verses using a single complex object that the developer has to create in code (in some fashion)?
Having the requirement to be able to set all the attribute values "at once" is not a justification for not using sub-properties as you are still able to do this by setting the super-property value to an object. Also remember that the very act of breaking a complex object into smaller pieces does allow you to provide a much more understandable interface for the consumer. You can describe each bit right there in the component.json rather than having to rely on code samples to illustrate the structure. However, there are some cases where you either can't use sub-properties or perhaps don't need to.
- The complex object is some kind of collection - the sub-property mechanism can describe nested objects but it cannot describe arrays of objects, so if your property is an array of some sort then it needs to be a single object property with the appropriate type defintion
- The complex object is not fixed in terms of it's shape - e.g. some sort of extensible record type that the CCA will introspect and dynamically adapt to
- All of the attributes of the complex object are needed and cannot be defaulted
- Your component is only ever used by developers who already have the information wrapped as a single object - there really may be no-need to unwrap the object or specify the detail of the attributes using sub-properties, that's fine, just don't force the reverse of making a developer having to create a brand new object just in order to pass it to configure your component.
You can always start out with a single complex object property and then explode it into sub-properties at a later date.
If you've just arrived at JET composite components and would like to learn more, then you can access the whole series of articles on the topic from the Composite Component Architecture Learning Path