Cannot hide selected object with JS code in my Plugin

Hi guys, I am porting my plugin from Sketch 66 to latest Sketch, Version 2025.1.3 (203472).

I am facing an issue this this line of code:

layer.setIsVisible(false);

no effect at all.

But if I hide layer with Command+Shift+h and then call layer.setIsVisible(true); in my plugin the layer gets visible.

Please help. :exploding_head:

I’m not a big expert on this but I believe this’ll work.

layer.hidden = true;
1 Like

Thank you! It works!

Now I see it:

//  to hide you do
layer.hidden = true;

// to show you do
layer.setIsVisible(false);

Technologia!! :laughing:

1 Like

giphy

1 Like

:police_car_light::police_car_light::police_car_light:

After some testing I see it is not working.

Here is a code to test:

const sketch = require('sketch')

export default function (context) {
    let selection = context.selection;
    let slice = selection.firstObject();

    // 🚨👇 Cannot hide selected object! 🚨
    slice.hidden = true;
}

Please HELP! :folded_hands:

Hey you seem to be mixing two different approaches here:

  1. The official JS API, available via require('sketch') and the likes
  2. A legacy “native” API available via context

I’d say stick to the JS API if you can (and please start a new thread here describing your use-case if you can not do something with the JS API):

const sketch = require('sketch')

let selectedLayer = sketch.getSelectedDocument().selectedLayers.layers[0]
selectedLayer.hidden = true
Click here for the legacy API sample code
let selection = context.selection
let slice = selection.firstObject()

slice.setIsVisible(false)

So, how do I know which one to use?
I see that Sketch has a lot of tricky stuff inside and many not obvious rules.

Please understand my case:

  1. Somewhere deep inside code code I have objects with a reference to layers.
  2. I need to hide/show those layers

If I go up and rewrire everything it will take ages. Please tell me how do I check which version of hide should I use? Should I do some checks before using hide/show?

Oh if you already have a plugin codebase that’s built on top of the legacy native APIs, then please refer to the second code snippet (under a spoiler) in my previous post. It should do the trick

Ok, then last sub-question in this thread:

  1. I have symbols and bitmaps on the page. I hide all symbols.
  2. I want to save as PNG some regions from the page (Bitmaps that are under hidden Symbols) with this code:
            sketch.export(this.page, {
                formats: 'png',
                output: '/tmp',
                overwriting: true,
                filename: '1.png',
                bounds:'0,0,100,100'
            });

Current results: I see PNG with Symbols

Expected result: PNG without Symbols (because they are hidden)

How to fix it?

Hmm I can’t replicate this issue in my testing: it exports the page as I see it on the canvas (i.e. with symbols hidden). Can you share a sample document and your exact script you’re running?

1 Like

Sooo, the issue is the following:

  1. Event if symbol is hidden, it still visible on export.
  2. If I use rectangle instead of the symbol all works as expected.

Here is a video: Symbol Problem

Here is the code:

const sketch = require('sketch')

function absoluteRectForLayer(layer) {
    // NOTE: the code below assumes that `layer` is anything but MSPage instance
    let parent = layer.parentObject()
    let relativeRect = layer.frame().rect()
    return parent.convertRect_toCoordinateSpace_(relativeRect, /* to absolute/page coordinates */nil)
}

export default function (context) {
    console.log("Test 1");

    let selection = context.selection;
    if (selection.count() === 0) {
        sketch.UI.message("🚨 Please select an element");
        return;
    }
    if (selection.count() > 1) {
        sketch.UI.message("🚨🚨 Please select a single element, not a group");
        return;
    }
    let slice = selection.firstObject();
    // slice.hidden = true;

    slice.setIsVisible(false);

    let layer1 = absoluteRectForLayer(slice);
    console.log(layer1);
    console.log(layer1.origin);
    let bound = layer1.origin.x + ',' + layer1.origin.y + ',' + layer1.size.width + ',' + layer1.size.height;
    console.log(bound);

    let doc = context.document;
    let page = doc.pages()[0];
    sketch.export(page, {
        formats: 'png',
        output: '/Users/max/Desktop',
        overwriting: true,
        filename: 'export_1.png',
        bounds: bound
    });
    slice.setIsVisible(true);
    sketch.UI.message('Done');
}
1 Like

Ohhh I see now, yes there’s indeed a race condition here because some parts of Sketch’ internal machinery run on a background thread, so basically they don’t get enough time to actually “apply” the new visibility status of a symbol before you try to export the corresponding area of the document – and as a result, it’s rendered as still visible.

Luckily, there’s a workaround. Do this right after your setIsVisible(false) call:

slice.setIsVisible(false);

if (slice.isKindOfClass(MSSymbolInstance) || slice.isKindOfClass(MSSymbolMaster)) {
  slice.ensureDetachHasUpdated()
}
1 Like

Thank you! It works!

p.s. I would not be able to come up with this code myself.

2 Likes

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.