Ember JS/Handlebars view helper - ember.js

Currently, if we define our view as {{#view App.myView}}, ember/handlebars will wrap the view element inside a <div id="ember-1234" class='ember-view'>.
Is there a way to stop this?

You probably want to set tagName as ''.
App.MyView = Em.View.extend({
tagName: ''
});
At least it stops wrapping inner contents.

If you want to customize view element's id, you can use:
{{#view App.myView id="my-id"}}

I usually think my views as wrapper. For example, if the initial given html code is :
<div class="item"><p>my stuff></p></div>
Then I create a view with a tagName property as "div" (which is default), and classNames property as "item". This will render, with proper handlebars template :
{#view App.myView}
<p>my stuff></p>
{/view}
-> render as
<div id="ember-1234" class="ember-view item">
<p>my stuff></p>
</div>
Then if you need to have your proper ID on this div, you could define the "elementId" property on your view class (before create()). (#see source code)

I assume you are talking about the 'ember-view' class which is not customizable (element type being customizable thanks to the tagName attribute...).
Actually, Ember later uses this class to register (once!) an event listener on the document in order to dispatch events to the JS view.
I don't mind it would be that simpler to avoid using this class. There would have to find another way to select all ember's controlled element, but I have no idea how.
See source, # line 117.

If I understand you correctly you want to achieve something like jQuery's replaceWith? You can use this in Ember.js when my Pull Request gets merged: https://github.com/emberjs/ember.js/pull/574.
Also have a look at Create Ember View from a jQuery object

Related

Get contents of Meteor template

I have the following Meteor template:
<template name="homeBoxTpl">
<div>
Some content
</div>
</template>
I have an event binding so that when a button on the page is clicked it should get the html contents of the template "homeBoxTpl" - how can this be achieved?
What you need is an event handler, and like Chase say you can access the content of meteor templates using jquery, but meteor has its own way. In order to get a copy of the html, you can place a wrapper round the content in the template, then do this:
Template.homeBoxTpl.events({
'click #someButton':function(e,t){
var templateContents = t.$('.wrapperInTemplate').html();
}
})
Here we are using Template.$ wich returns a jQuery object of those same elements.
Take a look into Template.instances for more information
Just to clarify, where is the button? Is it in another template? I assume you only render homeBoxTpl once.
In which case the event handler for the template where your button exists will have no reference to another template instance. There is no global lookup where you can find all rendered instances of a specific Template
You will have to set an unique identifier "id" for it, or some other discerning info such as a class/attribute and find it via old fashioned JS DOM selectors/traversal.
document.getElementById is fastest, but if there are multiple instances of that template, t.firstNode does give you a good starting point for the DOM traversal.
However making your code dependent on a specific DOM layout is bad practice / too much coupling. Is there any reason why the data underlying that Template's HTML content isn't available somewhere else like a session or collection? It would perhaps be more flexible too to access the data not the HTML.
You can use jquery to access what you need. For example, if you have the following template:
<template name="homeBoxTpl">
<div class="content-container">
Some content
</div>
<button id="btn" type="button">Click me</button>
</template>
Then use the following javascript:
Template.homeBoxTpl.events({
'click #btn': function(e) {
e.preventDefault();
var content = $(".content-container").text();
console.log(content); //Result is "Some content"
}
});

Accessing model data in router when using a view

I am looking for a way to access model data in a route when using a view to display model attributes.
Example
Template
<h2>New post</h2>
<form {{action save model on="submit"}}>
<label>Title</label>
{{input type="text" value=title placeholder="title" id="title"}}
<label>Text</label>
{{view "tinymce" value=text }}
<button>Post</button>
</form>
View Template
<textarea id="tinymce">
</textarea>
View
export default Ember.View.extend({
templateName: 'views/tinymce-textarea',
didInsertElement: function() {
tinymce.EditorManager.execCommand('mceRemoveEditor',true, 'tinymce');
tinymce.EditorManager.execCommand('mceAddEditor',true, 'tinymce');
}
});
Router
export default Ember.Route.extend({
....
actions : {
save : function(model) {
if (!model.get('title').trim() || !model.get('text').trim()) {
return;
}
model.save().then(this.onSuccessfulSave.bind(this), this.onFailedSave.bind(this));
}
}
});
Now, obviously this doesn't work, since model.text is never bound in the view, like it would be if I were to use the textarea template helper:
{{textarea value=text placeholder="text" id="text"}}
But this is just one of many (many) ways I have tried to get this to work, and I am at a complete loss as how one would access model attributes in the route when using a view. And it does seem like a pretty common usecase to me too.
I have failed to find information regarding this on SO or anywhere else, so if anyone is able to help me, thanks in advance! / AS.
So one of the main things that you're missing out is binding the view to the controller. This is actually really straight forward to do, but without it Ember doesn't know that it should propagate changes between the two. The first thing I would do is this:
{{view "tinymce" valueBinding="text" }}
This says that the views value will be binded to the controller's text value. Whenever view's value is updated, it will propogate to the controller and vice versa.
The next item to take care of is actually binding the value in the view. All you need to do is tell the input to bind it's value to the view's value. This can be done like this
{{textarea value="view.value" placeholder="text" id="text"}}
Try this out, and you can use this jsbin that I created as an example:
http://emberjs.jsbin.com/qanudu/26/
If you have any other questions just let me know, but this should solve your issues!

How do I setup an Ember View class to be appended to a particular container?

Ember.View has a nice method called .appendTo("#container") which would allow me to specify a container div for the view. However, when I use the router and .connectOutlet method, an instance of my view is created automatically based on convention and is added to the page body element by default. Is there a way to configure the class definition of the view so that upon creation it will be inside my desired #container. Here is my view:
Jimux.BuildsView = Em.View.extend({
templateName: 'builds',
appendTo: '#jimux-header', #this was just a guess and did not work. but does some propery like this exist for the view?
tagName: 'div',
listVisible: true,
...
Another way to ask this question is: how do I tell Ember router to append a view to a particular item in the dom? By default the router appends the view to the body.
And here is the router bit:
# Connect builds controller to builds view
router.get('applicationController').connectOutlet("builds","builds", Jimux.buildsController)
To clarify, I dont want to put my whole Ember app in a container. I have several views in my application, and most of them are fine directly in the body. But there are a couple like the one mentioned in this question, which I want to put inside "#application-header" div.
You can specify the root element for your application object.
window.App = Ember.Application.create({
rootElement: '#ember-app'
});
Edit:
Having re-read your question, I think you should look into named outlets, so you could do something like:
<div id="application-header">
{{outlet builds}}
</div>
{{outlet}}
well..after understanding your question, i remember having same trouble. Also, thing is i didn't find any way to do this even after going through the Ember code. But later i understood that its for good purpose only. I know you already might have come across with handlebars with which we can acheive this. If we give a view a ID to get appended, we are constraining the application and the whole use of ember becomes useless. Ok coming to you question, as far as i know, we can acheive that appending mustache templates in you div element of HTML.
<div id="jimux-header">
{{view Jimux.BuildsView}}
</div>
This way we can use the Jimux.BuildsView where ever you want and as many times possible. The Beauty of Ember you have to say...
Just add rootElement in the application object.
var App = Ember.Application.create({
rootElement: '#container'
});

emberjs bind data attributes

I am wondering if there is a way to bind data attributes in a template when calling a view.
For example (this doesn't work):
{{ view App.SomeView data-dateBinding="currentDate" }}
I have ended up doing it this way:
<a {{bindAttr data-date="currentDate"}}></a>
There must be a way to do it when calling the view?
More on the excellent answer from #kurt-ruppel.
An example using : to describe the property for attribute binding, entirely done from the view.
App.SomeView = Ember.View.extend({
attributeBindings: ["date:data-date"],
date: function() { return '1642-12-06' }
.... rest of view
})
The cleaner template.
{{view App.SomeView}}
You have to define in App.SomeView which attributes you want put in the HTML.
App.SomeView = Ember.View.extend({
attributeBindings: ["data-date"]
.... rest of view
})
Now data-dateBinding should work:
{{view App.SomeView data-dateBinding="currentDate" }}
FWIW - and this is in response to #sly7_7's comments from the top answer -, it is possible to specify a data-* attribute binding in the view itself, as opposed to setting it in the template.
Similar to classNameBindings, you can prepend a preferred value to the attribute, joining the values with a ':'. Best place to see this in action is probably in the related ember.js tests. Gives credence to the value of good testing, seeing as how sometimes it serves as the best documentation.

how can i unbind an emberjs handlebar helper

I have a custom handlebar helper:
Handlebars.registerHelper('foo', function(key) {
return (key + ' bar');
});
and in my html I have:
{{foo beer}}
the result is
<div id="ember127" class="ember-view">beer bar</div>
how can I make my own handlebar helper act like the ember {{unbound beer}} and just produce "beer bar" without any additional markup ?
So I think you might be confused on how the helpers, templates, and Ember views work exactly. The markup you created is expected and is the exact markup you'd get with a working unbound helper.
Ember.Handlebars templates are always placed within an Ember view object (as you have above). Something that a normal bound helper would produce would be:
<div id="ember127" class="ember-view">
<script id="metamorph-1-start" type="text/x-placeholder"></script>
beer bar
<script id="metamorph-1-end" type="text/x-placeholder"></script>
</div>
Now if you want to surround your string with some other tag than a div (lets say an anchor tag or something), then you'd need to create a view, set it's template and tag name, then append that view.
Take a look at this jsFiddle and take a look at the results pane in your inspector for some examples of what I'm talking about. Hope that clears things up for you.
Ember has a helper called unbound that lets you wrap another helper. You can thus turn your bound (automatically) foo helper into an unbound one like so
{{unbound foo beer}}