[13.0.7] How to access components and its properties?

componentId = 'CompentId'

c = skuid.runtime.getPage('Questionnaire_v2').component.getById(componentId);

in v1 I could c.unrender(), etc. but how do I do that in v2?

In my case I want to disable/unrender modal component from JS.

Best Answer

  • Anna Wiersema
    Anna Wiersema 🛠️ 
    Accepted Answer

     Hi @lukaspovilonis, someone from the team was able to review your code and here's what you can use to render the table inside the wrapper:

    let wrapperId = 'wrapperTable';
    let strXmlTable = `<skuid__table allowColumnFreezing="dragDrop" model="UIModel" uniqueid="sk-NAL-5813" mode="read">
                        <fields>
                            <field id="Field1" uniqueid="fi-NAP-7426"/>
                            <field id="Field2" uniqueid="fi-NAP-7427"/>
                        </fields>
                        <filtering enableSearch="false"/>
                        <rowActions/>
                        <massActions/>
                    </skuid__table>`;xmlDef = skuid.utils.makeXMLDoc(strXmlTable);var wrapperComponent = skuid.$C(wrapperId);wrapperComponent.set({
        components: [
            xmlDef,
        ]
    });
    


    the only thing that was changed was the last part of your code

    var wrapperComponent = skuid.$C(wrapperId);
    wrapperComponent.set({
        components: [
            xmlDef,
        ]
    });
    


Answers

  • Hi @lukaspovilonis, what is your desired outcome here?

    • If you want to render and unrender a component, it's best to do that via the action framework using the toggle component action.
    • Is there a reason it doesn't make sense to use the action framework for your specific use case?
  • lukaspovilonis
    edited November 12, 2020

    Action/Action-Sequence don't behave as expected.

    async/await or $.when([runActionSequence]).then([runAnotherActionSequence]) is also not working.

    In my example i'm trying to achieve the affect of skuid.component.getById([ComponentId]).rerender() from Skuid v1. Hence, first I'm hiding component and then showing it again (or toggle x2).

    On the surface, it seems like Skuid v2 is updating the state only after all actions have been executed.


    Note: when I say I expect the component to rerender I mean rerender like skuid.component.getById([ComponentId]).rerender() in v1, and not hiding/showing the HTML tag.


    Example 1:

    Execute the following lines all together in console.

    skuid.runtime.getPage([PageName]).actionSequences.getByName('TogglWrapper').run();

    skuid.runtime.getPage([PageName]).actionSequences.getByName('TogglWrapper').run();

    Result: As explained before, it seems like first action is not considered or skuid doesn't update the state.


    Example 2:

    Execute the following lines one at a time in a console:

    skuid.runtime.getPage([PageName]).actionSequences.getByName('TogglWrapper').run();

    skuid.runtime.getPage([PageName]).actionSequences.getByName('TogglWrapper').run();

    Result: Component gets hidden after first line is executed, and then the component is shown again after the 2nd line is executed, achieving the desired result.


    Example 3:

    Execute the following all together in console:

    async function test(){

    await skuid.runtime.getPage([PageName]).actionSequences.getByName('TogglWrapper').run();

    await skuid.runtime.getPage([PageName]).actionSequences.getByName('TogglWrapper').run();

    }

    test();

    Result: Same as example 1, the state is updated 'once' and it's after both action sequences have executed.


    Example 4:

    Execute the following all together in console:

    skuid.runtime.getPage([PageName]).actionSequences.getByName('TogglWrapper').run();

    setTimeout(() => {

      skuid.runtime.getPage([PageName]).actionSequences.getByName('TogglWrapper').run()}, 

      2000);

    Result: As desired, same as example 2, first the component gets hidden and then 2 seconds later it is shown again.


    Example 5:

    Create an action sequence with 2 actions, both of them toggling the same component

    Result: Same as example 1, only updating the state after the last action.


    Side affect/bug:

    Showing/hiding components multiple times, the component starts to duplicate.


    Use case:

    I need to re-render components for multiple reasons in multiple places, but in this use case i'm trying to redraw (drill to the top and show new data) when model has been updated due to filter .


    Best,

    Lukas

  • Hi Anna,

    Thank you for the reply.

    It is true, using actions and action sequence would work achieve the same result.


    But,


    Furthermore, is it possible to create an action sequence inside Javascript?

    I tried

    • skuid.runtime.getPage([PageName]).actionSequences.getSequenceXMLFromId([ActionSequenceId]) -> Returns an error
    • skuid.runtime.getPage('Reporting_v2').actionSequences.initializeActionSequences(xml) -> returns an empty list

    What should these functions do, how should I use them and is there a different way?


    My use case:

    I update a filter, I want a chart to drill to the top and re-render. I have other use cases, but this one is the one I'm currently working on.


    Best,

    Lukas

  • Thanks for your reply, Lukas.

    • If I'm understanding correctly, you have a chart that you've drilled down into, and you want the chart to reset to the original un-drilled down version when the filter is selected, correct?
    • You can dig into the highcharts api for more on how to re-set the drill-ing level via JavaScript. If you have multiple charts on the page, you'd have to make sure you get the correct chart in context.
  • Hi Anna,

    Thank you for the suggestion, but unfortunately I am unable to find anything.

    The only way to create a HighChart is to recreate one which would require options plus more:

    If I recreate a chart using just options it will create a chart of only the level that I got options from (I cannot drilldown after I re-create it).

    • hc = skuid.runtime.getPage([PageName]).component.getById([ChartId]).getHighchartsObject()
    • Highcharts.chart([ChartWrapperId], hc.options);

    I assume Skuid creates a new chart when a drill down event is called or charts are manipulated outside of chart options.

  • Hi Anna,

    Another two use cases have came up:

    1. I need to rerender picklist choices, where the picklist itself is created using custom field renderer. If the picklist options are based on another model, when that model is updated then the picklist's options are rerendered automatically by Skuid. Though, in my case the options are based on JS Snippet and I might need to rerender either due to another model update, user choosing an option from a different picklist or button click.
    2. A user can submit a questionnaire by a click of a button, after the questionnaire has been submitted the user shouldn't be able to edit it anymore. Hence, I need to rerender form fields, custom form fields, buttons, custom buttons

    Unfortunately running action sequence to show/hide component doesn't actually reconstruct the component as it did in v1 (and that's what I'm looking for), instead it feels like it just changes hide/show attribute on HTML tag.

    Your help is much appreciated.

    Best,

    Lukas

  • Anna Wiersema
    Anna Wiersema 🛠️ 
    edited December 16, 2020

    Hi Lukas, one of our product engineers took a look at this post, please find their answers below:


    Comment 1

    The Question

    componentId = 'CompentId'

    c = skuid.runtime.getPage('Questionnaire_v2').component.getById(componentId);


    in v1 I could c.unrender(), etc. but how do I do that in v2?


    In my case I want to disable/unrender modal component from JS.

    Dev Answer

    Unrender in V2 simply sets the “visible” boolean within state to “false”. This works for most components but a modal has to be removed entirely so they could run “c.unregister()” which should remove it entirely.


    Comment 2

    First part

    Action/Action-Sequence don't behave as expected.

    async/await or $.when([runActionSequence]).then([runAnotherActionSequence]) is also not working.

    In my example i'm trying to achieve the affect of skuid.component.getById([ComponentId]).rerender() from Skuid v1. Hence, first I'm hiding component and then showing it again (or toggle x2).

    On the surface, it seems like Skuid v2 is updating the state only after all actions have been executed.

    Note: when I say I expect the component to rerender I mean rerender like skuid.component.getById([ComponentId]).rerender() in v1, and not hiding/showing the HTML tag.

    Developer

    Why are you trying to “rerender” the component? In v2 nothing really needs rerendering. If state is updated properly it will auto-update itself.


    Example one

    Execute the following lines all together in console.

    skuid.runtime.getPage([PageName]).actionSequences.getByName('TogglWrapper').run();

    skuid.runtime.getPage([PageName]).actionSequences.getByName('TogglWrapper').run();

    Result: As explained before, it seems like first action is not considered or skuid doesn't update the state.

    Developer

    If this is performing an action on the modal then there will be issues because we use a delay to hide/show the modal so it does a fade in/out effect.


    Example two

    Execute the following lines one at a time in a console:

    skuid.runtime.getPage([PageName]).actionSequences.getByName('TogglWrapper').run();

    skuid.runtime.getPage([PageName]).actionSequences.getByName('TogglWrapper').run();

    Result: Component gets hidden after first line is executed, and then the component is shown again after the 2nd line is executed, achieving the desired result.

    Developer

    This probably works better because the delay is around 300 milliseconds so doing it manually probably creates its own delay


    Example three

    Execute the following all together in console:

    async function test() {

        await component.run();

        await component.run();

    }

    test();

    Result: Same as example 1, the state is updated 'once' and it's after both action sequences have executed.

    Developer

    This could be better implemented on our side but the toggling of a modal kicks off a separate asynchronous method that does not tie back to the action firing it. Could be a product improvement.


    Example four

    Execute the following all together in console:

    component.run();

    setTimeout(() => {

        component.run()}, 

     2000);

    Result: As desired, same as example 2, first the component gets hidden and then 2 seconds later it is shown again.

    Developer

    This makes sense that this would work since the delay/transition of the modal is 300 milliseconds.


    Example five

    Create an action sequence with 2 actions, both of them toggling the same component

    Result: Same as example 1, only updating the state after the last action.

    Developer

    Again, this goes back to the separate 300ms asynchronous hiding/showing of the modal so it makes sense this would not work.


    Side effect/bug

    Showing/hiding components multiple times, the component starts to duplicate.

    Developer

    This does make sense as well since many register/unregister calls are being made.

  • Hello Anna,

    Thank you so much for getting these answers, and sorry for delayed reply.


    Thank you for confirming that 'toggle' component is just setting the visibility, makes sense.


    Why I need it:

    • Skuid isn't able to handle rerendering if a component makes uses of unrelated model, e.g. a model used to populate a picklist. In my case I have two custom picklists where one is dependent on another, so when an item is selected for first one I need to filter the 2nd picklist.
    • There is custom logic in JS that asks for rerendering. In my case, user is able submit a questionnaire, making the questionnaire uneditable, so I have to rerender custom fields so they are not editable. And, similar to first case, upon a button click a picklist should populate (or change the options).

    Everything does make more sense knowing that there is 300ms delay. Knowing that delay is static will definitely help. Also, it would be appreciated if one day async function returns after the 300ms instead of before. You said it's 'around' 300ms, so to confirm, if i put manual delay of 300ms will my showing/hiding component consistently work? If not, what is minimal delay that will consistently work?

    I have tested with 'Example Four' - even if I put timeout for 1ms it still works, so I'm wondering what's happening there?


    Regarding Chart Side effect - so like modals charts are also unregistered once they are hidden?


    I have another issue regarding rendering. I Render a component on one tab, switch tabs and come back the component i dynamically created will have disappeared. In the example it's all on one page for simplicity and illustration, but in my solution there are over tabs each tab has a page include to avoid going over xml limit. Would you be able to clarify why that is happening and how can make my dynamic components be there when I switch back? Example is below.

    <skuid__page unsavedchangeswarning="yes" personalizationmode="server" showsidebar="true" showheader="true">
    <models>
    <model id="UIModel" limit="20" query="true" datasource="Ui-Only" createrowifnonefound="true">
        <fields>
            <field id="Field1" displaytype="TEXT" length="255"/>
            <field id="Field2" displaytype="TEXT" length="255"/>
        </fields>
        <conditions/>
        <actions/>
    </model>
    </models>
    <components>
    <skuid__tabSet uniqueid="sk-NAP-7008">
        <tabs>
            <skuid__tabPanel name="New Tab">
                <components>
                    <skuid__table allowColumnFreezing="dragDrop" model="UIModel" uniqueid="sk-NAL-5813" mode="read">
                        <fields>
                            <field id="Field1" uniqueid="fi-NAP-7426"/>
                            <field id="Field2" uniqueid="fi-NAP-7427"/>
                        </fields>
                        <filtering enableSearch="false"/>
                        <rowActions/>
                        <massActions/>
                    </skuid__table>
                </components>
            </skuid__tabPanel>
            <skuid__tabPanel name="New Tab">
                <components>
                    <skuid__buttonSet model="UIModel" uniqueid="sk-NAR-11475">
                        <groups>
                            <skuid__buttonGroup uniqueId="sk-NAR-11473">
                                <buttons>
                                    <skuid__button label="Create Table" uniqueId="sk-NAR-11474">
                                        <actions>
                                            <action type="custom" snippet="createTable"/>
                                        </actions>
                                    </skuid__button>
                                </buttons>
                            </skuid__buttonGroup>
                        </groups>
                    </skuid__buttonSet>
                    <skuid__wrapper uniqueid="wrapperWrapperTable">
                        <components>
                            <skuid__wrapper uniqueid="wrapperTable">
                                <components/>
                                <styles>
                                    <spacing/>
                                </styles>
                                <background/>
                            </skuid__wrapper>
                        </components>
                        <styles>
                            <spacing/>
                        </styles>
                        <background/>
                    </skuid__wrapper>
                </components>
            </skuid__tabPanel>
        </tabs>
    </skuid__tabSet>
    </components>
    <resources>
        <labels/>
        <javascript>
    <jsitem location="inlinesnippet" name="createTable" cachelocation="false">let wrapperId = 'wrapperTable';
    let strXmlTable = `&lt;skuid__table allowColumnFreezing="dragDrop" model="UIModel" uniqueid="sk-NAL-5813" mode="read"&gt;
                        &lt;fields&gt;
                            &lt;field id="Field1" uniqueid="fi-NAP-7426"/&gt;
                            &lt;field id="Field2" uniqueid="fi-NAP-7427"/&gt;
                        &lt;/fields&gt;
                        &lt;filtering enableSearch="false"/&gt;
                        &lt;rowActions/&gt;
                        &lt;massActions/&gt;
                    &lt;/skuid__table&gt;`;
    
    
    
    xmlDef = skuid.utils.makeXMLDoc(strXmlTable);
                
    var dynamicChartComponent = skuid.$(
        "#" + wrapperId
    );
    
    
    
    dynamicChartComponent.empty();
    dynamicChartComponent.prepend('&lt;div id="new_div"&gt;&lt;/div&gt;');
    tempElement = dynamicChartComponent.find('#new_div');
    
    
    var myComponent = skuid.component.factory({
        element: tempElement,
        xmlDefinition: xmlDef
        });</jsitem>
    </javascript>
        <css/>
        <actionsequences/>
    </resources>
    <styles>
        <styleitem type="background" bgtype="none"/>
    </styles>
    </skuid__page>
    


    All of the best,

    Lukas

  • Hello Anna,

    Thank you so much to you, and the developer!

    I'm very grateful to receive this small piece of knowledge! This has solved the components disappearing problem. Even more importantly, this has solved another problem that was on its path to become a monster and start making me lose my sleep. I really appreciate this!

    Would be amazing if there was a way to control rendering, my current work around is to attach styling/rendering/Enable conditions with a model which then I update to fire the event for re-rendering.

    Once more, thank you!

    All the best,

    Lukas

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!