How to pass a property to an Handlebars helper - ember.js

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

Related

Ember i18n dynamic link inside of translation

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"

Binding HTML strings in Ember.JS

I am using a third party indexing service (Swiftype) to search through my database. The returned records contains a property called highlight. This simply adds <em> tags around matching strings.
I then bind this highlight property in Ember.JS Handlebars as such:
<p> Title: {{highlight.title}} </p>
Which results in the following output:
Title: Example <em>matching</em> text
The browse actually displays the <em> tags, instead of formatting them. I.e. Handlebars is not identifying the HTML tags, and simply printing them as a string.
Is there a way around this?
Thanks!
Handlebars by default escapes html, to prevent escaping, use triple brackets:
<p> Title: {{{highlight.title}}} </p>
See http://handlebarsjs.com/#html-escaping
Ember escapes html because it could be potentional bad code which can be executed. To avoid that use
Ember.Handlebars.SafeString("<em>MyString</em>");
Here are the docs
http://emberjs.com/guides/templates/writing-helpers/
if you've done that you could use {{hightlight.title}} like wished,...
HTH

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.

Ember Handlebars Embed ID

I am trying to use ember to show a dynamic list of found content. The problem is that when I try to put handlebars in html attributes, everything breaks.
RegApp.PatronsFound = Ember.CollectionView.create
tagName: 'table'
content: []
itemViewClass: Ember.View.extend
template: Ember.Handlebars.compile("<td><button onclick='alert({{content.id}})'>{{content.name}}</button>")
RegApp.PatronsFound.appendTo('body')
When it is fed a piece of content with the ID of 3 and the name FOO, I want this html to be generated:
<button onclick="alert(3)">FOO</button>
Instead, I get this:
<button onclick="alert(<script id=" metamorph-4-start'="" type="text/x-placeholder">3<script id="metamorph-4-end" type="text/x-placeholder"></script>)'>FOO</button>
You can use
{{unbound content.id}}
to arbitrarily insert values into your templates. Normally, such values are wrapped in metamorph tags which allow the displayed value to be bound to the backing value, and updated whenever the backing value changes. This only works if the output is regular HTML, not, in this case, spanning event handlers and embedded JS. {{unbound}} inserts the value at that property path once, without metamorph tags, and without being updated if that value changes in the future.

Ember.js Strip Binding Tags

Is there a way to strip binding tags from an ember.js infused handlebars template? I would like to be able to extract just the html without any of the metamorph script tags.
I have this related question but wanted to ask this more general question as well.
You can use the unbound Handlebars helper to do this at the individual property level.
There is work being done on an #unbound block helper, which would be nice for what you're trying to do: https://github.com/emberjs/ember.js/pull/321
Another approach is to, in your views, specify a plain Handlebars template. None of the output will be bound.
App.UnboundView = Ember.View.extend({
template: Handlebars.compile("output is: {{msg}} here"),
msg: "not bound"
});
Here's a jsFiddle example: http://jsfiddle.net/ebryn/zQA4H/
Here's a better way
{{unbound propertyName}}
http://emberjs.com/api/classes/Ember.Handlebars.helpers.html#method_unbound
In case anyone needs this functionality, I created a small jquery plugin to do it:
# Small extension to create a clone of the element without
# metamorph binding tags and ember metadata
$.fn.extend
safeClone: ->
clone = $(#).clone()
# remove content bindings
clone.find('script[id^=metamorph]').remove()
# remove attr bindings
clone.find('*').each ->
$this = $(#)
$.each $this[0].attributes, (index, attr) ->
return if attr.name.indexOf('data-bindattr') == -1
$this.removeAttr(attr.name)
# remove ember IDs
clone.find('[id^=ember]').removeAttr('id')
clone
Still hoping there is a better way.