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

has="mixin this, mixin that" #663

Closed
jimmont opened this issue Sep 6, 2017 · 11 comments
Closed

has="mixin this, mixin that" #663

jimmont opened this issue Sep 6, 2017 · 11 comments

Comments

@jimmont
Copy link

jimmont commented Sep 6, 2017

has="mixin" Idea for managing mixins without conflicting with existing classes or is= attribute. A followup to #662 #509 re is=.

Goal: address practical need for mixins with existing and custom elements, hook into element lifecycle, not conflict with various libraries, expectations in the wild.

...Sorter...
customElements.mixin('sortable', Sorter);


<any has="sortable"></any>
<any has="sortable filterable whatever"></any>
@bedeoverend
Copy link

bedeoverend commented Sep 7, 2017

If you're interested, just as an example of it in action - I created a proof of concept of essentially this a little while back - using (Base) => class extends Base {...} style of mixins, which adds the mixin into the proto chain, and allows use of super. Essentially tries to mimic the Element Upgrade behavior, but w/ dynamic mixins. See discussion

Seems like concept of mixins in general has definitely be discussed before, and also custom-attributes which may also be an alternative here.

In general I'm +1 for the mixin concept, but feel there must be some reasons it hasn't been successful so far...

@annevk
Copy link
Collaborator

annevk commented Sep 7, 2017

I think the main problem is that JavaScript itself lacks native support. If it ever got native support we'd want to be compatible with that. So until that point it seems better to experiment in "user space".

@bedeoverend
Copy link

@annevk that sounds completely fair. What if, rather than specifying a particular mixin syntax or anything, we could just open up and generalise the Element Upgrade process - so that we could upgrade new prototypes as we needed?

Realise this is touching on #620, which is closed due to existence of setPrototypeOf / __proto__ but as noted, they ruin engine optimisations, and this idea of dynamic Element Upgrades would also include lifecycle hooks e.g. connected / disconnected etc. I'm not sure if implementing it natively would fix those engine optimisation issues...?

@annevk
Copy link
Collaborator

annevk commented Sep 7, 2017

Well yeah, but at that point you're enshrining a particular variant of mixins that may or may not be what ends up in JavaScript.

@bedeoverend
Copy link

bedeoverend commented Sep 7, 2017

Oh right - as in, replacing the prototype to add extra functionality is one variant of mixins, and not necessarily the one that will become standard, and therefore not something to pursue right now for CEs?

Might be better for me to make my comments over on #620 then, as it's more a comment on being able to make further upgrades.

@annevk
Copy link
Collaborator

annevk commented Sep 7, 2017

Right.

@trusktr
Copy link
Contributor

trusktr commented Sep 7, 2017

Mixing classes together (in whatever form, class factories, concatenation, etc) is adding much complexity that my idea avoids in the first place (avoiding anything to do with inheritance).

Assuming it would be named has="" (which I like because it is the shortest so far and the word describes which behaviors the element "has"), then in the following:

<any-element has="behavior1 behavior2 behavior3" />

those classes are not associated by inheriatnce at all.

They are standalone classes, as I just described here: #509 (comment)

They don't inherit from each other, there's no concatenation, prototype mangling, or any form of multiple inheritance; there's nothing about inheritance at all, to keep it simple and clean.

They are standalone behaviors, then when instantiated are given the opportunity to act on (or on behalf of) an element. They are behaviors that can run logic based on the life cycle of a given element, and they don't need to extend from each other or operate on the same this.

In most cases, they will probably never actually need to add or remove properties on the target element, and using their own this will suffice.

In less common cases, the behavior might want to expose imperative API (rather than just attribute-based API). And in such cases, this idea (though slightly more verbose than accessing properties on an element itself) provides a way for a behavior's public API to be accessed, and encourages developers not to modify properties directly on the target element.

However, behavior authors still can modify the target element directly if they want to (just like authors of any jQuery behavior).

In the end, this would be more similar to jQuery than multiple inheritance, in the sense that jQuery plugins can have their own this and APIs on that this can be called and properties on that this can be set without modifying the target element. The target element is merely a medium from which to react to, and from which behaviors can react based on the target element's (attribute) state.

F.e., in jQuery, we use behaviors like this:

$(someElement).behavior('some-method', 'some-arg')

(This pattern is documented here)

In this jQuery example, we're passing the element to jQuery and getting back a jQuery context that lets us use a behavior associated with the element (using the aforementioned and widely-adopted pattern), and to then call a method on that behavior (not on the element directly).

In this regard, the idea in #662 is similar, in the sense that behaviors are independent of each other.

In my example where I wrote

audioDiv.components['audio-player'].callWhatever()

// or

audioDiv.behaviors['audio-player'].callWhatever()

that is effectively similar to

$(audioDiv).audioPlayer('callWhatever')

in jQuery, where we get a behavior associated with the target element and call a method on it.

This concept has already been proven (jQuery), just that in the current form it is not declarative, only imperative.

#662 proposes something that replaces the current is="" attribute with something that is still declarative, more concise than jQuery's version, but also similar to jQuery's concept of standalone behaviors that are less likely to conflict than mixins of whatever form.

The idea in #662 is also better than jQuery's, because each behavior is nicely organized into a class that has its own very clear this context on which it can do anything it wants, and with an API like audioDiv.behaviors['audio-player'].callWhatever() it is possible to get the highly-individual this context of a behavior and call methods on it.

The pattern is simply a lot cleaner, semantic, and idiomatic than jQuery's, based on modern JS.

That said, this idea is its own, jQuery or not. The behaviors associated with an element are independent (there's no inheritance involved, and there should not be, for the sake of simplicity).

It allows any number of authors to be able to associate behaviors with any number of elements (that is similar to jQuery).

It also solves the problems with is="" (confusing inheritance patterns limited to only a single class (a single behavior)) and also solves the problems that is="" addresses (f.e. not being able to replace <tr> with <custom-element> inside a table).

@jimmont
Copy link
Author

jimmont commented Sep 7, 2017

Yeah this isn't really about mixins as much as it is about declaratively decorating elements with functionality in a way that hooks into the element lifecycle predictably, and simply too. That seems to be the generally desired capability. As to is= and mixins I figure leave that conversation where its been spinning for a long time and just do something practical that solves the majority of the actual use-cases. See where it goes in the wild and iterate as indicated from further experience.

@annevk
Copy link
Collaborator

annevk commented Sep 8, 2017

@annevk
Copy link
Collaborator

annevk commented Sep 8, 2017

@jimmont OP calls it mixins but now you say it's not mixins? I'm not sure I follow.

@jimmont
Copy link
Author

jimmont commented Sep 8, 2017

I've come to the conclusion that the discussion here isn't focused on practical/pragmatic solutions and am closing this issue. Feel free to discuss or handle further as you wish.

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

4 participants