Javascript: Check if a component is currently visible (by component ID)?

Mark LMark L ✭✭✭✭
edited June 29, 2020 in Questions
Is there a way to check if a component (with a given component ID) is currently visible on the screen in Javascript?

I can check if it is "rendered" with

skuid.component.getById('COMPONENTID').isRendered

but this isn't enough, as it turns out that it being rendered and it being currently visible on the screen have different implications. For instance if I tell it to render with .render(), even if it "isRendered", if it's not currently visible on the screen this will cause an error.

Is there a way to check on the component's actual visibility (the component not being hidden)?

Thanks!

Comments

  • Luzie BaumgartLuzie Baumgart 🛠️ 
    edited June 29, 2020
    Hi Mark, that sounds like a cool idea to check rendered vs. visible. I'm sure there are different ways to check it - we got help from our solutions engineers and can show you one way to achieve it. The following sample page contains three wrapper components of different colours, and a JS snippet which checks if the purple wrapper component is completely visible. The snippet is triggered by a button click. You can see the result in the browser console (visibility true/false). We hope that this idea is helpful for you:

    <skuidpage personalizationmode="server" showsidebar="false" showheader="false" globalfeedbackenabled="false">
    <models/>
    <components>
    <wrapper uniqueid="sk-2Qyg-384">
    <components>
    <buttonset uniqueid="sk-2Qyg-385" position="center">
    <buttons>
    <button type="multi" label="check purple's visibility in the browser console" uniqueid="sk-2Qyg-386">
    <actions>
    <action type="custom" snippet="newSnippet"/>
    </actions>
    </button>
    </buttons>
    <renderconditions logictype="and"/>
    </buttonset>
    </components>
    <styles>
    <styleitem type="background"/>
    <styleitem type="border" margin="none" borders="all">
    <styles>
    <styleitem property="border" value="16px solid transparent"/>
    <styleitem property="box-sizing" value="border-box"/>
    </styles>
    </styleitem>
    <styleitem type="size"/>
    </styles>
    </wrapper>
    <wrapper uniqueid="orange">
    <components/>
    <styles>
    <styleitem type="background" bgtype="color">
    <styles>
    <styleitem property="background-color" value="orange"/>
    </styles>
    </styleitem>
    <styleitem type="border"/>
    <styleitem type="size" height="custom">
    <styles>
    <styleitem property="min-height" value="600px"/>
    </styles>
    </styleitem>
    </styles>
    </wrapper>
    <wrapper uniqueid="green">
    <components/>
    <styles>
    <styleitem type="background" bgtype="color">
    <styles>
    <styleitem property="background-color" value="green"/>
    </styles>
    </styleitem>
    <styleitem type="border"/>
    <styleitem type="size" height="custom">
    <styles>
    <styleitem property="min-height" value="600px"/>
    </styles>
    </styleitem>
    </styles>
    </wrapper>
    <wrapper uniqueid="sk-2QyT-316">
    <components>
    <buttonset uniqueid="sk-2CE1-633" position="center">
    <buttons>
    <button type="multi" label="check purple's visibility in the browser console" uniqueid="sk-2CE1-634">
    <actions>
    <action type="custom" snippet="newSnippet"/>
    </actions>
    </button>
    </buttons>
    <renderconditions logictype="and"/>
    </buttonset>
    </components>
    <styles>
    <styleitem type="background"/>
    <styleitem type="border" margin="none" borders="all">
    <styles>
    <styleitem property="border" value="16px solid transparent"/>
    <styleitem property="box-sizing" value="border-box"/>
    </styles>
    </styleitem>
    <styleitem type="size"/>
    </styles>
    </wrapper>
    <wrapper uniqueid="purple">
    <components/>
    <styles>
    <styleitem type="background" bgtype="color">
    <styles>
    <styleitem property="background-color" value="purple"/>
    </styles>
    </styleitem>
    <styleitem type="border"/>
    <styleitem type="size" height="custom">
    <styles>
    <styleitem property="min-height" value="600px"/>
    </styles>
    </styleitem>
    </styles>
    </wrapper>
    </components>
    <resources>
    <labels/>
    <javascript>
    <jsitem location="inlinesnippet" name="newSnippet" cachelocation="false">var params = arguments[0],
    $ = skuid.$;
    var component = skuid.component.getById('purple');
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();
    var elemTop = $(component.element).offset().top;
    var elemBottom = elemTop + $(component.element).height();
    var result= ((elemBottom &lt;= docViewBottom) &amp;&amp; (elemTop &gt;= docViewTop));
    console.log("visibility "+ result);</jsitem>
    </javascript>
    <css/>
    <actionsequences/>
    </resources>
    <styles>
    <styleitem type="background" bgtype="none"/>
    </styles>
    </skuidpage>

  • Mark LMark L ✭✭✭✭
    edited June 20, 2020
    Hi Luzie,

    Thanks for the update. Interesting hack, but not quite what I'm looking for. The XML page example depends on the Y location of the element on the screen and assumes that it is visible as long as its Y location is within screen bounds.

    Here I've moved the colors into a tab set where an element's visibility is dependent on it being within the currently selected tab and this method now breaks, causing an error when not yet rendered, and showing "visible" after rendering whether or not its tab is selected and it is actually visible:

    <skuidpage personalizationmode="server" showsidebar="false" showheader="false" globalfeedbackenabled="false">
    <models/>
    <components>
    <wrapper uniqueid="sk-2Qyg-384">
    <components>
    <buttonset uniqueid="sk-2Qyg-385" position="center">
    <buttons>
    <button type="multi" label="check purple's visibility in the browser console" uniqueid="sk-2Qyg-386">
    <actions>
    <action type="custom" snippet="newSnippet"/>
    </actions>
    </button>
    </buttons>
    <renderconditions logictype="and"/>
    </buttonset>
    </components>
    <styles>
    <styleitem type="background"/>
    <styleitem type="border" margin="none" borders="all">
    <styles>
    <styleitem property="border" value="16px solid transparent"/>
    <styleitem property="box-sizing" value="border-box"/>
    </styles>
    </styleitem>
    <styleitem type="size"/>
    </styles>
    </wrapper>
    <tabset rememberlastusertab="false" defertabrendering="true" uniqueid="sk-2RoA-302">
    <tabs>
    <tab name="Orange">
    <components>
    <wrapper uniqueid="orange">
    <components/>
    <styles>
    <styleitem type="background" bgtype="color">
    <styles>
    <styleitem property="background-color" value="orange"/>
    </styles>
    </styleitem>
    <styleitem type="border"/>
    <styleitem type="size" height="custom">
    <styles>
    <styleitem property="min-height" value="600px"/>
    </styles>
    </styleitem>
    </styles>
    </wrapper>
    </components>
    </tab>
    <tab name="Green" loadlazypanels="true">
    <components>
    <wrapper uniqueid="green">
    <components/>
    <styles>
    <styleitem type="background" bgtype="color">
    <styles>
    <styleitem property="background-color" value="green"/>
    </styles>
    </styleitem>
    <styleitem type="border"/>
    <styleitem type="size" height="custom">
    <styles>
    <styleitem property="min-height" value="600px"/>
    </styles>
    </styleitem>
    </styles>
    </wrapper>
    </components>
    </tab>
    <tab name="Purple" loadlazypanels="true">
    <components>
    <wrapper uniqueid="purple">
    <components/>
    <styles>
    <styleitem type="background" bgtype="color">
    <styles>
    <styleitem property="background-color" value="purple"/>
    </styles>
    </styleitem>
    <styleitem type="border"/>
    <styleitem type="size" height="custom">
    <styles>
    <styleitem property="min-height" value="600px"/>
    </styles>
    </styleitem>
    </styles>
    </wrapper>
    </components>
    </tab>
    </tabs>
    </tabset>
    <wrapper uniqueid="sk-2QyT-316">
    <components>
    <buttonset uniqueid="sk-2CE1-633" position="center">
    <buttons>
    <button type="multi" label="check purple's visibility in the browser console" uniqueid="sk-2CE1-634">
    <actions>
    <action type="custom" snippet="newSnippet"/>
    </actions>
    </button>
    </buttons>
    <renderconditions logictype="and"/>
    </buttonset>
    </components>
    <styles>
    <styleitem type="background"/>
    <styleitem type="border" margin="none" borders="all">
    <styles>
    <styleitem property="border" value="16px solid transparent"/>
    <styleitem property="box-sizing" value="border-box"/>
    </styles>
    </styleitem>
    <styleitem type="size"/>
    </styles>
    </wrapper>
    </components>
    <resources>
    <labels/>
    <javascript>
    <jsitem location="inlinesnippet" name="newSnippet" cachelocation="false">var params = arguments[0],
    $ = skuid.$;
    var component = skuid.component.getById('purple');
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();
    var elemTop = $(component.element).offset().top;
    var elemBottom = elemTop + $(component.element).height();
    var result= ((elemBottom &lt;= docViewBottom) &amp;&amp; (elemTop &gt;= docViewTop));
    console.log("visibility "+ result);</jsitem>
    </javascript>
    <css/>
    <actionsequences/>
    </resources>
    <styles>
    <styleitem type="background" bgtype="none"/>
    </styles>
    </skuidpage>
    Is there any more direct way of checking visibility? Currently my strategy is to keep calling a function to re-render the object and in a try/catch, keep catching the error when it tries to render while the element isn't visible, and re running the function until the element becomes visible again and an error isn't caught; not an ideal solution -- pretty messy, would be preferable to find a more direct way of dealing with this.

    Thanks!
  • Arne-Per HeurbergArne-Per Heurberg ✭✭✭✭
    edited June 20, 2020
    did you ever find a different a solution?
  • Mark LMark L ✭✭✭✭
    edited June 21, 2020
    Wrote this in your other post but here it is again:

    function to wait for an element to be visible on the screen and then runs the callback when it is:

    // skuid.custom.waitForElement(fparams,callback)
    // wait for an element to be ready on the screen before performing the callback function
    // fparams = {
    //  initEle: function to initialize the element / check if the element is initialized,
    //      should return the initialized element. Takes context as a variable.
    //  context: passed context or defaults to window
    //  chunkTime: time between chunks, defaults to 250
    // }
    skuid.custom.waitForElement = function (fparams, callback) {
        fparams = fparams || {};
        const initEle = fparams.initEle || undefined;
        const element = fparams.element || undefined;
        const context = fparams.context || window;
        const chunkTime = fparams.chunkTime || 250;
        
        function doChunk () {
            let ele;
            if (initEle === undefined && element !== undefined) {
                ele = element;
            } else if (initEle !== undefined) {
                ele = initEle.call(context);
            }
            
            if (typeof ele !== 'undefined') {
                let error = false;
                try {
                    callback.call(context, ele);
                } catch (err) {
                    error = true;
                    console.log('Still waiting for element.. Error: ${err}');
                }
                
                if (!error) {
                    console.log('Wait for element complete.');
                    clearInterval(ourInterval);
                }
            } else {
                console.log('Still waiting for element..');
            }
        }
        
        // Keep trying to get the element and perform the callback until there isn't an error
        const ourInterval = setInterval(doChunk, chunkTime);
    };

  • Arne-Per HeurbergArne-Per Heurberg ✭✭✭✭
    edited June 21, 2020
    thanks! that is better than what I did. Stay safe and well
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!