What is the right way to not use reserved public name withing web-component - web-component

When I run a build with stencil, I get
[Warn]
The #Prop() name "title" is a reserved public name. Please rename the "title"
prop so it does not conflict with an existing standardized prototype member.
Reusing prop names that are already defined on the element's prototype may
cause unexpected runtime errors or user-interface issues on various browsers,
so it's best to avoid them entirely.
I know it's only a warning but since it may cause unexpected runtime errors, I was wondering if some standard for naming it already existed. (since title was for me the more obvious propriety name to use).
If not, what would be the best practice?

title is a global html attribute name - 'reserved'. See https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes. As a best practice, you shouldn't use global attribute names for #Props. I don't know of any 'standard' for naming a property which is the title of your component but isn't the same as the global title attribute (which is usually used for the tooltip).

As of today, the only workaround I found was to add attributes as property and pass all the information through this variable, like the following
attributes: {
title: string
description: string
/** ... */
}
I didn't found better than that.
But I'm still open to any ideas

Properties and component attributes are strongly connected but not necessarily the same thing.
We cannot use the title variable because of the HTMLElement prop type, but we can set the field text as title like this
#Prop({ attribute: 'title' }) heading?: string;

Related

Why can you set a lit public property 'attribute' option to false?

From the Lit documentation: "The component shouldn't change its own public properties, except in response to user input."
Also from the documentation: "Internal reactive state works just like public reactive properties, except that there is no attribute associated with the property."
However, when you declare a property, there is an option of setting attribute to false, which prevents an attribute from being associated with the property.
#property({attribute: false})
data = {};
What would be the purpose of doing this? Wouldn't the property just act like internal state at that point?
For reference, Lit already has several ways of declaring internal state variables, either with the #state decorator or setting the state option to true, so I'm just not sure why they allow this too.
I think the main use case for this is for when you have to pass big complex data to the component but want it to be set directly as a property and still get lit to rerender stuff for you.
I think this is easier to visualize with an example, let's say you're making a component which will render a list out of an array passed as a property.
If the array was set as an attribute, it would look something like this:
<list-renderer items='[{id: "1", name: "John Doe"}, {id: "2", name: "Alice Williams"}]'></list-renderer>
Now, this example only has two items, but it could be something way bigger, and that attribute will eventually need to be serialized into an array using JSON.parse() by lit. So, you're just doing an extra step, especially if you already had the array as a JS object rather than JSON data.
So, for this kind of cases it's easier to just force users to set items as a JS property directly.
This will also apply for when you need to pass complex configuration setting objects or functions to the component.
Then again, for most of the components you'll be making, you will probably stick with either having the attribute or making it a fully internal state property.
This way you are really free to use any combination.
A property which acts also as state and attribute
A property which acts also as state but not as an attribute
A state, which is not a property
A property, which is an attribute
A property which is not an attribute
see also https://javascript.info/dom-attributes-and-properties for the difference between properties and attributes.

Get the item set as display

I have a container x, with a Link item y set as display.
How can I access programmatically y if I know x?
I tried: getattr(x, 'default_page', None), but it returns None all the time.
By using getattr you may override plone default behavior regarding how to determinate the default page of an object (item or container).
Content objects in Plone inherit BrowserDefaultMixin, which provides the functionality of getting the default page of a object
The mixin, respectively a utility used by the mixin provides the desired method called getDefaultPage
>>> x = b.getObject()
>>> x.getDefaultPage()
...
This will return the right content object or view depending on the configuration on the object, on the FTI and on the View itself and more.
Have a look at get_default_page for more details.
And even better...
This canonical way of getting the default page, would also have helped finding the issue in your case pretty fast, since the method does certain checks to make sure the passed object provides the right "features". A string would not pass those checks.
default_page = getattr(x, 'default_page', None) is the answer. But make sure you have an object for x.
My mistake was I tried b.getObject().absolute_url() in my query instead of b.getObject().

Graphql Schema doku displays Input type automatically with Input

I have added leangen/graphql-spqr as described in the readme.
Before we had a custom implementation of graphql types like in customtype.types.gql.
After implementation, everything works fine, except the type which are called e.g. OperatorInput, are named in the autogenerated graphql doc like "OperatorInputInput".
I tried to Change it like this in the declaration:
#GraphQLArgument(name = "OperatorInput", description = "Required fields for Operator") OperatorInput operator
But it wasn't applied.
Do you know any workaround?
This is intended. Keep in mind that in GraphQL's type system, input and output types are strictly different. Let's say you have this in Java:
public Book saveBook(Book in) {...}
The Book that is the return type and the Book that is the argument type are 2 different types in GraphQL, and must have unique names. So Input is added automatically to make the names unique.
If you're 100% sure you want to override this, register a custom TypeInfoGenerator via GraphQLSchemaGenerator#withTypeInfoGenerator. You can inherit from DefaultTypeInfoGenerator and override generateInputTypeName. BUT! Do pay attention that if you end up producing the same name for 2 different types, all hell breaks loose. So maybe only drop the suffix Input if the classname already ends with Input and never ever use such classes for output.
Btw #GraphQLArgument sets the name of the argument, not the name of the type of the argument.

Multiple "default" properties/methods in a VB6 class?

I am trying to make a replacement VB6 class for the Scripting.Dictionary class from SCRRUN.DLL. Scripting.Dictionary has (among other things) a "Keys" method that returns an array of keys, and a read/write "Item" property that returns the item associated with a key. I am confused about this, because both of them seem to be defaults for the class. That is:
For Each X In MyDict
Is equivalent to:
For Each X In MyDict.Keys
Which to me implies that "Keys" is the default operation for the class, but:
MyDict("MyKey") = "MyValue"
MsgBox MyDict("MyKey")
Is equivalent to:
MyDict.Item("MyKey") = "MyValue"
MsgBox MyDict.Item("MyKey")
Which to me implies that "Item" is the default operation for the class.
I've never before created a VB6 class that had a default operation, so upon realizing this, I thought perhaps I could define multiple default operations as long as they all have different signatures, which they do: Keys is nullary, the Item getter takes a Variant, and the Item setter takes two Variants. But this doesn't seem to be allowed: When I use "Tools/Procedure Attributes" to set the Keys function to be the default, and then I use it to set the Item property to be the default, the IDE complains that a default has already been set.
So I think I'm misunderstanding something fundamental here. What is going on in the Scripting.Dictionary object that makes it able to act as if "Keys" is the default in some contexts, but as if "Item" is the default in others? And whatever it is, can I accomplish the same thing in VB6?
OK, answering my own question: I haven't tried this yet, but I gather that "Item" should be made the default, and that I should add an entirely new function called "NewEnum" that looks something like the following (slightly modified from an example in Francesco Balena's "Programming Microsoft Visual Basic 6.0" book):
Public Function NewEnum() As IUnknown
Set NewEnum = m_Keys.[_NewEnum]
End Function
(where "m_Keys" is a Collection containing the keys), and then use Tools/Procedure Attributes to hide NewEnum and to set its ProcID to -4.
What you are observing is the difference between the default member and a collection enumerator. A COM object (including VB6 classes) can have both.
You can identify the default property of a class by looking in the Object Browser for the tiny blue globe or the words "default member of" in the description (see Contents of the Object Browser). The Object Browser will not identify an enumerator method, but if you look at the class's interface definition using OLE View or TypeLib Browser (free but registration required) it's DispId will be 0xfffffffc or -4.
In your own class, you can mark the default property by setting the Procedure ID to "(default)" in the Procedure Attributes dialog (see Making a Property or Method the Default). You already listed the steps for setting up the collection enumerator in your own answer, but you can find this listed as well in the Programmer's Guide topic Creating Your Own Collection Class: The House of Bricks.
Scripting.Dictionary has a dirty secret:
It does not handle enumeration at all, it returns big ugly Variant arrays and your For Each loops iterate over those.
This is one of the reasons why a Dictionary can actually be far less efficient than a standard VB6 Collection.

Moving fields between fieldsets on Dexterity

In Archetypes, in order to move a field from a fieldset (or schemata) to another, we can do the following:
schema['creators'].schemata = 'default'
However, I'm not achieving the same using Dexterity. I've tried using form hints. Ex:
form.fieldset('default',
fields=['creators']
)
I notice that it doesn't work because the field "creators" is unknown at this time. (The ownership behavior wasn't evaluated yet).
Nevertheless, with form hints, I can move from "default" to another (eg. "ownership").
myfile = NamedFile(title=_(u"A file"))
form.fieldset('ownership', fields=['myfile'])
How can I do that? Writing my own behavior?
Thx!
You likely need to make the define the field you want to assign on an interface under your control. While this seems duplicative, it is a good idea for purposes of being complete and explicit. You can either:
(1) Declare 'creators' field on your content type interface (likely, recommended solution), or...
(2) Use your own behavior as documented here (and adding this behavior to the type's FTI in portal_types and associated setup XML): http://docs.plone.org/external/plone.app.dexterity/docs/behaviors/creating-and-registering-behaviors.html
The first solution should be the easiest. Any fields that you wish to control fieldset location or order of should likely be defined by your interfaces anyway.

Resources