Custom datatype support in View attributeBindings and bindAttr


#1

Currently, the only attribute types supported are strings, numbers and booleans. Attempts to use other datatypes are met with:

Assertion Failed: Attributes must be numbers, strings or booleans, not <type>

EmberData already has a mechanism to define how objects are serialized. I would expect that views use the serializer that is already defined for the datatype. If the view requires a different serialization format, then by all means, add another computed property. But barring further customizations, a custom datatype (that already knows how to serialize itself) should be supported by Ember views. At the very least, invoking .toString() on the attribute would be a reasonable default.

As it stands, the value of a custom datatype is greatly diminished if I have to define its serialization mechanism twice (in the Transform and a computed property just for the view).


#2

While I don’t agree that templates should know anything about transforms, I do think that invoking toString() seems sane. Ember already does this for models (if I put {{model}} in a template it displays <App.MyModel@...> which is the toString() form.

The code that throws the exception is at https://github.com/emberjs/ember.js/blob/53290cc70fb5befe6343cb7c11c56014f4736dc6/packages_es6/ember-handlebars/lib/helpers/binding.js#L666. Seems like we might be able to bind to the original path, but display the .toString() version in the handlebarsGet helper.


#3

While I would be happy to at least have some default (whether it’s toString or Transform#serialize()) I’d be remiss if I didn’t point out that not all attributes emitted in a template are visible by the user.

The concern that server-serialization and client-serialization are different is valid. However, that assumes that client-serialization is user-visible. Indeed, I would imagine that anything user-visible would already have some (or many) computed properties to generate UX-friendly formats. Further, I would hypothesize that the client/server serializations of user-invisible attributes would, in general, be the same.

Therefore I strongly believe the default serialization of an attribute should use the datatype’s Transform#serialize method. (Precisely because the user-visible form would already require a computed property anyhow.)


#4

Interested… What use case do you have that requires other things to be reified into attribute bindings?


#5

Two use cases, actually.

My custom datatype is a URI. (using URI.js) My UriTransform is a subclass of StringTransform with #deserialize overridden to invoke new URI(serialized). I have a number of computed properties based on the uri that display certain components of the uri (subdomain and path, for example). These computed properties are for visual display to the user. However, the attribute bindings for which I would expect the template to use the transform’s #serialize method emit the whole uri as a string into @href and @title attributes.

Additionally, I have some Date attributes which are serialized into the @datetime attribute of time elements.


#6

But isn’t that a prime case for using a component? Views are pretty much only for output and event gathering, from my understanding. Components are for more complicated interactions with different types of data.

Connecting types to template bindings seems quite a lot like violation of separation of concerns for the view layer (ie templates, ie handlebars) to me. Handlebars should know about the DOM and about text, and numbers and simple data constructs… for anything else, it should be abstracted into a component, or some other controller-backed thing. (no?)

It’s a similar problem to putting logic into the view… I realise some of this will be possible when htmlbars hits, but I don’t necessarily consider it a good thing.


#7

I agree on principle, except that the transform defines how to serialize a thing to text. That’s precisely what the view needs. I’m not suggesting that the template bindings should know anything about the datatype.

TBH, I haven’t looked at how the Transforms are invoked. So I would agree that it’s not great if the view has to lookup the correct transform to apply it to the object. However, I would imagine a better scenario wherein the data object’s toString delegated to its Transform#serialize method. In this case, the view/template would have zero knowledge of the transform or custom datatype. It simply invokes toString on anything it’s given.

FWIW, in my particular case because the datatype needed multiple text formats, it did make sense to make a component. And that’s exactly what I would expect to do for any datatype that needed multiple representations in the view/template. But I believe the more common use case is for a custom datatype that has a primary serialization format (which would be codified in the Transform). It makes sense for the view/template to default to the primary serialization, as opposed to throwing errors as it does now.