What are the differences between using <compose view-model="./my-element"> and <my-element>? What are some scenarios where one is more suitable?
Asked Answered
M

4

6

A teammate and I have been building an application in Aurelia for the last four months, and he and I have been creating and using components in these two different ways. I want to have some consistency and change everything over to one of the two styles, but I don't know which one is preferred or more suitable for our needs.

I chose to use <compose> because to me it feels cleaner and suits every need I have encountered, but if using the custom element is objectively better I want to switch to that.

For example:

(his-way view-model:)

import { bindable, bindingMode } from 'aurelia-framework';

export class HisWay {
  @bindable({ defaultBindingMode: bindingMode.twoWay }) data;
}

(his-way view:)

<require from="./his-way"></require>
<his-way data.two-way="myModel" containerless></project-name>

(my-way view-model:)

export class MyWay {
  activate(model) {
    this.model = model;
  }
}

(my-way view:)

<compose view-model="./my-way" model.bind="myModel" containerless></compose>

Do I need to change over, and if not, what are some reasons I can use to persuade him to using the same style that I have been using?

Mikimikihisa answered 11/8, 2016 at 1:50 Comment(5)
One difference is the custom-element tag, wich I find very useful for my CSS. That is reason for me to use <his-way> instead of <compose view-model="./my-way">.Mutate
Our designer doesn't like the dealing with the custom elements themselves, which is why we use containerless everywhere. I can't say I agree with the sentiment.Mikimikihisa
When using <compose> you can render a component that will be defined at run time. For instance, <compose view-model.bind="someViewModel" view.bind="someView"></compose>. Another advantage is that with <compose> you can reuse views and view-models. You can use the same view for 2 different componentsRefugee
@FabioLuz These are good points, and I forgot about them although I have used <compose> in this way already. Thanks!Mikimikihisa
You can although make the choice of the view dynamic for a component as well by using useViewStrategy()Cushat
G
9

Use the custom element approach when possible.

Compose targets dynamic scenarios. If your <compose> element's view and view-model attribute values are static (not data-bound) you probably should have used a custom element for the reasons described below.

Portablity: Custom elements are more portable because they have a higher degree of encapsulation. A custom element's template cannot access the outer scope, all data must be passed in via @bindable properties. This contrasts with <compose>, which allows accessing the outer scope, making it very easy to get sloppy and make assumptions about the environment in which a composed view will be used.

Features: Custom elements have more features than the <compose> element. Template parts/slots (transclusion), bindable properties, ability to "globalize" via globalResources and more.

Reuse: It's much easier for a team to reuse a widget when it's encapsulated in a custom element and globalized via globalResources. The team can simply write <mega-widget ...></mega-widget> as opposed to having to remember the relative path to mega-widget.html and mega-widget.js and write a valid <compose view="..." view-model="..."></compose> expression.

Better fit: Any use-case where you are creating a data-entry widget really deserves a custom element. It's far easier to use a currency custom element- eg: <currency value.bind="unitCost"></currency> than it would be to try and achieve similar results with <compose>. Not sure how you would accomplish it really.

CSS: it's easier to target a custom element with css selectors than a specific compose element instance. mega-element { display: block; ... }

https://www.danyow.net/aurelia-custom-element-vs-compose/

Guardsman answered 12/8, 2016 at 14:28 Comment(2)
This is exactly the kind of response I was hoping for. Thank you.Mikimikihisa
This is a great explanation. I will recommend that you request this to be added to the official docs. As a new Aurelia learner, this was much more helpful than what's currently there.Indochina
C
1

I personally wouldn't force yourself into only using a certain approach. Most frameworks suffer from the fact that they try to convince you that there is only one winning paradigm. But thats not true since each project, and even inside the project each requirement can be completely different.

So when looking at whether to render components using the custom element name vs compose, first ask yourself what is the design goal you want to achieve. Unification in my opinion is not enough.

Going only with the custom-element approach is great because its easy to read and easy to get going for a kinda static page structure. On the other hand if your page requires a lot of dynamic composition, the composed approach as the name suggests is the way to go.

So I'd tend to agree that compose is better or lets say more flexible, but at the same time also kinda verbose.

One argument against compose can be the use of custom attributes. E.g. if you use aurelia-i18n and would like to use the attribute-translation approach, you'd be better off using the custom-element syntax. So as you see its really all about the use-case.

EDIT:

If we really want to go down to the nitty gritty, the best argument for the custom element approach is that compose itself is actually nothing more than a custom element.

Cushat answered 11/8, 2016 at 13:55 Comment(2)
For consistency sake, I would like to move everything to one style except where it makes sense to use the other style. Bringing a new developer into a project that uses both styles willy nilly for no rhyme or reason would just take a little longer to explain that they both essentially are doing the same thing (although they don't necessarily in some cases). I find it interesting that you think using <compose> is more verbose; after all the imports, @bindable decorator, and <require>, in my opinion the <compose> lifestyle is easier on the eyes, but maybe I am alone on that!Mikimikihisa
Well partially, you can omit the require if you do a global registration of the component. Also clearly defined attributes might describe the purpose better instead of a object passed to the model. So as such its really just a matter of tasteCushat
H
1

The answer is no. You don't need to switch over for situations like the example provided. The Compose element (i.e. Components) and Custom Elements solve different problems. The former allows you to compose a view or view and viewmodel pair into another view. The default behavior matches up views and viewmodels based on name but I understand you could actually bind a different viewmodel each time (which might give some interesting uses in say, a for loop.) I use Components when I want to break a larger view down into more manageable chunks. I will also use them where I want code reuse, but I am not looking to customize it too much from one use to another e.g. footer, navigation.

Custom Elements I understand are basically WebComponents, an evolving web standard that takes advantage of the Shadow DOM. (You can read more about that at links below.) While similar, they have a lot more power than a simple Component and IMO a greater ability for reuse. Unlike a Component, a Custom Element can have a range of bound attributes and therefore give you more control over it as you use it in a view. The example of your teammate's doesn't really do them justice. One could argue that a Component would be a better choice in that situation.

Horowitz answered 12/8, 2016 at 2:36 Comment(0)
T
1

Another important aspect to understand between the compose element and a custom element is the life cycle that is invoked.

Using compose element will invoke the activate(params) of the Navigation Life Cycle, as well as the usual Component Life Cycle (created, bind, attached, detached, unbind).

This can be useful, and a nuance.

Trampoline answered 24/5, 2017 at 14:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.