@openui5/sap.ui.core
Version:
OpenUI5 Core Library sap.ui.core
878 lines (818 loc) • 31.4 kB
JavaScript
/*!
* OpenUI5
* (c) Copyright 2026 SAP SE or an SAP affiliate company.
* Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
*/
//Provides class sap.ui.model.odata.v4.ODataPropertyBinding
sap.ui.define([
"./Context",
"./ODataBinding",
"./lib/_Cache",
"./lib/_Helper",
"sap/base/Log",
"sap/ui/base/SyncPromise",
"sap/ui/model/BindingMode",
"sap/ui/model/ChangeReason",
"sap/ui/model/PropertyBinding"
], function (Context, asODataBinding, _Cache, _Helper, Log, SyncPromise, BindingMode, ChangeReason,
PropertyBinding) {
"use strict";
/*eslint max-nested-callbacks: 0 */
var sClassName = "sap.ui.model.odata.v4.ODataPropertyBinding",
aImmutableEmptyArray = Object.freeze([]),
mSupportedEvents = {
AggregatedDataStateChange : true,
change : true,
dataReceived : true,
dataRequested : true,
DataStateChange : true
},
sVirtualPath = "/" + Context.VIRTUAL, // a snippet indicating a virtual path
/**
* @alias sap.ui.model.odata.v4.ODataPropertyBinding
* @author SAP SE
* @class Property binding for an OData V4 model.
* An event handler can only be attached to this binding for the following events:
* 'AggregatedDataStateChange', 'change', 'dataReceived', 'dataRequested' and
* 'DataStateChange'. For unsupported events, an error is thrown.
* @extends sap.ui.model.PropertyBinding
* @hideconstructor
* @mixes sap.ui.model.odata.v4.ODataBinding
* @public
* @since 1.37.0
* @version 1.146.0
* @borrows sap.ui.model.odata.v4.ODataBinding#getGroupId as #getGroupId
* @borrows sap.ui.model.odata.v4.ODataBinding#getRootBinding as #getRootBinding
* @borrows sap.ui.model.odata.v4.ODataBinding#getUpdateGroupId as #getUpdateGroupId
* @borrows sap.ui.model.odata.v4.ODataBinding#hasPendingChanges as #hasPendingChanges
* @borrows sap.ui.model.odata.v4.ODataBinding#isInitial as #isInitial
* @borrows sap.ui.model.odata.v4.ODataBinding#refresh as #refresh
* @borrows sap.ui.model.odata.v4.ODataBinding#requestRefresh as #requestRefresh
* @borrows sap.ui.model.odata.v4.ODataBinding#resetChanges as #resetChanges
* @borrows sap.ui.model.odata.v4.ODataBinding#toString as #toString
*/
ODataPropertyBinding
= PropertyBinding.extend("sap.ui.model.odata.v4.ODataPropertyBinding", {
constructor : constructor
});
//*********************************************************************************************
// ODataPropertyBinding
//*********************************************************************************************
/**
* Do <strong>NOT</strong> call this private constructor, but rather use
* {@link sap.ui.model.odata.v4.ODataModel#bindProperty} instead!
*
* @param {sap.ui.model.odata.v4.ODataModel} oModel
* The OData V4 model
* @param {string} sPath
* The binding path in the model; must not end with a slash
* @param {sap.ui.model.Context} [oContext]
* The context which is required as base for a relative path
* @param {object} [mParameters]
* Map of binding parameters
* @throws {Error}
* If disallowed binding parameters are provided
*/
function constructor(oModel, sPath, oContext, mParameters) {
PropertyBinding.call(this, oModel, sPath);
// initialize mixin members
asODataBinding.call(this);
if (sPath.endsWith("/")) {
throw new Error("Invalid path: " + sPath);
}
this.mScope = undefined;
if (mParameters) {
if (typeof mParameters.scope === "object") {
this.mScope = mParameters.scope;
mParameters = {...mParameters};
delete mParameters.scope;
}
this.checkBindingParameters(mParameters,
["$$groupId", "$$ignoreMessages", "$$noPatch"]);
this.sGroupId = mParameters.$$groupId;
this.bNoPatch = mParameters.$$noPatch;
this.setIgnoreMessages(mParameters.$$ignoreMessages);
} else {
this.sGroupId = undefined;
this.bNoPatch = false;
}
if (this.sPath === "@$ui5.context.isSelected") {
this.bNoPatch = true;
}
this.oCheckUpdateCallToken = undefined;
this.oContext = oContext;
this.bHasDeclaredType = undefined; // whether the binding info declares a type
this.bInitial = true;
// Note: system query options supported at property binding only for ".../$count"
this.mQueryOptions = this.oModel.buildQueryOptions(_Helper.clone(mParameters),
/*bSystemQueryOptionsAllowed*/sPath.endsWith("$count"));
this.vValue = undefined;
// BEWARE: #doFetchOrGetQueryOptions uses #isRoot which relies on this.oContext!
this.fetchCache(oContext);
oModel.bindingCreated(this);
}
asODataBinding(ODataPropertyBinding.prototype);
/**
* The 'change' event is fired when the binding is initialized or refreshed or its type is
* changed or its parent context is changed. It is to be used by controls to get notified about
* changes to the value of this property binding. Registered event handlers are called with the
* change reason as parameter.
*
* @param {sap.ui.base.Event} oEvent
* The event object
* @param {function():Object<any>} oEvent.getParameters
* Function which returns an object containing all event parameters
* @param {sap.ui.model.ChangeReason} oEvent.getParameters.reason
* The reason for the 'change' event could be
* <ul>
* <li> {@link sap.ui.model.ChangeReason.Change Change} when the binding is initialized,
* when it gets a new type via {@link #setType}, or when the data state is reset via
* {@link sap.ui.model.odata.v4.ODataModel#resetChanges},
* {@link sap.ui.model.odata.v4.ODataContextBinding#resetChanges},
* {@link sap.ui.model.odata.v4.ODataListBinding#resetChanges} or {@link #resetChanges},
* <li> {@link sap.ui.model.ChangeReason.Refresh Refresh} when the binding is refreshed,
* <li> {@link sap.ui.model.ChangeReason.Context Context} when the parent context is
* changed.
* </ul>
*
* @event sap.ui.model.odata.v4.ODataPropertyBinding#change
* @public
* @since 1.37.0
*/
/**
* The 'dataReceived' event is fired after the back-end data has been processed and the
* registered 'change' event listeners have been notified. It is only fired for GET requests.
* The 'dataReceived' event is to be used by applications for example to switch off a busy
* indicator or to process an error.
*
* If back-end requests are successful, the event has almost no parameters. For compatibility
* with {@link sap.ui.model.Binding#event:dataReceived 'dataReceived'}, an event parameter
* <code>data : {}</code> is provided: "In error cases it will be undefined", but otherwise it
* is not. Use {@link #getValue() oEvent.getSource().getValue()} to access the response data.
* Note that controls bound to this data may not yet have been updated, meaning it is not safe
* for registered event handlers to access data via control APIs.
*
* If a back-end request fails, the 'dataReceived' event provides an <code>Error</code> in the
* 'error' event parameter.
*
* @param {sap.ui.base.Event} oEvent
* The event object
* @param {function():Object<any>} oEvent.getParameters
* Function which returns an object containing all event parameters
* @param {object} [oEvent.getParameters.data]
* An empty data object if a back-end request succeeds
* @param {Error} [oEvent.getParameters.error] The error object if a back-end request failed.
* If there are multiple failed back-end requests, the error of the first one is provided.
*
* @event sap.ui.model.odata.v4.ODataPropertyBinding#dataReceived
* @public
* @since 1.37.0
*/
/**
* The 'dataRequested' event is fired directly after data has been requested from a back end.
* It is only fired for GET requests. The 'dataRequested' event is to be used by applications
* for example to switch on a busy indicator. Registered event handlers are called without
* parameters.
*
* @param {sap.ui.base.Event} oEvent
*
* @event sap.ui.model.odata.v4.ODataPropertyBinding#dataRequested
* @public
* @since 1.37.0
*/
/**
* See {@link sap.ui.base.EventProvider#attachEvent}
*
* @param {string} sEventId The identifier of the event to listen for
* @param {object} [_oData]
* @param {function} [_fnFunction]
* @param {object} [_oListener]
* @returns {this} <code>this</code> to allow method chaining
*
* @public
* @see sap.ui.base.EventProvider#attachEvent
* @since 1.37.0
*/
// @override sap.ui.base.EventProvider#attachEvent
ODataPropertyBinding.prototype.attachEvent = function (sEventId, _oData, _fnFunction,
_oListener) {
if (!(sEventId in mSupportedEvents)) {
throw new Error("Unsupported event '" + sEventId
+ "': v4.ODataPropertyBinding#attachEvent");
}
return PropertyBinding.prototype.attachEvent.apply(this, arguments);
};
/**
* Updates the binding's value and sends a change event if necessary. A change event is sent
* if the <code>bForceUpdate</code> parameter is set to <code>true</code> or if the value
* has changed unless the request to read the new value has been cancelled by a later request.
* If a relative binding has no context the <code>bForceUpdate</code> parameter
* is ignored and the change event is only fired if the old value was not
* <code>undefined</code>.
* If the binding has no type, the property's type is requested from the meta model and set.
* Note: The change event is only sent asynchronously after reading the binding's value and
* type information.
* If the binding's path cannot be resolved or if reading the binding's value fails or if the
* value read is invalid (e.g. not a primitive value), the binding's value is reset to
* <code>undefined</code>. As described above, this may initiate a change event depending on the
* previous value and the <code>bForceUpdate</code> parameter. In the end the data state is
* checked (see {@link sap.ui.model.PropertyBinding#checkDataState}) even if there is no change
* event. If there are multiple synchronous <code>checkUpdateInternal</code> calls the data
* state is checked only after the last call is processed.
*
* @param {boolean} [bForceUpdate]
* If <code>true</code> the change event is always fired except there is no context for a
* relative binding and the (old and new) value is <code>undefined</code>. If
* <code>undefined</code> a change event is also fired in case the data state contains control
* messages, see {@link sap.ui.model.DataState#getControlMessages}.
* @param {sap.ui.model.ChangeReason} [sChangeReason=ChangeReason.Change]
* The change reason for the change event
* @param {string} [sGroupId=getGroupId()]
* The group ID to be used for the read.
* @param {boolean} [bPreventBubbling]
* Whether the dataRequested and dataReceived events related to the refresh must not be
* bubbled up to the model
* @param {any} [vValue]
* The new value obtained from the cache, see {@link #onChange}
* @returns {sap.ui.base.SyncPromise<void>}
* A promise which is resolved without a defined result when the check is finished, or
* rejected in case of an error. If the cache is no longer the active cache when the response
* arrives, that response is ignored almost silently (that is, with a canceled error) and the
* value remains unchanged.
*
* @private
* @see sap.ui.model.PropertyBinding#checkDataState
*/
// @override sap.ui.model.odata.v4.ODataBinding#checkUpdateInternal
ODataPropertyBinding.prototype.checkUpdateInternal = function (bForceUpdate, sChangeReason,
sGroupId, bPreventBubbling, vValue) {
var bDataRequested = false,
iHashHash = this.sPath.indexOf("##"),
bIsMeta = iHashHash >= 0,
oMetaModel = this.oModel.getMetaModel(),
mParametersForDataReceived = {data : {}},
sResolvedPath = this.getResolvedPath(),
oCallToken = {
// a resolved binding fires a change event if checkUpdateInternal is called at least
// once with bForceUpdate=true; an unresolved binding only fires if it had a value
// before
forceUpdate : sResolvedPath
&& (bForceUpdate
|| bForceUpdate === undefined
&& this.getDataState().getControlMessages().length > 0
|| this.oCheckUpdateCallToken && this.oCheckUpdateCallToken.forceUpdate)
},
vType = this.oType, // either the type or a promise resolving with it
that = this;
this.oCheckUpdateCallToken = oCallToken;
if (!vType && sResolvedPath && this.sInternalType !== "any" && !bIsMeta
&& !sResolvedPath.includes(sVirtualPath)) {
vType = oMetaModel.fetchUI5Type(this.sReducedPath || sResolvedPath);
}
if (vValue === undefined) {
// if called via #onChange, we need to fetch implicit values
vValue = this.oCachePromise.then(function (oCache) {
var sDataPath, sMetaPath;
if (oCache) {
return oCache.fetchValue(that.lockGroup(sGroupId || that.getGroupId()),
/*sPath*/undefined, function () {
bDataRequested = true;
that.fireDataRequested(bPreventBubbling);
}, that)
.then(function (vResult) {
that.checkSameCache(oCache);
return vResult;
});
}
if (!that.isResolved()) {
return undefined;
}
if (sResolvedPath.includes(sVirtualPath)) {
// below virtual context: no change event
oCallToken.forceUpdate = false;
}
if (!bIsMeta) { // relative data binding
return that.oContext.fetchValue(that.sReducedPath, that);
} // else: metadata binding
sDataPath = that.sPath.slice(0, iHashHash);
sMetaPath = that.sPath.slice(iHashHash + 2);
if (sMetaPath[0] === "/") {
sMetaPath = "." + sMetaPath;
}
return oMetaModel.fetchObject(sMetaPath,
oMetaModel.getMetaContext(that.oModel.resolve(sDataPath, that.oContext)),
that.mScope && {scope : that.mScope});
}).then(function (vValue0) {
if (!vValue0 || typeof vValue0 !== "object") {
return vValue0;
}
if (that.sInternalType === "any" && (that.getBindingMode() === BindingMode.OneTime
|| !bIsMeta && (that.getBindingMode() === BindingMode.OneWay
|| that.sPath[that.sPath.lastIndexOf("/") + 1] === "#"))) {
if (bIsMeta) {
return vValue0;
}
if (that.bRelative) {
return _Helper.publicClone(vValue0);
}
}
Log.error("Accessed value is not primitive", sResolvedPath, sClassName);
}, function (oError) {
that.oModel.reportError("Failed to read path " + sResolvedPath, sClassName, oError);
if (oError.canceled) { // canceled -> value remains unchanged
oCallToken.forceUpdate = false;
return that.vValue;
}
mParametersForDataReceived = {error : oError};
// oError is re-thrown below
});
if (bForceUpdate && vValue.isFulfilled()) {
if (vType && vType.isFulfilled && vType.isFulfilled()) {
this.doSetType(vType.getResult());
}
this.vValue = vValue.getResult();
}
// Use Promise to become async so that only the latest sync call to checkUpdateInternal
// wins
vValue = Promise.resolve(vValue);
} else if (vValue && typeof vValue === "object") {
vValue = _Helper.publicClone(vValue);
}
return SyncPromise.all([vValue, vType]).then(function (aResults) {
var oType = aResults[1],
vValue0 = aResults[0];
if (oCallToken === that.oCheckUpdateCallToken) { // latest call to checkUpdateInternal
that.oCheckUpdateCallToken = undefined;
that.doSetType(oType);
if (oCallToken.forceUpdate || that.vValue !== vValue0) {
that.bInitial = false;
that.vValue = vValue0;
that._fireChange({reason : sChangeReason || ChangeReason.Change});
}
that.checkDataState();
}
if (bDataRequested) {
that.fireDataReceived(mParametersForDataReceived, bPreventBubbling);
}
if (mParametersForDataReceived.error) {
throw mParametersForDataReceived.error;
}
});
};
/**
* Destroys the object. The object must not be used anymore after this function was called.
*
* @public
* @see sap.ui.model.Binding#destroy
* @since 1.39.0
*/
// @override sap.ui.model.Binding#destroy
ODataPropertyBinding.prototype.destroy = function () {
this.oModel.bindingDestroyed(this);
this.oCheckUpdateCallToken = undefined;
this.mQueryOptions = undefined;
this.mScope = undefined;
this.vValue = undefined;
asODataBinding.prototype.destroy.call(this);
PropertyBinding.prototype.destroy.apply(this, arguments);
};
/**
* @override
* @see sap.ui.model.odata.v4.ODataBinding#doCreateCache
*/
ODataPropertyBinding.prototype.doCreateCache = function (sResourcePath, mQueryOptions) {
return _Cache.createProperty(this.oModel.oRequestor, sResourcePath, mQueryOptions);
};
/**
* @override
* @see sap.ui.model.odata.v4.ODataBinding#doFetchOrGetQueryOptions
*/
ODataPropertyBinding.prototype.doFetchOrGetQueryOptions = function () {
return this.isRoot() ? this.mQueryOptions : undefined;
};
/**
* Sets the given type for this binding while keeping its internal type.
*
* @param {sap.ui.model.Type} oType
* The type for this binding
*
* @private
* @see sap.ui.model.PropertyBinding#setType
*/
ODataPropertyBinding.prototype.doSetType = function (oType) {
PropertyBinding.prototype.setType.call(this, oType, this.sInternalType);
};
/**
* @override
* @see sap.ui.model.odata.v4.ODataBinding#getDependentBindings
*/
ODataPropertyBinding.prototype.getDependentBindings = function () {
return aImmutableEmptyArray;
};
/**
* @override
* @see sap.ui.model.odata.v4.ODataBinding#getResumePromise
*/
ODataPropertyBinding.prototype.getResumePromise = function () {};
/**
* Returns the current value.
*
* @returns {any}
* The current value
*
* @public
* @see sap.ui.model.PropertyBinding#getValue
* @since 1.37.0
*/
ODataPropertyBinding.prototype.getValue = function () {
return this.vValue;
};
/**
* Determines which type of value list exists for this property.
*
* @returns {sap.ui.model.odata.v4.ValueListType}
* The value list type
* @throws {Error}
* If the binding is unresolved (see {@link sap.ui.model.Binding#isResolved}), if the metadata
* is not loaded yet or if the property cannot be found in the metadata
*
* @public
* @since 1.45.0
*/
ODataPropertyBinding.prototype.getValueListType = function () {
var sResolvedPath = this.getResolvedPath();
if (!sResolvedPath) {
throw new Error(this + " is unresolved");
}
return this.getModel().getMetaModel().getValueListType(sResolvedPath);
};
/**
* @override
* @see sap.ui.model.odata.v4.ODataBinding#hasPendingChangesInDependents
*/
ODataPropertyBinding.prototype.hasPendingChangesInDependents = function () {
return false;
};
/**
* @override
* @see sap.ui.model.Binding#initialize
*/
ODataPropertyBinding.prototype.initialize = function () {
if (this.isResolved()) {
if (this.isRootBindingSuspended()) {
this.sResumeChangeReason = ChangeReason.Change;
} else {
this.checkUpdate(true);
}
}
};
/**
* @override
* @see sap.ui.model.odata.v4.ODataBinding#isMeta
*/
ODataPropertyBinding.prototype.isMeta = function () {
return this.sPath.includes("##");
};
/**
* Change handler for the cache. The cache calls this method when the value is changed.
*
* @param {any} vValue
* The new value
* @param {boolean} [bForceUpdate]
* Update the bound control even if no data have been changed.
*
* @private
*/
ODataPropertyBinding.prototype.onChange = function (vValue, bForceUpdate) {
this.checkUpdateInternal(bForceUpdate, undefined, undefined, false, vValue)
.catch(this.oModel.getReporter());
};
/**
* @override
* @see sap.ui.model.odata.v4.ODataBinding#onDelete
*/
ODataPropertyBinding.prototype.onDelete = function () {
// nothing to do
};
/**
* @override
* @see sap.ui.model.odata.v4.ODataBinding#refreshInternal
*/
ODataPropertyBinding.prototype.refreshInternal = function (_sResourcePathPrefix, sGroupId,
bCheckUpdate, bKeepCacheOnError) {
var that = this;
if (this.isRootBindingSuspended()) {
this.refreshSuspended(sGroupId);
return SyncPromise.resolve();
}
return this.oCachePromise.then(function () {
if (that.oCache && that.oCache.reset) {
that.oCache.reset();
} else {
that.fetchCache(that.oContext, false, /*bKeepQueryOptions*/true, sGroupId,
bKeepCacheOnError);
}
if (bCheckUpdate) {
return that.checkUpdateInternal(undefined, ChangeReason.Refresh, sGroupId,
/*bPreventBubbling*/bKeepCacheOnError);
}
});
};
/**
* Requests the value of the property binding.
*
* @returns {Promise<any|undefined>}
* A promise resolved with the resulting value or <code>undefined</code> if it could not be
* determined, or rejected in case of an error
*
* @public
* @since 1.69.0
*/
ODataPropertyBinding.prototype.requestValue = function () {
var that = this;
return Promise.resolve(this.checkUpdateInternal(false).then(function () {
return that.getValue();
}));
};
/**
* Requests information to retrieve a value list for this property.
*
* @param {boolean} [bAutoExpandSelect]
* The value of the parameter <code>autoExpandSelect</code> for value list models created by
* this method. If the value list model is this binding's model, this flag has no effect.
* Supported since 1.68.0
* @returns {Promise<Object<object>>}
* See {@link sap.ui.model.odata.v4.ODataMetaModel#requestValueListInfo}
* @throws {Error}
* If the binding is unresolved (see {@link sap.ui.model.Binding#isResolved})
*
* @public
* @since 1.45.0
*/
ODataPropertyBinding.prototype.requestValueListInfo = function (bAutoExpandSelect) {
var sResolvedPath = this.getResolvedPath();
if (!sResolvedPath) {
throw new Error(this + " is unresolved");
}
return this.getModel().getMetaModel()
.requestValueListInfo(sResolvedPath, bAutoExpandSelect, this.oContext);
};
/**
* Determines which type of value list exists for this property.
*
* @returns {Promise<sap.ui.model.odata.v4.ValueListType>}
* A promise that is resolved with the type of the value list. It is rejected if the property
* cannot be found in the metadata.
* @throws {Error}
* If the binding is unresolved (see {@link sap.ui.model.Binding#isResolved})
*
* @public
* @since 1.47.0
*/
ODataPropertyBinding.prototype.requestValueListType = function () {
var sResolvedPath = this.getResolvedPath();
if (!sResolvedPath) {
throw new Error(this + " is unresolved");
}
return this.getModel().getMetaModel().requestValueListType(sResolvedPath);
};
/**
* @override
* @see sap.ui.model.odata.v4.ODataBinding#resetChangesInDependents
*/
ODataPropertyBinding.prototype.resetChangesInDependents = function () {};
/**
* A method to reset invalid data state, to be called by
* {@link sap.ui.model.odata.v4.ODataBinding#resetChanges}.
* Fires a change event if the data state is invalid to ensure that invalid user input, having
* not passed the validation, is also reset.
*
* @private
*/
ODataPropertyBinding.prototype.resetInvalidDataState = function () {
if (this.getDataState().isControlDirty()) {
this._fireChange({reason : ChangeReason.Change});
}
};
/**
* Method not supported
*
* @throws {Error}
*
* @deprecated As of version 1.37.0, calling this method is not supported
* @public
* @see sap.ui.model.Binding#resume
* @since 1.37.0
* @ui5-not-supported
*/
// @override sap.ui.model.Binding#resume
ODataPropertyBinding.prototype.resume = function () {
throw new Error("Unsupported operation: resume");
};
/**
* Resumes this binding and checks for updates if the parameter <code>bCheckUpdate</code> is
* set.
*
* @param {boolean} bCheckUpdate
* Whether this property binding shall call <code>checkUpdate</code>
* @param {boolean} [bParentHasChanges]
* Whether there are changes on the parent binding that become active after resuming
*
* @private
*/
ODataPropertyBinding.prototype.resumeInternal = function (bCheckUpdate, bParentHasChanges) {
var sResumeChangeReason = this.sResumeChangeReason;
this.sResumeChangeReason = undefined;
this.fetchCache(this.oContext);
if (bCheckUpdate) {
this.checkUpdateInternal(bParentHasChanges ? undefined : false, sResumeChangeReason)
.catch(this.oModel.getReporter());
}
};
/**
* Sets the (base) context if the binding path is relative. Invokes (@link #fetchCache) to
* create a cache and {@link #checkUpdate} to check for the current value if the
* context has changed. In case of absolute bindings nothing is done.
*
* @param {sap.ui.model.Context} [oContext]
* The context which is required as base for a relative path
* @throws {Error}
* If the binding's root binding is suspended
*
* @private
*/
// @override sap.ui.model.Binding#setContext
ODataPropertyBinding.prototype.setContext = function (oContext) {
if (this.oContext !== oContext) {
if (this.bRelative) {
this.checkSuspended(true);
this.deregisterChangeListener();
if (oContext) {
if (this.oType && !this.bHasDeclaredType
// Note: this.oType => this.sReducedPath
&& _Helper.getMetaPath(this.oModel.resolve(this.sPath, oContext))
!== _Helper.getMetaPath(this.sReducedPath)) {
this.doSetType(undefined);
}
this.sReducedPath = undefined;
}
}
this.oContext = oContext;
this.sResumeChangeReason = undefined;
if (this.bRelative) {
this.fetchCache(this.oContext);
this.checkUpdateInternal(this.bInitial || undefined, ChangeReason.Context)
.catch(this.oModel.getReporter());
}
}
};
/**
* Sets the optional type and internal type for this binding; used for formatting and parsing.
* Fires a change event if the type has changed.
*
* @param {sap.ui.model.Type} oType
* The type for this binding
* @param {string} _sInternalType
* The internal type of the element property which owns this binding, for example "any",
* "boolean", "float", "int", "string"; see {@link sap.ui.model.odata.type} for more
* information
*
* @public
* @see sap.ui.model.PropertyBinding#setType
* @since 1.43.0
*/
// @override sap.ui.model.PropertyBinding#setType
ODataPropertyBinding.prototype.setType = function (oType, _sInternalType) {
var oOldType = this.oType;
this.bHasDeclaredType = !!oType;
if (oType && oType.getName() === "sap.ui.model.odata.type.DateTimeOffset") {
oType.setV4();
}
PropertyBinding.prototype.setType.apply(this, arguments);
if (!this.bInitial && oOldType !== oType) {
this._fireChange({reason : ChangeReason.Change});
}
};
/**
* Sets the new current value and updates the cache. If the value cannot be accepted or cannot
* be updated on the server, an error is logged to the console and added to the message manager
* as a technical message. Unless preconditions fail synchronously, a
* {@link sap.ui.model.odata.v4.ODataModel#event:propertyChange 'propertyChange'} event is
* fired and provides a promise on the outcome of the asynchronous operation. Since 1.122.0,
* this method allows updates to the client-side annotation "@$ui5.context.isSelected". Note:
* Changing the value of a client-side annotation never initiates a PATCH request, no matter
* which <code>sGroupId</code> is given. Thus, it cannot be reverted via {@link #resetChanges}.
*
* @param {any} vValue
* The new value which must be primitive
* @param {string} [sGroupId]
* The group ID to be used for this update call; if not specified, the update group ID for
* this binding (or its relevant parent binding) is used, see {@link #getUpdateGroupId}.
* Valid values are <code>undefined</code>, '$auto', '$auto.*', '$direct' or application group
* IDs as specified in {@link sap.ui.model.odata.v4.ODataModel}. When writing to a client-side
* annotation, this parameter is ignored.
* @throws {Error} If
* <ul>
* <li> the binding's root binding is suspended.
* <li> the new value is not primitive.
* <li> no value has been read before and the binding does not have the parameter
* <code>$$noPatch</code>.
* <li> the binding is not relative to an {@link sap.ui.model.odata.v4.Context}.
* <li> the binding has the parameter <code>$$noPatch</code> and a group ID has been given.
* </ul>
*
* @public
* @see sap.ui.model.PropertyBinding#setValue
* @since 1.37.0
*/
ODataPropertyBinding.prototype.setValue = function (vValue, sGroupId) {
var oGroupLock,
oPromise,
sResolvedPath = this.getResolvedPath(),
that = this;
function reportError(oError) {
that.oModel.reportError("Failed to update path " + sResolvedPath, sClassName, oError);
return oError;
}
this.checkSuspended();
if (this.bNoPatch && sGroupId) {
throw reportError(new Error("Must not specify a group ID (" + sGroupId
+ ") with $$noPatch"));
}
_Helper.checkGroupId(sGroupId);
if (typeof vValue === "function" || (vValue && typeof vValue === "object")) {
throw reportError(new Error("Not a primitive value"));
}
if (!this.bNoPatch && this.vValue === undefined) {
throw reportError(new Error("Must not change a property before it has been read"));
}
if (this.vValue !== vValue) {
if (this.oCache) {
reportError(new Error("Cannot set value on this binding as it is not relative"
+ " to a sap.ui.model.odata.v4.Context"));
return; // do not update this.vValue!
}
oGroupLock = this.bNoPatch ? null : this.lockGroup(sGroupId, true, true);
oPromise = this.oContext.doSetProperty(this.sPath, vValue, oGroupLock);
oPromise.catch(function (oError) {
if (oGroupLock) {
oGroupLock.unlock(true);
}
reportError(oError);
});
if (!oPromise.isRejected() && that.oModel.hasListeners("propertyChange")) {
that.oModel.firePropertyChange({
context : that.oContext,
path : that.sPath,
promise : oPromise.isPending() ? oPromise.getResult() : undefined,
reason : ChangeReason.Binding,
resolvedPath : sResolvedPath,
value : vValue
});
} // else: do not construct parameter object in vain
}
};
/**
* Returns <code>true</code>, as this binding supports the feature of not propagating model
* messages to the control.
*
* @returns {boolean} <code>true</code>
*
* @public
* @see sap.ui.model.Binding#getIgnoreMessages
* @see sap.ui.model.Binding#setIgnoreMessages
* @since 1.82.0
*/
// @override sap.ui.model.Binding#supportsIgnoreMessages
ODataPropertyBinding.prototype.supportsIgnoreMessages = function () {
return true;
};
/**
* Method not supported
*
* @throws {Error}
*
* @deprecated As of version 1.37.0, calling this method is not supported
* @public
* @see sap.ui.model.Binding#suspend
* @since 1.37.0
* @ui5-not-supported
*/
// @override sap.ui.model.Binding#suspend
ODataPropertyBinding.prototype.suspend = function () {
throw new Error("Unsupported operation: suspend");
};
/**
* @override
* @see sap.ui.model.odata.v4.ODataBinding#updateAfterCreate
*/
ODataPropertyBinding.prototype.updateAfterCreate = function () {
return this.checkUpdateInternal();
};
/**
* @override
* @see sap.ui.model.odata.v4.ODataBinding#visitSideEffects
*/
ODataPropertyBinding.prototype.visitSideEffects = function () {};
return ODataPropertyBinding;
});