Qlik Community

Qlik Sense Integration, Extensions, & APIs

Discussion board where members can learn more about Integration, Extensions and API’s for Qlik Sense.

Partner
Partner

Select values in different app

Hello Community,

I stumbled upon an interesting issue today and would love to know if I did something wrong:

My task is to link different Qlik Sense apps and synchronize their field selections via JavaScript, which seems very easy at first:

require(["js/qlik"], function (qlik) {

    // load apps

    var master = qlik.openApp('869559e8-d565-4909-a302-b74390ca98d8', config);

    var slave = qlik.openApp('f35b3d7a-c6fa-4c55-9b6f-7869d07f653a', config);

    // load filter-objects

    master.getObject('QV01', '3466decc-948a-43cc-b6f0-3804909c9889')

    slave.getObject('QV02', 'JmbmQWN');

    // assign event-handler to selection state of master app

    var selState = master.selectionState();

    var listener = function () {

        if (selState.selections.length == 0) {

            return;

        }

        // re-map selections for easier access

        var syncableSelections = selState.selections.map(function (s) {

                return {

                    field: s.fieldName,

                    values: s.qSelected

                };

            });

        syncableSelections.forEach(function (selection) {

            console.log('Selecting in ' + slave.id, selection.field, JSON.stringify(selection.values));

            slave.field(selection.field).selectMatch(selection.values, true);

        });

    };

    selState.OnData.bind(listener);

});

With this code, only the first selection I make in my master app is applied to the slave-application. Others are ignored and I get a ""Request aborted" message in the developer console.

While trying different things I found that if I extract the "syncableSelections"-variable using JSON.stringify and manually re-assign the variable (making it a constant), the selection of multiple fields works as expected (=even if I deselect stuff in the slave app, it will be re-selected next time I select something in the master app):

syncableSelections = [{

        "field": "dlType",

        "values": "R"

    }, {

        "field": "Vergleich",

        "values": "YTY"

    }, {

        "field": "MeasureLabel",

        "values": "Einkaufsvolumen"

    }, {

        "field": "DimensionLabel",

        "values": "Mandant"

    }, {

        "field": "Basis",

        "values": "Rechnung"

    }

];

syncableSelections.forEach(function (selection) {

            console.log('Selecting in ' + slave.id, selection.field, JSON.stringify(selection.values));

            slave.field(selection.field).selectMatch(selection.values, true);

        });

...

I even logged both JSON-Versions to console and they're exactly the same, yet it only works when syncableSelections is a constant.


I've never experienced something like this so if anyone knows why this is happening I'd love to know!

And for anyone interested, those are possible solutions to this issue (atleast the ones I found):

Using setTimeout (shorter but maybe there'll be timing issues [I didn't really test it]):

        var s = 0;

        var time = 25;


        syncableSelections.forEach(function (selection) {

            console.log('Selecting in ' + slave.id, selection.field, JSON.stringify(selection.values));

            setTimeout(function () {

                slave.field(selection.field).selectMatch(selection.values, true);

            }, s * time);

            s++;

        });

Using a  sequential promise-chain (sequentially executes every promise in an array):

// create promise array

var promises = [];

// and generator-function for a selection-promise

var promiseForLater = function (selection) {

    // we want to return a function without parameters because

    // we're going to execute it in a context where we don't know which selection

    // we want to apply

    return function () {

        return app.field(selection.field).selectValues(selection.values, true);

    }

};

// clear before applying other selections

promises.push(function () {

    return app.clearAll()

});

// use generator-function to fill array with functions

syncableSelections.forEach(function (selection) {

    promises.push(promiseForLater(selection));

});

// use es6 array-"reduce" function to sequentially

// execute the selection-promises

promises.reduce(function (promiseChain, currentTask) {

    // we dont need any result,

    // hence we skip the concatenation of result-values

    return promiseChain.then(function (chainResults) {

        return currentTask()

    });

    // start value, has to be set for reduce function

}, Promise.resolve([]));

Cheers,

Mathias

7 Replies
ErikWetterberg
Honored Contributor

Re: Select values in different app

Hi,

Have you checked what Engine API call is aborted? Is it retried?

Erik Wetterberg

https://extendingqlik.upper88.com/

Partner
Partner

Re: Select values in different app

Hello Erik,

I did now, the error occurs on "GetField":

{"delta":true,"handle":1,"method":"GetField","params":["Vergleich","$"],"id":29,"jsonrpc":"2.0"}

-> {"jsonrpc":"2.0","id":29,"error":{"code":15,"parameter":"Failure","message":"Request aborted"}}

Interestingly, there does not seem to be an issue with the GetField-function because if I remove the ".selectMatch(selection.values, true); " no error is displayed!

I don't think the request is retried because there is no frame containing the field name "Vergleich" except the erroneous.

Cheers

ErikWetterberg
Honored Contributor

Re: Select values in different app

‌Hi,

WHat Qlik Sense version are you using? I think there was an issue with getField falls geting aborted, which they really shouldn’t. Might be solved in later releases.

A Work-around could be to get the fields (IF you know them ) in advance.

Erik Wetterberg

https://extendingqlik.upper88.com/

Partner
Partner

Re: Select values in different app

Hello Erik,

thanks again for your help, I'm using June 2018. The most "interesting" part of this issue is this though:

1.) Creating "syncableSelections"-variable via .map-function:

14a23481607ac8772fec56a478f73762.gif

As you can see (maybe you can - gyazo scales it down pretty hard) I'm logging the JSON-representation of the "syncableSelections"-variable to the console.


2.) If I copy the JSON-representation and assign it manually to the  "syncableSelections"-variable the selections are made correctly:

syncableSelections = [{"field":"dlType","values":"R"},{"field":"Vergleich","values":"YTY"},{"field":"Basis","values":"Rechnung"},{"field":"MeasureLabel","values":"Einkaufsvolumen"}]

13da3412b926c5b682692aadb2e08e59.gif

This behaviour is something I really can not comprehend 😕

Cheers,

Mathias

Partner
Partner

Re: Select values in different app

Hi Mathias,

Did you resolve the 'Request aborted' for the GetField message?

I get the same problem occasionally in my mashup as well. Not sure how to handle aborted GetFields, as the qlik.app.field() always returns an object, and not a promise.

(I asked a separate question in this thread: https://community.qlik.com/t5/Qlik-Sense-Integration/How-to-handle-qlikk-app-field-being-aborted/td-...)

 

Any help would be appreciated,

Vegard 🙂

iharsh220
New Contributor II

Re: Select values in different app

Hi,

app.field('LastName').selectValues(["Jones"], true, true);

you can try this.. if you want to select any values.

in your case you have to do like this master .field('LastName').selectValues(["Jones"], true, true); or

slave .field('LastName').selectValues(["Jones"], true, true);

 

Partner
Partner

Re: Select values in different app

Thank you iharsh,

However in my case, it is the master.field('LastName') that gets aborted, and therefore the .selectValues(["Jones"], truetrue) never executes.

 

However, as 'aaz' writes in the other thread,  it will be fixed in a future release.  So I can live with workarounds for now. 🙂

 

Thanks for your input anyway. 🙂