Passing components in block form to Ember helpers, and rendering them


#1

I want to pass to and render a component inside a helper function.

For example, let’s say I have a helper, t, that, given a String and key-value pairs, returns a string in a given locale. So, for a given string, welcome_user, t could return an English translation: Welcome {{name}}!. Here is the string with its translation, defined in a .yml file:

en:
  welcome_user: 'Welcome {{name}}!'

Naively, {{t 'welcome_user' name=user.name}} would output "Welcome Bob!" if user.name was "Bob".

The problem

Now, what if I want to add some markup around user.name? Ideally, I want to be able to wrap user.name with a component (say, a link to the homepage). Is there a way Ember can allow this?

To help illustrate what I’m trying to do, here’s some really rough interfaces:

{{t 'welcome_user'
  name=({{#link-to 'main'}}
      {{param.user.name}}
    {{/link-to}})
}}

{{!-- or --}}

{{#t 'welcome_user'}}
  {{#param "name"}}
    {{#link-to 'main'}}
      {{param.user.name}}
    {{/link-to}}
  {{/#param}}
{{/t}}

{{!-- or (based off http://www.sitepoint.com/using-inline-partials-and-decorators-with-handlebars-4-0/) --}}

{{t 'welcome_user' name=(partial 'user-name')}}

{{#* inline 'user-name'}}
  {{#link-to 'main'}}
    {{param.user.name}}
  {{/link-to}}
{{/inline}}

In all possibilities, the link-to component is passed as a name argument to t. t will then, somehow, render the component. Is there an easy (or hard) solution to doing this? To clarify, t was a helper only for illustrative purposes. If a solution requires t to be a component, for example, I’m happy to convert.

I believe this is a legitimate need, and important to allow for a couple reasons:

  • This will improve solutions for internationalization and accessibility. This is my biggest motivation and most important reason.
  • We should be able to express powerful ideas in templates.
  • I’d like to avoid shoving HTML into computed properties/helpers.

I don’t have any particular opinion on what the API would look like, just as long as it’s possible to achieve the theoretical use-case I outlined here.

What do y’all think?


#2

Is there a reason why you can’t do something like: {{t 'welcome'}} {{user.name}}? That way, you could format user separately and add a link to it.

Is it the case that the placement of name might be positioned differently within the translated string depending on the language, like it might be 'Welcome {{name}}!' for one language but '{{name}} Welcome!' in another? Can you clarify a bit more why name needs to be passed into the helper?


#3

Is it the case that the placement of name might be positioned differently within the translated string depending on the language, like it might be ‘Welcome {{name}}!’ for one language but ‘{{name}} Welcome!’ in another?

Yep, that’s why; word order isn’t the same in all languages. Interpolation is common in translation libraries, including ember-i18n for that reason.


#4

Could you do something along the lines of what is described here:

In other words, you could write a function that constructs an anchor tag wrapped around name using string interpolation, and then you could use that string in your translation helper. For example, a computed property on the user model could be defined like this:

nameLink: Ember.computed('name', function() {
  let name = get(this, 'name');
  let link = `<a href="/welcome/users/link">${name}</a>`;
  
  return link;
})

And then you could send your computed nameLink string to your translation helper like:

{{t 'welcome_user' name=user.nameLink}}

You may need to mark the HTML string that is returned in the computed property as html safe (check out http://emberjs.com/api/classes/Ember.String.html#method_htmlSafe)