Defining an ID for html element in Emberjs/handlebars fails - javascript

I have following issue here:
<ul class="aClass">
{{#if something}}
<li>{{#link-to "blub" bind-attr data-testid=aID}}{{loc "blub"}}{{/link-to}}</li>
{{/if}}
</ul>
so i want to have an element(the link-to is rendered to ...) in the resulting element with the id aId. But the element does not contain the wanted id in the rendered HTML. something like this:
...
any ideas?

In Ember, bind-attr shouldn't be used inside of your link-to help as that should only be used inside of html elements:
<a {{bind-attr href=myLink}}>My Link</a>
Inside of Handlebars helpers, you just define the property directly.
{{#link-to "blub" data-testID="aID"}}{{loc "blub"}}{{/link-to}}
The attribute is not rendered into the HTML if the quotes are missing.
But you also need to reopen the LinkView:
Ember.LinkView.reopen({
attributeBindings: ['data-testID']
});
See similar question here.
And the Ember docs here.

Try using quotes:
{{#link-to "blub" bind-attr data-testid="aID"}}{{loc "blub"}}{{/link-to}}
A lack of quotes will cause Ember to try a property lookup on the current view context, instead of just spitting out a string as you'd like it to.

Related

Ember generated action or jquery onclick

I have an ember application which works fine. But user's interaction does some DOM insertion like below...
$(.test).append(<a {{action "getData"}}>Get Data</a>);
The problem is that Ember seems do not recognize that an action "getData" has been added to the DOM. Nothing is happening when I click the element. Any thoughts on this?
Another way I am trying to do is:
//create the element
$(.test).append(<a id="idnum">Get Data</a>);
//make click listener
$('#idnum').click(function(){
console.log("get data");
}
my question is where should i place the code inside the component so the it can listen on the click event. Thanks.
You should do it in Ember way. Try handlebars {{#if}} helper to render an element dynamically.
{{#if canGetData}}
<a {{action "getData"}}>Get Data</a>
{{/if}}
Here you can set the value of the canGetData to true in the controller based on the users action.
The first example can't work because ember does not analythe the Handlebars elements in the DOM, but rather parses your Handlebars template with HTMLBars, which is a full HTML parser, and then renders it manually by inserting elements, not text into the DOM.
However the second example is the way to go if you have to rely on external code that does manual DOM manipulation. And it does work. Checkout this twiddle.
This does work:
this.$('.target').append('<a id="idnum">Get Data</a>');
this.$('#idnum').on('click', () => {
alert('clicked');
});
Just make sure that the DOM is ready. So do it in the didInsertElement hook or after the user clicked a button or so.
Like Lux suggested avoid DOM manipulation. I prefer the following approach,
if it is dynamic then you can consider wrapping DOM element as a new component and use component helper.
find sample twiddle
In application.js
export default Ember.Controller.extend({
appName: 'Ember Twiddle',
linksArray:[ Ember.Object.create({value:'Text to display',routename:'home'}),
Ember.Object.create({value:'Text to display2',routename:'home'})],
actions:{
addItem(){
this.get('linksArray').pushObject(Ember.Object.create({value:'AddedDynamically',routename:'home'}));
}
}
});
in Application.hbs
<h1>Welcome to {{appName}}</h1>
<br>
{{#each linksArray as |item|}}
{{component 'link-to' item.value item.route }}
{{/each}}
<button {{action 'addItem'}}>Add Item</button>
<br>
{{outlet}}
<br>
<br>

Rendering dynamically generated {{link-to}} links in an Ember.js Handlebar template expression

I have an Ember template that is rendering text with a Handlebar expression, i.e. {{caption}}. The text being rendered has hashtags in it, each of which I need to make clickable, and going to a specific route in the Ember app.
I created a helper to parse the text and replace each hashtag with a link to the necessary route combined with the hashtag, so now the Handlebar expression looks like: {{clickable-hashtags caption}}. However, the helper creates the links using regular HTML <a href> tags, and this is returned using Ember.Handlebars.SafeString.
I would like to use Ember's {{#link-to}} helper method for each hashtag instead, but can't seem to figure out how to do that. Is it possible for Handlebars to parse out the link-to tags within the template's {{caption}} expression?
Well, you could do it with an computed property
The caption:
This is my #hashtag caption
In controller:
computedCaption: function () {
var words = caption.split(" ");
return words.map(function (e) {
var isHashtag = e.charAt(0) === "#";
return {isHashtag: isHashtag, text: e};
});
}.property("computedCaption")
Template:
{{#each computedCaption as |cap|}}
{{#if cap.isHashtag}}
{{#link-to 'tags' cap.text}}{{cap.text}}{{/link-to}}
{{else}}
{{cap.text}}
{{/if}}
{{/each}}
Result
This is my #hashtag
caption
JS Bin: http://emberjs.jsbin.com/kohubu/1/
Computed properties # Emberjs
The problem I see with doing it that way is not being able to bind variables (and helper results) to the link-to helper. The work around I would use would be to use actions and to move your helper logic into the controller.
Define the transitionTo action in the application route:
App.ApplicationRoute = Ember.Route.extend({
events: {
transitionTo: function (route) {
this.transitionTo(route);
}
}
});
Template:
{{#each item in controller.captions}} <!-- or instead use model-->
<li>
<a {{action 'transitionTo' item.route}}> <!-- without hashtags -->
{{item.label}} <!-- with hashtags -->
</a>
</li>
{{/each}}
Have you considered doing client-side HTML compilation?
I'm thinking you'll need to install the necessary helpers (i.e. link-to) and pass in variable values. This test may be of some help getting there.

Ember bind-attr not updating

I have a view with the following:
App.MyView = Ember.View.extend({
isSet: false,
layoutName: 'myview',
click: function() {
this.set('isSet', !this.get('isSet'));
}
};
And the template for it:
<i {{bind-attr class=":fa isSet:fa-check"}}></i> Toggle
The click event is working fine, and updates isSet (I can see that in ember inspector), but the bound class does not get added. Is there something wrong in my logic?
Use view.isSet instead of isSet in your template.
<i {{bind-attr class=":fa view.isSet:fa-check"}}></i> Toggle
Another possible solution, not to the OP's problem but to one with a similar title.
When using bind-attr to bind property changes and element class, it is important to include also static class mapping inside the bind-attr helper and not in a separate, static, class attribute.
This will not always work:
<div class="round" {{bind-attr class="highlighted:hl"}}>Inner text</div>
The correct way is:
<div {{bind-attr class=":round highlighted:hl"}}>Inner text</div>
If you are using above ember 1.11
then use the below tag
Reference :
http://www.hutchinson.io/bind-attr-is-dead/

Ember - how to render a view's property without html

I have an Ember view with the currentUrl property; this property gets the value when the view is called, like this:
{{view App.MyView currentUrl="www.website.com"}}
and in the view's template i have something like this:
<a href="{{view.currentUrl}}">
but this does not work because the output of handlebar expression is:
<script%20id='metamorph-4-start'%20type='text/x-placeholder'></script>www.website.com<script%20id='metamorph-4-end'%20type='text/x-placeholder'></script>
and not only www.website.com as I would like; do you know how can I get an output without the HTML?
Perhaps you can use the {{unbound}} helper here.
<a href="{{unbound view.currentUrl}}">
or the {{bind-attr}} helper
<a {{bind-attr href="view.currentUrl"}}>
depending if you want the property to be live updated (bind-attr) or not (unbound)

How to use the parentView.template in N nested children in EmberJS

here is what I'm trying to do:
I want to create a tree widget in emberjs that will look like:
{{view UI.TreeView content="App.rootNode"}}
{{name}} //-> content of each node, it could be <img src="{{icon}}" /> {{name}}
{{/view}}
The problem I'm facing is how to use the inner template in my itemViewClass.
Here is what I came up with so far: http://jsfiddle.net/YJ7zM/13/
Relevant line:
template: Em.Handlebars.compile("{{name}} {{view UI.TreeChildrenView contentBinding=\"children\"}}")
That's the line I don't like and would like to replace with something more like:
templateBinding: "parentView.template"
The problem is that "parentView" will only work for the first level of the tree, for the other ones it would be "parentView.parentView.template" and so go.
You could always define the template externally and use templateName...
http://jsfiddle.net/YJ7zM/14/
edit
Revised to address first comment. http://jsfiddle.net/ud3323/mgCva/

Categories