EDUCAÇÃO E TECNOLOGIA

How to enable Smart Variant Management for Custom Controls

Have you ever wondered how to enable Smart Variant Management for your custom controls?

Then you are lucky because this guide will show you how to do it! ðŸŽ‰

Before we start let’s have a look at the documentation on how to use the Smart Variant Management:

The sap.ui.comp.smartvariants.SmartVariantManagement control provides an interface to enable a simple integration of the sap.ui.comp.variants.VariantManagement control and access to the layered repository of SAPUI5 flexibility for easy communication.

What this simply means is that you can persist the current state of your control and application in the so called Layer Repository as part of the SAPUI5 Flexibility Services using the Smart Variant Management control.

This feature is mainly used by e.g. Smart Filter Bar or Smart Table but can also be implemented by any custom control.

So let’s get started by creating a new XML Composite Control:

InputWithSmartVariantManagement.control.xml

<core:FragmentDefinition xmlns:core="sap.ui.core" xmlns="sap.m"> <Input id="idInput" width="{$this>width}" value="{$this>value}" change="onChange"/>
</core:FragmentDefinition>

InputWithSmartVariantManagement.js

sap.ui.define([ 'sap/ui/core/XMLComposite', 'sap/base/Log'
], ( XMLComposite, Log
) => XMLComposite.extend('com.sap.example.InputWithSmartVariantManagement', { metadata: { properties: { width: { type: 'sap.ui.core.CSSSize', defaultValue: null, invalidate: true }, value: { type: 'string', defaultValue: null, invalidate: true } }, events: { change: { value: { type: 'string' } } } }, init (...args) { XMLComposite.prototype.init.apply(this, args) this.log = Log.getLogger(this.getMetadata().getName()) this.input = this.byId('idInput') }, exit (...args) { XMLComposite.prototype.exit.apply(this, args) this.log = null this.input = null }, onChange () { const value = this.getValue() this.fireChange({ value }) }
}))

With this in place the first step is now to get a reference to our SmartVariantManagement instance.

We can do this by adding an association smartVariant to our control:

 associations: { smartVariant: { type: 'sap.ui.comp.smartvariants.SmartVariantManagement', multiple: false } },

Next we have to register and initialize our control with the SmartVariantManagement instance whenever the association is being set.

We can do this by overriding the generated setSmartVariant method which is just a shorthand for this.setAssociation(‘smartVariant’, smartVariant):

 setSmartVariant (smartVariant) { this._registerSmartVariantManagement(smartVariant) this._initialiseSmartVariantManagement() return this.setAssociation('smartVariant', smartVariant) },

In _registerSmartVariantManagement we simply resolve the association and get the actual reference to the SmartVariantManagement instance:

_registerSmartVariantManagement (smartVariant) { if (!smartVariant) { return } if (typeof smartVariant === 'string') { this.smartVariantManagement = sap.ui.getCore().byId(smartVariant) } else if (smartVariant instanceof SmartVariantManagement) { this.smartVariantManagement = smartVariant } else { this.log.error('Invalid association: smartVariant', JSON.stringify(smartVariant)) } },

In _initialiseSmartVariantManagement we have to create a PersonalizibleInfo instance for our control and add this to the corresponding aggregation of the SmartVariantManagement instance.

Finally we have to call SmartVariantManagement.initialise.

It is important to mention here that the approach using the initialise event which is still being described in the documentation has been deprecated as of SAPUI5 1.38.0.

_initialiseSmartVariantManagement () { if (!this.smartVariantManagement) { return } const oPersonalizableInfo = new PersonalizableInfo({ type: 'control', // can be any type!? SmartTable sets 'table' here keyName: 'persistencyKey', // must match the control's property name dataSource: 'TODO' // can be any type!? e.g. SmartTable sets 'TODO' here }) oPersonalizableInfo.setControl(this) this.smartVariantManagement.addPersonalizableControl(oPersonalizableInfo) this.smartVariantManagement.initialise(() => this.onInitialiseVariant(), this) }, onInitialiseVariant () { // noop },

The last step is now to implement the interface methods which will be called by the SmartVariantManagement instance to fetch and apply the variant for our custom control.

 variantsInitialized () { // noop }, fetchVariant () { const value = this.getValue() const variant = { value } return variant }, applyVariant (variant = null) { this.variant = variant const variantValue = this.variant?.value const value = this.getValue() if (variantValue && variantValue !== value) { this.setValue(variantValue) this.onChange() } },

Additionally we need to mark the SmartVariantManagement instance as modified whenever our input value changes.

The SmartVariantManagement instance will highlight this by showing a * (asterisk).

 onChange () { const value = this.getValue() const variantValue = this.variant?.value if (this.smartVariantManagement && variantValue !== value) { this.smartVariantManagement.currentVariantSetModified(true) } this.fireChange({ value }) }

All put together the final implementation for our custom control will look like this:

sap.ui.define([ 'sap/ui/core/XMLComposite', 'sap/base/Log', 'sap/ui/comp/smartvariants/SmartVariantManagement', 'sap/ui/comp/smartvariants/PersonalizableInfo'
], ( XMLComposite, Log, SmartVariantManagement, PersonalizableInfo
) => XMLComposite.extend('com.sap.example.InputWithSmartVariantManagement', { metadata: { properties: { width: { type: 'sap.ui.core.CSSSize', defaultValue: null, invalidate: true }, value: { type: 'string', defaultValue: null, invalidate: true }, persistencyKey: { type: 'string', defaultValue: null, invalidate: true } }, associations: { smartVariant: { type: 'sap.ui.comp.smartvariants.SmartVariantManagement', multiple: false } }, events: { change: { value: { type: 'string' } } } }, init (...args) { XMLComposite.prototype.init.apply(this, args) this.log = Log.getLogger(this.getMetadata().getName()) this.input = this.byId('idInput') this.smartVariantManagement = null }, exit (...args) { XMLComposite.prototype.exit.apply(this, args) this.log = null this.input = null this.smartVariantManagement = null }, setSmartVariant (smartVariant) { this._registerSmartVariantManagement(smartVariant) this._initialiseSmartVariantManagement() return this.setAssociation('smartVariant', smartVariant) }, _registerSmartVariantManagement (smartVariant) { if (!smartVariant) { return } if (typeof smartVariant === 'string') { this.smartVariantManagement = sap.ui.getCore().byId(smartVariant) } else if (smartVariant instanceof SmartVariantManagement) { this.smartVariantManagement = smartVariant } else { this.log.error('Invalid association: smartVariant', JSON.stringify(smartVariant)) } }, _initialiseSmartVariantManagement () { if (!this.smartVariantManagement) { return } const personalizableInfo = new PersonalizableInfo({ type: 'control', keyName: 'persistencyKey', dataSource: 'TODO' }) personalizableInfo.setControl(this) this.smartVariantManagement.addPersonalizableControl(personalizableInfo) this.smartVariantManagement.initialise(() => this.onInitialiseVariant(), this) }, onInitialiseVariant () { // noop }, variantsInitialized () { // noop }, fetchVariant () { const value = this.getValue() const variant = { value } return variant }, applyVariant (variant = null) { this.variant = variant const variantValue = this.variant?.value const value = this.getValue() if (variantValue && variantValue !== value) { this.setValue(variantValue) this.onChange() } }, onChange () { const value = this.getValue() const variantValue = this.variant?.value if (this.smartVariantManagement && variantValue !== value) { this.smartVariantManagement.currentVariantSetModified(true) } this.fireChange({ value }) }
}))

And to conclude here is an example of how the SmartVariantManagement and the custom control will work together:

<core:FragmentDefinition xmlns:core="sap.ui.core" xmlns:smartvariants="sap.ui.comp.smartvariants" xmlns:example="com.sap.example" xmlns="sap.m"> <smartvariants:SmartVariantManagement id="idSmartVariantManagement" persistencyKey="pKeyPageVariantManagement" lifecycleSupport="true" showExecuteOnSelection="true" showShare="true"/> <example:InputWithSmartVariantManagement id="idInputWithSmartVariantManagement" width="6rem" smartVariant="idSmartVariantManagement" persistencyKey="pKeyInputWithSmartVariantManagement" change="onChange"/>
</core:FragmentDefinition>

👾 Happy Coding! 👾