You know it already but enigma.js is the JavaScript wrapper around the Qlik's Engine API.

If you are building a mashup/web app or some sort of automation that require Engine communication you'll have to use Engine API and here enigma.js is your friend.

Just to mention that JavaScript is not the only "flavor" of Enigma. You can find enigma for Go and .NET:

qlik-oss/enigma-go
Go library for consuming Qlik’s Associative Engine. - qlik-oss/enigma-go
q2g/enigma.net
.NET library for consuming Qlik’s Associative Engine. - q2g/enigma.net

But in this post I want to introduce you to one very cool (but not very popular) functionality that Enigma provides - mixins.

Mixins allow us to extend, with additional methods, or override existing methods. Mixins are bound to at least one type (type being - Doc, GenericObject, GenericBookmark etc.). The official documentation can be found in the official enigma.js repo.

Let's write some code (basics)

Essentially each mixin is a JS object with few properties - init, types and extends and/or overrides.

A very simple mixin will be:

const docMixin = {
    types: ['Doc'],
    init(args) {
        console.log(`My mixin is being initialized`);        
    },
    extend: {
        myMixin() {
            console.log('My mixin was called!');
        },

    }
}

From the snipped above, we can see:

  • this snipped is available for docs (apps)
  • when the mixin is initialised a message will be printed in the console
  • when its called the mixin will only print a message

To use the mixin we have to add this object (or objects) to the Enigma session:

const session = enigma.create({
    schema,
    mixins: [docMixin],
    url: 'ws://localhost:9076/app/engineData',
    createSocket: (url) => new WebSocket(url),
});

Once we have the session established then we can open an app and use our mixin:

let global = await session.open()
let doc = await global.openDoc('/data/Consumer Sales.qvf')
doc.myMixin()

In our case the mixin is pretty general (just printing a message) and we might want to use it for other types and not just in the apps context. To add it to more types just edit the type array:

...
types: ['Doc', 'GenericObject', 'GenericBookmark']
...

A bit more advanced example

Getting the layout of an object is a two step process:

let qObject = await doc.getObject('some-object-id-here');
let qLayout = await qObject.getLayout();

What about if we write an mixin that is doing these two steps for us so we can have a single command to get the layout? An example mixin can look like this:

const docMixin = {
    types: ['Doc'],
    init(args) { },
    extend: {
        getLayoutMixin(objectId) {
            let qObject = await doc.getObject(objectId);
            let qLayout = await qObject.getLayout();

            return [ qObject, qLayout ]
        }
    }
}

const session = enigma.create({
    schema,
    mixins: [docMixin],
    url: 'ws://localhost:9076/app/engineData',
    createSocket: (url) => new WebSocket(url),
});

let global = await session.open()
let doc = await global.openDoc('/data/Consumer Sales.qvf')

let [myObject, myObjectLayout] = await doc.getLayoutMixin('some-object-id');

Conclusion

Personally I found the mixins to be very cool and handy feature. But also I found them very underused (including myself here as well).

I've been setting my own collection of useful mixins in my free time and the next post will be about this collection but you can have a look in the repo if you want:

countnazgul/enigma-mixin
Set of Enigma mixin. Contribute to countnazgul/enigma-mixin development by creating an account on GitHub.

Hope you liked it!

Stefan