Unlock a world of possibilities! Login now and discover the exclusive benefits awaiting you.
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
Hi,
Have you checked what Engine API call is aborted? Is it retried?
Erik Wetterberg
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
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
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:
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"}]
This behaviour is something I really can not comprehend 😕
Cheers,
Mathias
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 🙂
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);
Thank you iharsh,
However in my case, it is the master.field('LastName') that gets aborted, and therefore the .selectValues(["Jones"], true, true) 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. 🙂