Ember i18n dynamic link inside of translation - ember.js

I was wondering how I could pass a link into to {{t}} helper. I am using v3.0.1 of Ember i18n at the moment.
Obviously you cannot pass a link helper into a t helper (something like
{{ t "some-translation-string" link={{#link-to 'page' model}}page{{/link-to}} }}
won't work of course).
So I was thinking, maybe I can create a custom prop that returns a whole link. But then again, how do I create that link?. Does anyone know of a method that has the same arguments as the link-to helper, but returns just the link (In my case 'page' and model)?

You might be able to achieve that with a basic link, but I doubt that you'll be able to toss a live link-to component inside a translation.
So instead split your translation string into pieces:
{{t 'goToSettingPage-before'}}
{{link-to (t 'goToSettingPage-link') 'route.name'}}
{{t 'goToSettingPage-after'}}
'goToSettingPage-before': 'Go to'
'goToSettingPage-link': 'settings'
'goToSettingPage-after': 'page.'

You can create a helper to do exactly what you want using ember-href-to.
Helper:
compute (params) {
const i18n = this.get('i18n');
const target = hrefTo(this, params[1]);
// const targetParam = params[2]; //dynamic segment
const text = i18n.t(params[0]);
return Ember.String.htmlSafe('<a href='+ target +'>' + text +'</a>');
}
Template usage:
{{t "linkExample-learnMore" link=(helper-name 'linkExample-here' 'some.route')}}
Translations:
"linkExample-learnMore": "Click {{{link}}} to do something",
"linkExample-here":"here"

Related

Ember helper has undefined values

I can't figure out why the helper I created in app/helpers/shop-name.js:
import { helper } from '#ember/component/helper';
export function shopName(shop) {
return shop.identifier + '-' + shop.name;
}
export default helper(shopName);
doe not format the values as needed in my template application.hbs:
<select>
{{#each model as |shop|}}
<option value={{shop.id}}>{{shop-name shop}}</option>
{{/each}}
</select>
I get undefined-undefined displayed in my select list.
If I do the same conversion directly in the template:
<option value={{shop.id}}>{{shop.identifier}}-{{shop.name}}</option>
it works as needed. What's wrong with that helper ?
I'm using Ember 3.0.
Thank you.
I'm not sure that helpers can take inputs that aren't strings. I hope someone can confirm.
Anyway, your use case is really better handled at the model level, using a computed property:
shopName: computed('identifier', 'name', function() {
return `${identifier} - ${name}`;
})
and then you would just use {{shop.shopName}} in your template
There are multiple issues in your code.
shop is an object and I bet it's an Ember.Object. If dealing with Ember.Objects, you should always use get() method to retrieve values for now. This might change soon. Since you are not using get() method, you get undefined. Embers template engine is using getter and therefore it's a huge difference between shop.identifier in your helper and {{shop.identifier}} in your template. Resolve the issue by shop.get('identifier') or import { get } from '#ember/object'; [...] get(shop, 'identifier'); Use the last one if you can't be sure that shop is an instance of Ember.Object.
Since you are passing shop and not shop.identifier as argument to your helper, the helper will only be recomputed if the reference of shop changes (e.g. replaced by another object). Changes to the value of it's properties will not recompute the helper.
One solution for you problem is to use a computed property as suggested by ctcpip. Another one is the concat helper: {{concat shop.identifier '-' shop.name}}.

How can I write custom handlebars in Ember js?

js:
Ember.Handlebars.registerHelper('demo-helper', function (property, options) {
console.log('demo helper');
return '<li><a> '+ msg+'</a></li>';
});
hbs :
{{#demo-helper}} msg {{/demo-helper}}
How can I wrap hi (inner html of handlebar) with any custom tag?.I know that component has tag parameter that encapsulates html with given tag. But it supports only one tag. I want to encapsulate with multiple tags like
<li><a>innerhtml</a></li>
This is what components are for. They have can have an arbitrarily sized template. You can use {{yield}} to nest other html inside the component.
See https://guides.emberjs.com/v2.15.0/components/wrapping-content-in-a-component/.
component template:
<div><div><div>{{yield}}</div></div></div>
usage:
{{#my-component}} Hello world {{/my-component>}}
Components are very powerful and have many other options, see the guides for more info. They are the best resource.

How to extensively configure an Ember.Component

I am creating an Ember.Component which displays a CRUD table. As the component shall be reusable it needs a lot configuration, such as columns to display, pagination options, etc. ...
At the moment I am inserting the component using handlebars:
<div class="some-div">
{{power-table items=this.model columns='...'}}
</div>
I wouldn't want to use this nice way of inserting a component. However, it is pot really possible to extensively configure a component here, is it? I found out it's not even possible to pass an object as parameter, e.g. the following it not possible:
<div class="some-div">
{{power-table items=this.model columns=[id, name, foo, bar] }}
</div>
How and where should I configure the component?
What you can do is that instead of setting columns=[id,name,foo,bar] in the handlebar like this:
<div class="some-div">
{{power-table items=this.model columns=[id, name, foo, bar] }}
</div>
You can set the columns property in the controller for the handlebar template and use the name of the property in the handlebar file. So all the logic would come from the controller and the handlebar would just tell which property is accessible in the component and by what name. So the controller for the enclosing template would be the best place to heavily configure the component. Have a look at the following page for more info:
http://emberjs.com/guides/components/passing-properties-to-a-component/
I am not sure if I understood your problem correctly.

backbone/marionette attaching HTML into a region

I'm beginning to use Marionette within an existing backbone application. I've got some HTML which I want to append into a region. In pure backbone, I could just do this.$el.append(html_code) and that was all. As far as I can see, marionette regions allow only to operate on views (which have to implement the render method). Calling append on marionette region throws 'undefined method' errors.
Is it possible to attach plain HTML to a marionette region?
No, it's not possible to inject plain html into a Marionette.Region.
Theoretically you could access a regions DOM element with someRegion.el or someRegion.getElement(), but this must be done after rendering (which at least isn't possible inside a Marionette.View with standard behaviour).
But you can achieve the desired result by using a specially crafted Marionette.ItemView:
#someRegion.show(new Marionette.ItemView({template: '<h1>gach</h1>'}));
You maybe also should have a look at Marionette.Renderer .
a Marionette ItemView will look for a template and will call render on that template, so when you show the view in the region the html will be displayed just fine with out the need of you defining a render method.
MyImtemView = Backbone.Marionete.ItemView.extend({
template : "#myTemplate"
});
var myItemView = new MyItemView();
myLayout.aregion.show(myItemview);
this should work if you save your html in a template like this
`<script id="myTemplate" type="text/template">
<div><p>your html<p>
</div>
`
EDIT
you can also declare a render function in your view in case you need to generate and modify your html like this.
MyImtemView = Backbone.Marionete.ItemView.extend({
template : "#myTemplate",
render : function (){
this.$el.append(HMTL); //so here you work your html as you need
}
});
var myItemView = new MyItemView();
myLayout.aregion.show(myItemview); //the render function of your view will be called here
I ran into the same problem and tried the answers explained here, but I'm also using require.js and kept getting an error for the #my_view template not being found. If anyone can clarify where does Marionette look up the templates by default, that would be great.
Instead, I solved it by using the text.js plugin for underscore.js. This way you actually can use a plain html file as the template, without the need for nesting it in a script tag. Here's how I did it.
define(['backbone', 'underscore', 'marionette', 'text!tmpl/my_view.html'], function(Backbone, _, Marionette, view_t){
var MyView = Backbone.Marionette.ItemView.extend({
template : function(serialized_model) {
//define your parameters here
param1 = erialized_model.param1;
return _.template(view_t)({
param1: param1
});
}
});
return MyView;
});
I placed the text.js plugin in the same lib directory as all my other js libraries and my main.js for require declares the path to the templates as
'tmpl': '../../templates',
My project structure looks like this
root
index.html
js
main.js
app
App.js
views
MyView.js
lib
require.js
text.js
backbone.js
underscore.js
jquery.js
backbone.marionette.js
templates
my_view.html
My template 'my_view.html' simply looks like this.
<h1>THIS IS FROM THE TEMPLATE!!!</h1>
Worked perfectly. I hope you find it useful.
Using a view
var myHtml = '<h1>Hello world!</h1>';
var myView = new Marionette.ItemView({template: _.constant(myHtml)});
myRegion.show(myView);
Marionette.Renderer.render takes either a function or the name of a template (source code). _.constant creates a function that returns the passed-in parameter.
Attaching HTML
Alternately, the docs for Marionette.Region mention overriding the attachHtml method, see Set How View's el Is Attached.

How to pass a property to an Handlebars helper

I am trying to register a Handlebars.js helper in my Ember.js app that will allow me to pass in a view property that is a simple html string to be rendered without being escaped. My template looks like this:
<span class="add-on">{{log view.append}}{{safeMarkup view.append}}</span>
In this case the log statement outputs the html string properly to the console, something like <span>text</span>.
My helper, safeMarkup, is as follows:
Handlebars.registerHelper('safeMarkup', (string) ->
return new Handlebars.SafeString(string)
)
Yet, what gets rendered is not the value of the view.append property but the string "view.append" itself! Like so: <span class="add-on">view.append</span>. Any ideas what's going wrong here?
Thanks
In handlebar:
{{span 'className'}}
In app:
Handlebars.registerHelper('span', function(className) {
return new Handlebars.SafeString("<span class='"+Handlebars.Utils.escapeExpression(className)+"'></span>");
});
You can also use triple-mustache to avoid escaping of the html string...
http://jsbin.com/imafuq/8/edit