How can I change a Boolean property in Lit-Element to hide content on my component?
Asked Answered
D

5

13

I have a custom component that should hide content when I set a boolean property to false. Every other property gets reflected except that one. I must be doing something wrong.

static get properties(){
      title: {
        type: String,
        attribute: 'title',
      },

      titleEnable: {
        type: Boolean,
        attribute: 'title-enable',
      },
}

constructor() {
    super();
    this.titleEnable=true;
    this.title="default";
}

render(){

    return html`                
        ${this.titleEnable 
        ? html`
        <p class="title" ?hidden="${!this.titleEnable}">${this.title}</p>
        `
        : html ``} 
    ` 
}

If I use that component like <my-component></my-component> in an HTML file it shows: default as expected.

If I use it like this: <my-component title="New Title"></my-component> it displays: New Title as expected.

BUT if I try to hide it <my-component title-enable="false"></my-component> the boolean just doesn't change. I've tried !title-enable, title-enable='false", .titleEnable=false and all the variants you can imagine. What pisses me the most is that whenever I set in the constructor 'this.titleEnable=false' and I happen to just declare the variable WITHOUT value on the tag and it takes it as TRUE an "default" appears. <my-component title-enable></my-component> I am completely lost.

Dutyfree answered 14/3, 2020 at 1:12 Comment(0)
D
15

Ok, this is a tricky one. You need to handle it differently by passing some object as below:

  static get properties() {
    return {
      titleConfig: {
        type: Object,
        attribute: 'title-config'
      }
    }
  }

  render() {
    return html`                
      ${this.titleConfig.titleEnable
        ? html`
      <p class="title" ?hidden="${!this.titleConfig.titleEnable}">${this.titleConfig.title}</p>
      `
        : html``} 
  `
  }

In HTML:

<my-component title-config='{"title":"shan", "titleEnable": false}'></my-component>

Now, the question is why it is true every time?

Answer: For a Boolean property to be configurable from markup, it must default to false. If it defaults to true, you cannot set it to false from markup, since the presence of the attribute, with or without a value, equates to true. This is the standard behavior for attributes in the web platform.

It is taken from polymer doc.

So, by creating an attribute title-enable, the HTML considers this attribute as true

It's really a bummer for someone who starts working on Polymer or LitElement .

Dituri answered 14/3, 2020 at 18:53 Comment(2)
What's really a bummer is that this information is not in the lit documentation lol. You are golden bro. A thousand kudos to you.Dutyfree
Boolean properties are set by the presence of the attribute, not the attribute value. For the following show is true <boolean-test show></boolean-test> and <boolean-test show="false"></boolean-test>. For the following show is false <boolean-test></boolean-test>. This does however mean that the default value for boolean properties can't be true or you can never set it to false with an attribute. So instead of show with a default of true you would use the opposite with something like hide with a default value of false. From: github.com/lit/lit-element/issues/948Quiles
A
8

According to the documentation:

To bind to a boolean attribute you need to use the "?", notation:

Bind prop3 to a boolean attribute:

html`<input type="text" ?disabled="${this.prop3}">`

Boolean attributes are added if the expression evaluates to a truthy value, and removed if it evaluates to a falsy value.

Almsman answered 28/10, 2020 at 19:11 Comment(2)
Came back to this to try other solutions. This one doesn't work.Dutyfree
"If the default value is true it'll always be true" holds true!Blakley
P
1

You can also use reflected attributes instead:

static get properties(){
      title: {
        type: String,
        attribute: 'title',
      },

      titleEnable: {
        reflect: true,
      },
}

constructor() {
    super();
    this.titleEnable='true';
    this.title="default";
}

handleHidden() {
  return this.titleEnable === 'true'
}

render(){

    return html`                
        ${this.titleEnable 
        ? html`
        <p class="title" ?hidden="${!this.handleHidden()}">${this.title}</p>
        `
        : html ``} 
    ` 
}
Perineum answered 17/12, 2020 at 17:48 Comment(0)
P
0

This issue is because of data type. In lit-element 'false' | 'true' the type is returned as 'string' data type.

Solution:

Before that check your attribute data type is string or boolean

     ex: typeof attr

If it return string means, you have two solution:
    1. Change the attributes date type as boolean ex: Boolean(attr).
    2. Consider the value as string and check your condition.

From your example 
    if(this.titleConfig.titleEnable == 'true'){
        //true statement
    }else{
        // false statement
    }

my suggestion is this.titleConfig.titleEnable == 'true'

Paella answered 16/2, 2021 at 15:51 Comment(0)
P
-1

Instead of passing your value as an attribute you also could pass it as a property (https://lit.dev/docs/templates/expressions/#property-expressions):

<my-component .title-enable=${false}></my-component>
Perionychium answered 5/12, 2022 at 14:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.