Unlock a world of possibilities! Login now and discover the exclusive benefits awaiting you.
Hi!
I would like to export data selected by a bookmark in a certain application to be exported using a NodeJS script running on some server. Is this possible? The end goal here is to (semi-)automate a user segmentation process.
I can connect using Node and Enigma.js and list various things, but I am not sure if I can get a selection from a bookmark using Enigma. Or can I talk to the Capability API directly somehow?
Another possibility would be to write some kind of component that runs as an extension within the application, that the QlikSense user can click to automatically export the data somehow, but I would prefer the NodeJS solution if possible, as it would integrate better with our other systems.
Hopefully, this could be a start
const enigma = require("enigma.js");
const schema = require("enigma.js/schemas/12.612.0.json");
const bookmarkListProps = {
qInfo: {
qId: "BookmarkList",
qType: "BookmarkList"
},
qBookmarkListDef: {
qType: "bookmark",
qData: {
// dynamic data stored by the Qlik Sense client
title: "/qMetaDef/title",
description: "/qMetaDef/description",
sheetId: "/sheetId",
selectionFields: "/selectionFields",
creationDate: "/creationDate"
}
}
};
(async () => {
const session = enigma.create(<ENIGMA CONFIG>);
const global = await session.open();
const app = await global.openDoc(<APP_ID>);
// creates a session object
const bookmarkListModel = await app.createSessionObject(bookmarkListProps);
const bookmarkListLayout = await bookmarkListModel.getLayout();
const bookmarks = bookmarkListLayout.qBookmarkList.qItems;
var filteredBookmarks = bookmarks.filter(function (item) {
return item.qMeta.published && // Check if Bookmark is published
item.qMeta.title.includes("Book") // And contains a name "pattern"
});
console.log(filteredBookmarks);
// Iterate over the items: apply bookmark and fetch values from field
})()
.catch((err) => {
console.error("ERR:", err);
})
.finally(() => {
//session.close();
});
What would you like the outcome to be?
Do you want the selected values that the bookmark will apply or do you want the "datamodel" that the bookmark will produce?
https://qlik.dev/apis/json-rpc/qix/doc#%23%2Fentries%2FDoc%2Fentries%2FApplyBookmark if you want to apply/"use" the bookmark
Hi!
I would like my Qlik Sense users to be able to create customer segments using bookmarks in a certain application (to identify some group of customers). Then, I would like my script to look at these bookmarks, and write a text file containing the customer numbers for all these customers every night, or something like that.
It should be possible to have them publish bookmarks with some name convention soo that your script could find the bookmark and apply it. And after that grab the selected values from some field.
But I guess it would be a nicer experience for the users if you just make an extension that will post the values from a field to an internal server.
Long time since I did an extension but it should be pretty easy to make
I see your point, but for various reasons, I think the naming convention would be the best way here. However, what I don't understand is how I can use Enigma.js to achieve this. I can't find any examples of anything like this.
I have found a bunch of examples of have to use the Capability API, but that is always in the context of some frontend code, and I don't know how to translate that to anything that can be run in a NodeJS script on my servers.
Hopefully, this could be a start
const enigma = require("enigma.js");
const schema = require("enigma.js/schemas/12.612.0.json");
const bookmarkListProps = {
qInfo: {
qId: "BookmarkList",
qType: "BookmarkList"
},
qBookmarkListDef: {
qType: "bookmark",
qData: {
// dynamic data stored by the Qlik Sense client
title: "/qMetaDef/title",
description: "/qMetaDef/description",
sheetId: "/sheetId",
selectionFields: "/selectionFields",
creationDate: "/creationDate"
}
}
};
(async () => {
const session = enigma.create(<ENIGMA CONFIG>);
const global = await session.open();
const app = await global.openDoc(<APP_ID>);
// creates a session object
const bookmarkListModel = await app.createSessionObject(bookmarkListProps);
const bookmarkListLayout = await bookmarkListModel.getLayout();
const bookmarks = bookmarkListLayout.qBookmarkList.qItems;
var filteredBookmarks = bookmarks.filter(function (item) {
return item.qMeta.published && // Check if Bookmark is published
item.qMeta.title.includes("Book") // And contains a name "pattern"
});
console.log(filteredBookmarks);
// Iterate over the items: apply bookmark and fetch values from field
})()
.catch((err) => {
console.error("ERR:", err);
})
.finally(() => {
//session.close();
});
Thanks a lot!
That will work great for my purpose, but I still can't find a lot of information about how to actually retrieve the selected data in the script. The examples seems to always be about doing stuff in the browser, like selecting fields and applying bookmarks, so I'm still unsure about where to find more about this part:
// Iterate over the items: apply bookmark and fetch values from field
Actually, I now managed to do this:
app.applyBookmark('394db859-58d1-4fbf-89e2-321d219f480e');
let qObj = await app.getObject("mwEZnM");
const dataExport = await qObj.exportData("OOXML");
let downloadLink = `https://my.server.url${dataExport.qUrl}`;
That produces an url that I can use to get the data directly from a list in the application with the bookmark applied. Great success! Thanks again. Is this the way to do it? Our would there be a better solution?
It works as you do it but you will get one exported file per bookmark. Not sure that's what you want or you want to combine them all?
You can create a Listbox with the field that you are interested in and iterate over the bookmarks and retrieving the values (e.g selected and possible) from the Listbox
const listObjectProps = {
qInfo: {
qType: "my-list-object"
},
qListObjectDef: {
qDef: {
qFieldDefs: ["<FIELD_NAME>"]
},
qInitialDataFetch: [
{
qTop: 0,
qHeight: 100,
qLeft: 0,
qWidth: 1
}
]
}
};
const getValuesFromBookmark = async (filteredBookmarks, app) => {
const listbox = await app.createSessionObject(listObjectProps);
var allSelectedValues = [];
for (const bookmark of filteredBookmarks) {
await app.applyBookmark(bookmark.qInfo.qId);
const listBoxLayout = await listbox.getLayout();
const values = listBoxLayout.qListObject.qDataPages[0].qMatrix;
for (const value of values) {
if (value[0].qState === "S" || value[0].qState === "O") {
const elemNum = value[0].qElemNumber;
const allready = allSelectedValues.some((v) => v["qElemNumber"] === elemNum);)
if (!allready) {
allSelectedValues.push(value)
}
}
}
}
return allSelectedValues.flat();
};
// ==== And call it
const v = await getValuesFromBookmark(filteredBookmarks, app)
console.log(v)
The maximum number of rows possible to fetch at once is 10000 soo if your field contains more values you have to implement pagination. Maybe it's possible to only get the selectedvalues in the response (have checked the props of the listbox)