How to conditional add and remove `use:` property in Svelte 3?
Asked Answered
D

4

12

Is there a way to elegantly and conditionally add and remove use: property in Svelte 3?

Example:

<script>
    import {classes} from "./functions.js"

    export let originalClasses
</script>

<button use:classes>Button</button>

Is there a way to add or remove use:classes if originalClasses is true?

Duchy answered 30/3, 2021 at 15:16 Comment(0)
E
4

Actions in Svelte can receive a parameter, which you could use to enable or disable the effect.

Encyclical answered 30/3, 2021 at 15:24 Comment(0)
S
4

Given that you have no control over the classes function, one way would be to wrap the action with one of your own:

import classes from '....'
function classesWrap(node, useDefault = true) {
  useDefault && classes(node);
  
  return {
    update(useDefault) {
      useDefault && classes(node);
    }
  }
}

and then use this action instead: <div use:classesWrap={originalClasses}>

This works, kind of, when originalClasses is false, it will not set the default ones, and when it is true it will set them. When it starts as false and turns true it will also apply them (thanks to the update) However it seems that once an action is attached it cannot be removed again (which is logical as actions are supposed to run when the element gets mounted). This means that turning from true to false will not change anything, it will keep the default classes.

There are two (really bad) workarounds for this:

  1. add some extra code to the update function to remove the classes yourself:
update(useDefault) {
  useDefault && classes(node);
  !useDefault && node.classList.remove(...node.classList);
}

(but this removes all classes, also those you might have added yourself)

  1. a second option is to wrap the element with a {#key} block based on originalClasses this will force a re-render whenever it changes.
{#key originalClasses}
 <div use:classesWrap={originalClasses}>...</div>
{/key}

But this can be very expensive if this div has a lot of content, maybe for a one line element it might be ok.

(note: you don't need the update function anymore)

Of course this assumes that originalClasses can and will change, if you are 100% sure it will never ever change, just use the wrapper without update or key blocks.

Subheading answered 30/3, 2021 at 18:36 Comment(0)
F
1

Is this what you are trying to do?

REPL

//functions.js
export default function classes(node,options){
    if(options){
    node.className="myClass";
    }
        console.log(node);
}
Fragonard answered 30/3, 2021 at 15:41 Comment(0)
C
1

I got here trying to find out how to conditionally use an action. I discovered how to do it, it would look this way using the main example:

<script>
    import {classes} from "./functions.js"

    export let originalClasses

    const conditionalAction = originalClasses ? classes : ()=>{};
</script>

<button use:conditionalAction>Button</button>

Note that this will only work when the button is mounted and not for future value changes. If originalClasses was given to the component as true (<MyComponent originalClasses={true} />), the classes action will be used; if originalClasses is false or not set, the button will use no action (noop arrow function: ()=>{}).

Caddish answered 19/11, 2022 at 7:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.