In a SAPUI5 application I would like to update the content of a control (e. g. a tile) only when this is currently visible to the user. I created a function like this:
You can utilize jQuery do achieve that.
// determine whether your control is still part of the active DOM
jQuery.contains(document, yourControl.$());
// determine whether your control is visible (in terms of CSS)
yourControl.$().is(':visible');
// combined
MyControl.prototype.isVisible = function() {
return this.$().length && // has rendered at all
jQuery.contains(document, this.$()) && // is part of active DOM
this.$().is(':visible'); // is visible
};
Elements could still be invisible to the user by being:
visibility: hiddenopacity: 0Also check this answer
BR Chris
http://api.jquery.com/jQuery.contains/
http://api.jquery.com/visible-selector/
The web API IntersectionObserver is now supported by all major browsers, including Safari.src
const observer = new IntersectionObserver(callback/*, settings?*/);
observer.observe(domElement);
Below is a demo with UI5. Run the snippet and try to scroll there. The page title is changed depending on the visibility of the target element:
sap.ui.require([
"sap/ui/core/Core",
], Core => Core.attachInit(() => sap.ui.require([
"sap/ui/core/mvc/XMLView",
"sap/ui/model/json/JSONModel",
], (XMLView, JSONModel) => {
"use strict";
XMLView.create({
definition: `<mvc:View xmlns:mvc="sap.ui.core.mvc"
xmlns:core="sap.ui.core"
xmlns="sap.m"
displayBlock="true"
height="100%"
>
<App>
<Page title="Tile visible: {= %{/ratio} > 0}">
<FlexBox renderType="Bare"
height="360vh"
justifyContent="Center"
alignItems="Center"
>
<core:Icon id="myBox"
src="sap-icon://color-fill"
size="5rem"
color="Critical"
/>
</FlexBox>
</Page>
</App>
</mvc:View>`,
afterInit: function() {
this.byId("myBox").addEventDelegate({
onAfterRendering: onAfterRenderingBox.bind(this),
});
},
models: new JSONModel(),
}).then(view => view.placeAt("content"));
function onAfterRenderingBox() {
const domRef = this.byId("myBox").getDomRef();
new IntersectionObserver(myCallback.bind(this)).observe(domRef);
}
function myCallback(entries) {
const entry = getTarget(entries, this.byId("myBox").getDomRef());
this.getModel().setProperty("/ratio", entry.intersectionRatio, null, true);
}
function getTarget(entries, source) {
return entries.find(entry => entry.target === source);
}
})));
<script id="sap-ui-bootstrap"
src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"
data-sap-ui-libs="sap.ui.core, sap.m"
data-sap-ui-async="true"
data-sap-ui-theme="sap_fiori_3"
data-sap-ui-compatVersion="edge"
data-sap-ui-xx-waitForTheme="init"
></script>
<body id="content" class="sapUiBody sapUiSizeCompact"></body>
In case the IntersectionObserver is still not fully supported by the target browser (e.g. IE11), you can add the following polyfill to your project:
https://github.com/w3c/IntersectionObserver/blob/master/polyfill/intersection-observer.js
The polyfill checks whether the API is already natively supported beforehand. If it's not supported, the needed objects and methods will be added to the global object consecutively. The signature of the polyfilled API is equivalent to the native API.