How to use autofocus with ember.js templates? - ember.js

I have a simple ember.js text field and I'm trying to add autofocus
{{view PersonApp.SearchField placeholder="search..." valueBinding="searchText"}}
PersonApp.SearchField = Ember.TextField.extend({
});
Can I add this in the javascript or is at as simple as a attribute in the template itself?

Update:
More recent versions of Ember now have support for this built in, so you no longer need to reopen TextField to add an attributeBinding. As of January 2014 (commit fdfe8495), you can simply use the HTML5 autofocus attribute in your template:
{{input value=search type="text" placeholder="Search" autofocus="autofocus"}}
Here is a simple jsfiddle demonstration.
Previous Solution:
You can also reopen TextField to allow you to bind the autofocus attribute:
Ember.TextField.reopen({
attributeBindings: ['autofocus']
});
And then in your template:
{{input value=search type="text" placeholder="Search" autofocus="autofocus"}}

There is also the option to use the HTML5 autofocus attribute on the TextField.
PersonApp.SearchField = Ember.TextField.extend({
attributeBindings: ['autofocus'],
autofocus: 'autofocus'
});
See also documentation on Mozilla Developer Network for further information about the autofocus field:

Autofocus meaning that we start focusing on the text box right away? You want didInsertElement for that.
didInsertElement: function() {
this.$().focus();
}
http://jsfiddle.net/qKXJt/139/

I wrapped this method in a little 1kb package to solve this even a bit more elegantly, directly in the template, without any further coding:
<body>
<!-- all the libraries -->
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.3.0/handlebars.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/ember.js/1.2.0/ember.min.js"></script>
<script src="http://rawgithub.com/AndreasPizsa/ember-autofocus/master/dist/ember-autofocus.min.js"></script>
<!-- your template -->
<script type="text/x-handlebars">
Hello, world! {{ input }}
:
: more elements here
:
{{ autofocus }}
</script>
<!-- your app -->
<script>
Ember.Application.create();
</script>
</body>
The package is at https://github.com/AndreasPizsa/ember-autofocus
(or on bower install ember-autofocus). Enjoy!

Related

Ember.js: conditional input attribute

In Ember's input helper, how can I show/hide attributes based on a condition? For example, let's say I want to show required="required" if isEditable is true and disabled="disabled" otherwise. Currently I have something like this:
{{#if isEditable}}
{{input value=model.name required="required"}}
{{else}}
{{input value=model.name disabled="disabled"}}
{{/if}}
...but it would be nice if I bind the attributes somehow instead.
{{ input type='text' required=required disabled=disabled }} works just fine
Working example here
There are a whole bunch of attributes that you can bind directly and required and disabled are among the pack. See here
Note #blackmind is correct that if you were to do this from scratch, you would need to do some work. Fortunately though, TextSupport already does the work for you... :) See here
From the EmberJS site
By default, view helpers do not accept data attributes. For example
{{#link-to "photos" data-toggle="dropdown"}}Photos{{/link-to}}
{{input type="text" data-toggle="tooltip" data-placement="bottom" title="Name"}}
renders the following HTML:
<a id="ember239" class="ember-view" href="#/photos">Photos</a>
<input id="ember257" class="ember-view ember-text-field" type="text" title="Name">
There are two ways to enable support for data attributes. One way would be to add an attribute binding on the view, e.g. Ember.LinkView or Ember.TextField for the specific attribute:
Ember.LinkView.reopen({
attributeBindings: ['data-toggle']
});
Ember.TextField.reopen({
attributeBindings: ['data-toggle', 'data-placement']
});
Now the same handlebars code above renders the following HTML:
<a id="ember240" class="ember-view" href="#/photos" data-toggle="dropdown">Photos</a>
<input id="ember259" class="ember-view ember-text-field"
type="text" data-toggle="tooltip" data-placement="bottom" title="Name">
Or you can reopen the view
Ember.View.reopen({
init: function() {
this._super();
var self = this;
// bind attributes beginning with 'data-'
Em.keys(this).forEach(function(key) {
if (key.substr(0, 5) === 'data-') {
self.get('attributeBindings').pushObject(key);
}
});
}
});
I typically do the following
<input type="checkbox" {{bind-attr disabled=isAdministrator}}>

Set Handlebar class on the fly

I'd like to update the class of a div according to the user input. A simple input text that need to be validated.
I have to go with a helper but I can't figure it out.
<div class="{{validationClass}}">
<p>{{input type="text" id="titleInput" value=title placeholder="Title"}}</p>
</div>
When there's nothing written in the text field I'd like to surround the box with the red colour, after the used typed a single character I want it to go default.
So, according to bootstrap 2.x I'd need to set the div class to control-group error or control-group success etc.
I've never created a helper so I'm struggling, I don't know how to call it and how to return the desired string to be replaced in {{validationClass}}
Thanks.
You can use the bind-attr helper .
This is a sample:
<script type="text/x-handlebars" data-template-name="index">
<div {{bind-attr class=":control-group validationClass"}}>
<p>{{input type="text" id="titleInput" value=title placeholder="Title"}}</p>
</div>
</script>
App.IndexController = Ember.ObjectController.extend({
title: null,
validationClass: function() {
var title = this.get('title');
return title ? 'success' : 'error';
}.property('title')
});
http://jsfiddle.net/marciojunior/6Kgty/
Use {{bind-attr}} helper
{{!hbs}}
<div {{bind-attr class=":control-group isError:error"}}>
{{input type="text" class="form-control" value=testVal}}
</div>
//Controller
App.ApplicationController = Em.Controller.extend({
testVal: '',
isError: Em.computed.empty('testVal')
});
Sameple Demo

EmberJS multiple yield helper

I have a custom view that I've created in Ember. I really love the {{yield}} helper to allow me to control the 'bread' of the sandwich. However, what I'd like to do now, is create a 'double decker' sandwich, and have a view with more than 1 yield in it, or at the very least be able to parameterize which template to use in the 2nd yield.
so for example:
layout.hbs
<div>
<div class="header">Header Content</div>
<div class="tab1">
Tab 1 Controls.
<input type="text" id="common1" />
{{yield}}
</div>
<div class="tab2">
Tab 2 Controls.
<input type="text" id="common2" />
{{yield second-template}} or {{template second-template}}
</div>
</div>
app.js
App.MyDoubleDeckerView = Ember.View.extend({
layoutName:"layout',
templateName:"defaultTemplate",
"second-template":"defaultSecond"
});
App.MyExtendedDoubleDecker = App.MyDoubleDeckerView({
templateName:"myTemplate",
"second-template":"mySecondTemplate"
});
is there any way of doing something like this? What I love about the views in ember is the ability to centralize & extend views which allows me to keep the things that are common among all the views in one place...
As of Ember 3.25 you can use so called "named blocks" (see the Passing multiple blocks subsection of https://api.emberjs.com/ember/release/modules/#glimmer%2Fcomponent).
Example component:
<h1>{{yield to="title"}}</h1>
{{yield}}
and then use it like this:
<PersonProfile #person={{this.currentUser}}>
<:title>{{this.currentUser.name}}</:title>
<:default>{{this.currentUser.siganture}}</:default>
</PersonProfile>
I think you should use named outlets for this
http://emberjs.com/guides/routing/rendering-a-template/
Something like this should work:
layout.hbs
<div>
<div class="header">Header Content</div>
<div class="tab1">
Tab 1 Controls.
<input type="text" id="common1" />
{{yield}}
</div>
<div class="tab2">
Tab 2 Controls.
<input type="text" id="common2" />
{{view "view.secondView"}}
</div>
</div>
app.js
App.MyDoubleDeckerView = Ember.View.extend({
layoutName:"layout',
templateName:"defaultTemplate",
secondView: Ember.view.extend({
templateName: "defaultSecond"
})
});
App.MyExtendedDoubleDecker = App.MyDoubleDeckerView({
templateName:"myTemplate",
secondView: Ember.view.extend({
templateName: "mySecondTemplate"
});
});
In other words, invoke a view given by view.secondView from within your template. Then, set the secondView property in your class or subclass.
You could add a bit of syntactic sugar with
App.viewForTemplateName = function(templateName) {
return Ember.View.extend({
templateName: templateName
});
};
Then, in your view definitions above, do
secondView: App.viewForTemplateName('mySecondTemplate')

Nesting existing textfield view in a new view

I have been getting a bit stuck in finding a way to reuse an ember textfield so any help would be appreciated.
What I have is (simplified here) a selection of rows like:
<div class="detailItem">Email: {{view Ember.TextField valueBinding="email"}} </div>
<div class="detailItem">Name: {{view Ember.TextField valueBinding="name"}} </div>
and instead of always wrapping in a div I'd like to make use of a new view. e.g.:
<script type="text/x-handlebars" data-template-name="detailItem">
<div class="detailItem">{{Item name}}: {{view Ember.TextField valueBinding="itemValue"}} </div>
</script>
App.DetailItemView = Em.View.extend({
templateName: 'detailItem',
name: "",
......
});
The thing I am not sure is how I get the textfield's valueBinding to link up to my controller (well actually it's content). I can obviously add another property to DetailItemView and instantiate it with that property having the values 'email' and 'name'. How though would I then pass these into the contained Ember.TextField?
Thanks for any assistance
You can do the following:
App.DetailItemView = Ember.View.extend({
templateName: 'detail_item',
classNames: ['detailItem'],
label: null,
value: ''
});
and the template:
<script type="text/template" id="detail_item">
{{view.label}}:
{{view Ember.TextField valueBinding="view.value"}}
</script>
And then use it like this:
{{view App.DetailItemView label="Email" valueBinding="email"}}
{{view App.DetailItemView label="Name" valueBinding="name"}}

Ember.js - CollectionView, add an attribute to the div wrapper of the child view

I'm trying to combine two ebmer.js examples: Integrating with jQuery UI and the todos example from emberjs.com. I want to have a todo list that is sortable.
Everything went smooth until I got to a point where I wanted to serialize the sortable. For that to work, I need to be able to add an attribute to the sortable items.
this is the template:
{{#collection Todos.TodosListView}}
{{#view Todos.TodoView contentBinding="content" checkedBinding="content.isDone"}}
<label>{{content.title}}</label>
{{/view}}
{{/collection}}
Todos.TodosListView is a CollectionView, similar to the menu in the jQuery UI example. Todos.TodoView is a Checkbox.
This generates the following html:
<div class="ember-view todo-list ui-sortable" id="ember267">
<div class="ember-view" id="ember284">
<input type="checkbox" class="ember-view ember-checkbox todo" id="ember297">
<label>
<script type="text/x-placeholder" id="metamorph-1-start"></script>
something to do
<script type="text/x-placeholder" id="metamorph-1-end"></script>
</label>
</div>
</div>
What I need to be able to do is edit the <div> that wraps the <input>. Assuming the todo's id is 1, I want to add serial=todos_1. I tried to add didInsertElement to TodoView and add an attribute to the parent view, but I didn't have access to the content of the view (the todo itself).
Is this possible?
Thanks for your help.
EDIT:
I found a workaround - adding the ID to the DOM as a hidden element.
The updated template:
{{#collection Todos.TodosListView}}
{{#view Todos.TodoView contentBinding="content" checkedBinding="content.isDone" serial="content.serial"}}
<label>{{content.title}}</label>
<span style="display: none;" class="todo-id">{{content.id}}</span>
{{/view}}
{{/collection}}
Todos.TodoView.didInsertElement:
didInsertElement: function() {
var $div = this.get('parentView').$();
var id = $div.children('.todo-id').text();
$div.attr('serial', 'todos_' + id);
}
Generated html:
<div class="ember-view todo-list ui-sortable" id="ember267">
<div class="ember-view" id="ember284" serial="todos_100">
<input type="checkbox" class="ember-view ember-checkbox todo" id="ember297">
<label>
<script type="text/x-placeholder" id="metamorph-1-start"></script>
something to do
<script type="text/x-placeholder" id="metamorph-1-end"></script>
</label>
<span class="todo-id" style="display: none;">
<script type="text/x-placeholder" id="metamorph-2-start"></script>
100
<script type="text/x-placeholder" id="metamorph-2-end"></script>
</span>
</div>
</div>
I would still like to know if there's a more elegant way of achieving this.
You can create a computed property serial and add this property to the attributeBindings (documented here) of your itemViewClass of Todos.TodosListView, see http://jsfiddle.net/pangratz666/6X4QU/:
Todos.TodosListView = Ember.CollectionView.extend({
itemViewClass: Ember.View.extend({
attributeBindings: ['serial'],
serial: function() {
return 'todos_' + Ember.getPath(this, 'content.id');
}.property('content.id').cacheable()
})
});