Technical Articles
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! š¾