@openui5/sap.ui.core
Version:
OpenUI5 Core Library sap.ui.core
395 lines (366 loc) • 11.6 kB
JavaScript
/*!
* OpenUI5
* (c) Copyright 2009-2023 SAP SE or an SAP affiliate company.
* Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
*/
/*eslint-disable max-len */
// Provides an abstract property binding.
sap.ui.define([
'./Binding',
"sap/ui/base/SyncPromise",
"sap/base/Log",
"sap/base/assert",
'./SimpleType', // convenience dependency for legacy code that uses global names
'./DataState' // convenience dependency for legacy code that uses global names
],
function(Binding, SyncPromise, Log, assert) {
"use strict";
/**
* Constructor for PropertyBinding
*
* @abstract
* @class
* The PropertyBinding is used to access single data values in the data model.
*
* @param {sap.ui.model.Model} oModel
* @param {string} sPath
* @param {sap.ui.model.Context} oContext
* @param {object} [mParameters]
*
* @public
* @alias sap.ui.model.PropertyBinding
* @extends sap.ui.model.Binding
*/
var PropertyBinding = Binding.extend("sap.ui.model.PropertyBinding", /** @lends sap.ui.model.PropertyBinding.prototype */ {
constructor : function (oModel, sPath, oContext, mParameters) {
Binding.apply(this, arguments);
},
metadata : {
"abstract" : true,
publicMethods : [
"getValue", "setValue", "setType", "getType", "setFormatter", "getFormatter", "getExternalValue", "setExternalValue", "getBindingMode"
]
}
});
// the 'abstract methods' to be implemented by child classes
/**
* Returns the current value of the bound target
*
* @function
* @name sap.ui.model.PropertyBinding.prototype.getValue
* @return {any} the current value of the bound target
*
* @public
*/
/**
* Sets the value for this binding. A model implementation should check if the current default
* binding mode permits setting the binding value, and if so, set the new value in the model,
* too.
*
* @function
* @name sap.ui.model.PropertyBinding.prototype.setValue
* @param {any} vValue the value to set for this binding
*
* @public
*/
/**
* Returns a value formatted using the given function.
*
* @param {function} fnFormat The function to format the value
* @returns {any} The formatted value
*
* @private
*/
PropertyBinding.prototype._getBoundValue = function(fnFormat) {
var vValue = this.getValue();
return fnFormat(vValue);
};
/**
* Sets a value, after it has been parsed and validated using the given function
*
* @param {any} vValue
* The value to set for this binding
* @param {function} fnParse
* The function to parse the value
*
* @returns {Promise|undefined}
* A promise to set the value; <code>undefined</code> if the binding has no type
*
* @throws sap.ui.model.ParseException
* @throws sap.ui.model.ValidateException
*
* @private
*/
PropertyBinding.prototype._setBoundValue = function(vValue, fnParse) {
var oDataState = this.getDataState(),
that = this;
if (this.oType) {
return SyncPromise.resolve(vValue).then(function(vValue) {
return fnParse(vValue);
}).then(function(vValue) {
return SyncPromise.all([vValue, that.oType.validateValue(vValue)]);
}).then(function(aResult) {
return aResult[0];
}).then(function(vValue) {
oDataState.setInvalidValue(undefined);
that.setValue(vValue);
}).catch(function(oException) {
oDataState.setInvalidValue(vValue);
that.checkDataState(); //data ui state is dirty inform the control
throw oException;
}).unwrap();
} else {
oDataState.setInvalidValue(undefined);
that.setValue(vValue);
return undefined;
}
};
/**
* Convert raw to external representation.
*
* @param {any} vValue Raw value
* @return {any} External value
* @private
*/
PropertyBinding.prototype._rawToExternal = function(vValue) {
if (this.oType) {
vValue = this.oType.formatValue(vValue, this.sInternalType);
}
if (this.fnFormatter) {
vValue = this.fnFormatter(vValue);
}
return vValue;
};
/**
* Convert external to raw representation.
*
* @param {any} vValue External value
* @return {any} Raw value
* @private
*/
PropertyBinding.prototype._externalToRaw = function(vValue) {
// formatter doesn't support two way binding
if (this.oType) {
vValue = this.oType.parseValue(vValue, this.sInternalType);
}
return vValue;
};
/**
* Convert raw to internal representation.
*
* @param {any} vValue Raw value
* @return {any} Internal value
* @private
*/
PropertyBinding.prototype._rawToInternal = function(vValue) {
var oFormat;
if (this.oType && vValue !== null && vValue !== undefined) {
oFormat = this.oType.getModelFormat();
assert(oFormat && typeof oFormat.parse === "function", "The input format of " + this.oType + " should be an object with the 'parse' method");
vValue = oFormat.parse(vValue);
}
return vValue;
};
/**
* Convert internal to raw representation
* @param {any} vValue Internal value
* @return {any} Raw value
* @private
*/
PropertyBinding.prototype._internalToRaw = function(vValue) {
var oFormat;
if (vValue !== null && vValue !== undefined) {
oFormat = this.oType.getModelFormat();
assert(oFormat && typeof oFormat.format === "function", "The model format of " + this.oType + " should be an object with the 'format' method");
vValue = oFormat.format(vValue);
}
return vValue;
};
/**
* Returns the current external value of the bound target which is formatted via a type or
* formatter function.
*
* @throws sap.ui.model.FormatException
*
* @return {any} the current value of the bound target
*
* @public
*/
PropertyBinding.prototype.getExternalValue = function() {
switch (this.sInternalType) {
case "raw":
return this.getRawValue();
case "internal":
return this.getInternalValue();
default:
return this._getBoundValue(this._rawToExternal.bind(this));
}
};
/**
* Sets the value for this binding. The value is parsed and validated against its type and then
* set to the binding. A model implementation should check if the current default binding mode
* permits setting the binding value, and if so, set the new value in the model, too.
*
* @param {any} vValue The value to set for this binding
* @return {undefined|Promise} A promise in case of asynchronous type parsing or validation
* @throws sap.ui.model.ParseException
* @throws sap.ui.model.ValidateException
*
* @public
*/
PropertyBinding.prototype.setExternalValue = function(vValue) {
switch (this.sInternalType) {
case "raw":
return this.setRawValue(vValue);
case "internal":
return this.setInternalValue(vValue);
default:
if (this.fnFormatter) {
Log.warning("Tried to use twoway binding, but a formatter function is used");
return undefined;
}
return this._setBoundValue(vValue, this._externalToRaw.bind(this));
}
};
/**
* Returns the related JavaScript primitive value of the bound target which is parsed by the
* {@link sap.ui.model.SimpleType#getModelFormat model format} of this binding's type. If this
* binding doesn't have a type, the original value which is stored in the model is returned.
*
* This method will be used when targetType is set to "internal" or when it's included in a
* {@link sap.ui.model.CompositeBinding CompositeBinding} and the CompositeBinding needs to have
* the related JavaScript primitive values for its type or formatter.
*
* @return {any}
* The value which is parsed by the model format of the bound target, or the original value in
* case of no type.
*
* @public
*/
PropertyBinding.prototype.getInternalValue = function() {
return this._getBoundValue(this._rawToInternal.bind(this));
};
/**
* Sets the value for this binding with the related JavaScript primitive type. The value is
* formatted with the {@link sap.ui.model.SimpleType#getModelFormat model format} and validated
* against its type and then set to the model.
*
* @param {any} vValue
* The value to set for this binding
* @returns {Promise|undefined}
* A promise to set the value; <code>undefined</code> if the binding has no type
*
* @throws sap.ui.model.ValidateException
*
* @public
*/
PropertyBinding.prototype.setInternalValue = function(vValue) {
return this._setBoundValue(vValue, this._internalToRaw.bind(this));
};
/**
* Returns the raw model value, as it exists in the model dataset.
*
* This method will be used when targetType of a binding is set to "raw" or when it's include
* in a {@link sap.ui.model.CompositeBinding CompositeBinding} and the CompositeBinding needs to
* have the related JavaScript primitive values for its type or formatter.
*
* @return {any}
* The value which is parsed by the model format of the bound target, or the original value in
* case of no type.
*
* @public
*/
PropertyBinding.prototype.getRawValue = function() {
return this._getBoundValue(function(vValue) {
return vValue;
});
};
/**
* Sets the value for this binding with the raw model value. This setter will perform type
* validation, in case a type is defined on the binding.
*
* @param {any} vValue
* The value to set for this binding
* @returns {Promise|undefined}
* A promise to set the value; <code>undefined</code> if the binding has no type
*
* @throws sap.ui.model.ValidateException
*
* @public
*/
PropertyBinding.prototype.setRawValue = function(vValue) {
return this._setBoundValue(vValue, function(vValue) {
return vValue;
});
};
/**
* Sets the optional type and internal type for the binding. The type and internal type are used
* to do the parsing/formatting correctly. The internal type is the property type of the element
* which the value is formatted to.
*
* @param {sap.ui.model.Type} oType
* The type for the binding
* @param {string} sInternalType
* The internal type of the element property which this binding is bound against.
*
* @public
*/
PropertyBinding.prototype.setType = function(oType, sInternalType) {
this.oType = oType;
this.sInternalType = sInternalType;
};
/**
* Returns the type (if any) for the binding.
* @returns {sap.ui.model.Type} The binding type
* @public
*/
PropertyBinding.prototype.getType = function() {
return this.oType;
};
/**
* Sets the optional formatter function for the binding.
*
* @param {function} fnFormatter The formatter function for the binding
*
* @public
*/
PropertyBinding.prototype.setFormatter = function(fnFormatter) {
this.fnFormatter = fnFormatter;
};
/**
* Returns the formatter function.
* @returns {Function} The formatter function
* @public
*/
PropertyBinding.prototype.getFormatter = function() {
return this.fnFormatter;
};
/**
* Returns the binding mode.
* @returns {sap.ui.model.BindingMode} The binding mode
* @public
*/
PropertyBinding.prototype.getBindingMode = function() {
return this.sMode;
};
/**
* Sets the binding mode.
* @param {sap.ui.model.BindingMode} sBindingMode The binding mode
* @protected
*/
PropertyBinding.prototype.setBindingMode = function(sBindingMode) {
this.sMode = sBindingMode;
};
/**
* Resumes the binding update. Change events will be fired again.
*
* When the binding is resumed and the control value was changed in the meantime, the control
* value will be set to the current value from the model and a change event will be fired.
* @public
*/
PropertyBinding.prototype.resume = function() {
this.bSuspended = false;
this.checkUpdate(true);
};
return PropertyBinding;
});