Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't declare Boolean attributes with default of true? #1812

Closed
JanMiksovsky opened this issue Jun 9, 2015 · 12 comments
Closed

Can't declare Boolean attributes with default of true? #1812

JanMiksovsky opened this issue Jun 9, 2015 · 12 comments

Comments

@JanMiksovsky
Copy link

The way attributes are deserialized seems to preclude the declaration of attributes that default to true.

From the docs: "Boolean properties set based on the existence of the attribute: if the attribute exists at all, its value is true, regardless of its string-value (and the value is only false if the attribute does not exist)."

That works for attributes with a default value of false. If someone wants the default value, they leave the attribute off. If they want the non-default value of true, they can explicitly say attr="true" (or any string).

But I don't see how to declare support for a Boolean attribute that defaults to true. See http://jsbin.com/neyaxu/1/edit?html,output. Here, I want to be able to override the default behavior by saying red="false". Since Polymer interprets any string value of true, however, it doesn't appear to be possible to declaratively set the attribute to false. That can be done imperatively, but it should also be possible imperatively.

While an attribute's logic can always be flipped such that its default value is false, there are cases where an attribute's obviously API name naturally suggests a default value of true.

@punzki
Copy link

punzki commented Jun 9, 2015

+1 to being able to use prop="false" and have Polymer deserialize it as a Boolean false. Any other String value can be true. Or maybe also accept "0".

One more thing. It also causes more confusion when I use dom-repeat to create a bunch of custom elements, with Boolean properties. What am I supposed to set for the attribute?

<template is="dom-repeat" items="{{arr}}">
  <x-test bool-attr="{{item.foo}}"></x-test>
</template>

If Polymer were strict about "Boolean properties set based on the existence of the attribute", then there is no way to set bool-attr to false, since there's no way to conditionally set the presence of an attribute (you can only set an attribute's value). But actually, Polymer is fine with the above syntax... it reads the Boolean value of property foo in Objects in arr, and passes them on correctly to x-test's bool-attr property.

@arthurevans
Copy link

Note that this isn't really Polymer's definition of a boolean attribute, it's HTML's definition of a boolean attribute:

http://www.w3.org/TR/2008/WD-html5-20080610/semantics.html#boolean

I think there's a tension here between something that's arguably more flexible (foo="false") and something that's arguably more idiomatic with native elements (presence == true). Even the web platform is incoherent here, since ARIA uses string values for "true" and "false".

@punzki you're confusing setting an HTML attribute and data binding to a property. The value of item.foo isn't being deserialized here. You're assigning x-test.boolAttr the value of item.foo.

@punzki
Copy link

punzki commented Jun 10, 2015

@arthurevans - That's precisely my point, that it is confusing, and inconsistent. When you put x-test in regular HTML markup, you set x-test.boolAttr by the presence/absence of the bool-attr HTML boolean attribute. But when it's used inside a dom-repeat, you're supposed to assign it by using a non-boolean HTML attribute.

@adalinesimonian
Copy link

I'm curious to better understand the use-case for having a boolean property have a default of true. Would it not be possible to simply reverse the logic behind the property such that the desired functionality would be possible with a default of false?

For example, assuming we're working with an element that validates villains to see whether or not they're fit of being someone's arch-nemesis, instead of using evilLairRequired with a default of true, there would be a property evilLairOptional with a default of false.

Basically, what I'm getting at is: what's an expectable use-case where this is not possible?

@JanMiksovsky
Copy link
Author

@vsimonian There are cases where the most natural and desirable attribute name would be framed in the positive. While attributes are just symbols, and their meaning can be inverted and still make logical sense, an API is tantamount to language, and humans want language to read naturally. In some cases, the positive form of a word may be more concise or common than the negative form. (Some rare words like "inert" have no opposite form.) In other cases, the negative form may be misleading or inaccurate. And it's often desired that an API should mirror the corresponding terms in the user interface.

  • A component wants an auto-size attribute that defaults to true. It's hard to come up with a natural-sounding word or phrase that means the opposite of "auto-size".
  • A window component has a maximize attribute that defaults to true. The meaning of maximize="true" is different than minimize="false". Something like not-maximized="false" may be accurate but quite awkward and hard to parse.
  • A site has some type of object that can be marked as a "favorite", and for whatever reason, the default is true. Because the UI uses the term "favorite", it's desirable to have the attribute be called favorite, with a corresponding default value of true.

@jlg7
Copy link

jlg7 commented Jun 15, 2015

I encountered this when migrating elements from 0.5 to 1.0. To avoid coming up with corresponding negative forms, I just used an additional word in front of the attribute names to represent an attribute is disabled or its effects have been inhibited or its dimensions have been reduced (something like disable-).

Although more than one word, this seemed to:

  • preserve the UI jargon
  • aide in keeping the inherent truth and default behavior of the element
  • provide type hinting for attributes named similar to favorite where its boolean nature is rather obscure

The prefix disable- may not be great in all contexts but other familiar words may be juxtaposed to have the similar effects.

@kevinpschaaf
Copy link
Member

As Arthur mentioned, Boolean attributes have a specific platform meaning from which we do not want to stray. We also feel that the practice of defaulting booleans to false makes sense in the vast majority of cases, and places where the platform has strayed (e.g. draggable="true") were poor design decisions that result in confusing and unintuitive API and are warts of the platform that we are stuck with. For these reasons, we have no plan to change how type: Boolean values are deserialized by default.

That said, there are some options if you choose to go forward implementing this type of API for your elements.

  1. Use type: Object - this actually hints Polymer to use JSON.parse which result in the desired behavior ("true" and "false" parse desired):
    http://jsbin.com/zawale/edit?html,output
  2. Implement a custom serialize/deserialize function for your element. We intentionally made these methods easily overridable for cases when authors need to augment the default approach.
    http://jsbin.com/rerevu/edit?html,output

@JanMiksovsky
Copy link
Author

@kevinpschaaf I think Polymer's position is reasonable. Thanks for letting us know about those options!

ootwch pushed a commit to ootwch/sortable-list that referenced this issue Sep 12, 2015
Polymer properties with default value = true have to use Type: Object, otherwise it will not work.
See also: Polymer/polymer#1812 (comment)
@jptrainor
Copy link

This is a shame. It is not intuitive at all. I need to programatically set the value for paper-input-container's noLabelFloat boolean property It's wrapped in a custome element and I need to disable noLableFloat in some cases.. It cannot be done via a binding thanks to this behaviour. I have to resort to dom-if logic, or write code that sets the property value manually. All that could be avoided if I could just bind a value.

@arthurevans
Copy link

This isn't related to data binding. This only affects configuring the element from static markup.

You can easily use a data binding to toggle noLabelFloat:

http://jsbin.com/gosaza/edit?html,output

@jptrainor
Copy link

Many thanks. I got it working with the binding. In my state of confusion when I first countered this I issue I messed up my binding declaration and concluded incorrectly that it didn't work.

@arthurevans
Copy link

Glad to hear it 👍

rhysd added a commit to rhysd/neovim-component that referenced this issue Aug 7, 2016
because HTML attribute can't have true default value.

Polymer/polymer#1812
teamdandelion pushed a commit to tensorflow/tensorboard that referenced this issue May 23, 2017
matgnt added a commit to matgnt/scheduler-component that referenced this issue Aug 17, 2017
matgnt added a commit to matgnt/scheduler-component that referenced this issue Aug 18, 2017
…bahi#15

Component attributes are "true" if set and "false" if not.
Therefore, default values of "true" can never be set to "false" through
attributes.
Explained more in detail here:
Polymer/polymer#1812 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants