Skip to content

Instantly share code, notes, and snippets.

@geelen
Last active August 29, 2015 14:04
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save geelen/2e314d9c547b752603fd to your computer and use it in GitHub Desktop.
Save geelen/2e314d9c547b752603fd to your computer and use it in GitHub Desktop.
Web Component design thoughts

Web Component design thoughts

It feels like I'm facing the same thing the same problems writing the API of these components. In particular:

  • A component might have several distinct modes. As in, an <x-gif speed="1.0"> has a very different playback mode from <x-gif bpm="120">, so you shouldn't be allowed to have both speed and bpm. But it doesn't seem right to break them into separate components, so either one takes precedence or having both present causes an explosion.
  • A component might require more than one attribute to be valid. As in, <x-beat midi channel="0" note="65">. Until you have both the channel and note you can't make connection to the midi signal. But if you're driving the component with a framework like angular, it will first render incompletely (as <x-beat midi channel="{{ channel }}" note="{{ note }}">), then after a $digest will insert the right values. So a component may need to permit being in an invalid state temporarily, then when all attributes are set go and get set up.

The first bit feels like command-line options-parsing, but the second one is trickier. You have this stateful lifecycle of these components and tracking all the potential changes is really hard. Thoughts?

Feels like we need a declarative way of describing a component API that understands the different kinds of attributes, to reduce some of this complexity. Unless... some work like this has already been done. Like within x-tag or something?

@potch
Copy link

potch commented Aug 4, 2014

Should these components explode, as you say?? The tradition of HTML and the DOM is all about failing gracefully.

In the mutual exclusion case above, if speed and bpm are a mutual exclusion, picking one to always 'win' seems more humane than having neither work.

In the case of insufficient attributes to be valid, the tradition is to fail silently. Then, the moment all the right attributes are in place, the machine can spin to life. This will very comfortably allow for lazy initialization.

My procedure would be (and has been) something kind-of like state machine:

  1. Attribute is changed
  2. Re-evaluate the world to see if we are in a different mode, such as going from speed to bpm, or going from invalid to working and back again.
  3. Move to the new state (might involve re-initializing the component).

I'm very inclined to avoid some meta-layer around attribute relationships.

@geelen
Copy link
Author

geelen commented Aug 4, 2014

As am I, that's just where my thinking was leading me down, and so I needed to pop my head up and consider alternatives :)

I agree that it does make more sense in a HTML environment to fail silently, so yes, let's just say that speed takes precedence over bpm. That I think solves #1.

Do you have some examples of this state-change-based attribute handling? Coming from Polymer, the way I ended up doing this is a method for each attribute change, and different amounts of work needed for each one. But it feels messy, like each attribute needs far too much knowledge of its relationship with the rest of the component. Example here: https://github.com/geelen/x-gif/blob/gh-pages/src/x-gif.js#L23-L50

@Catharz
Copy link

Catharz commented Aug 4, 2014

Newbie at this stuff, and googling-as-I-go. If any of the following is impossible and/or dumb. I'd love to learn why. :)

With speed vs bpm, I'd give precedence to whichever value makes your code cleaner further down the line and document that it overrides the other. In a perfect world, I'd use pattern matching. But I don't know of any good pattern matching libraries for JavaScript or dealing with custom HTML tags.

If you don't want an 80s Hollywood representation of computer sounds, you will need to to wait until every tag is populated before any of them can be processed. Otherwise, delayed or out-of-order population of any elements will totally screw with the output. So the components will definitely be in an invalid state at some stage. Can something like MutationObservers help here? https://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#mutation-observers

@potch
Copy link

potch commented Aug 4, 2014

I'd say that attributes are pretty necessarily intertwined with the rest of their components. We tend not to coerce attributes into property members of the element other than for convenience, and then frequently use the attribute of the source of truth. For example, an element with a src attribute can have a getter and setter for .src that just gets and sets the attribute.

@sole
Copy link

sole commented Aug 5, 2014

hiii~

So the way I've done it before is, each time some attribute "that changes everything" changes its value, I just call the internal init function again to make sure everything is in order.

This is slightly inefficient if you change some attributes that trigger this init function several times, and it's also prone to infinite loops if you're not careful with what triggers what--sometimes you might want to change the internal value and not via the attribute so that the changed event does not trigger a full update event, if you know what I mean.

Also, I always try to make sure the elements start in a consistent initial state. That means giving their attributes sensible values to start with and calling init immediately after that.

Maybe there are better ways of doing this. I'm totally open to improving this workflow!

Re: attribute precedence. Pick one and use it? It might feel weird to be specifying two opposite things in a custom element but imagine something like this:

<p style="color: green;" class="red">aaaah</p>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment