I want to be able to set the focus to a textarea as a result of a mouse click not in that task area.
As a minimal example, let's say that I'm starting with a text and if you click on it, it gets replaced with a textfield. I can achieve this by a handlebars script:
<script type="text/x-handlebars">
{{#if isActive}}
{{view Ember.TextField}}
{{else}}
<p {{action foo}}> Click Here to Enter text </p>
{{/if}}
</script>
with a controller of
App.ApplicationController = Ember.Controller.extend({
isActive: false,
foo: function(){
this.set("isActive", true);
}
});
This works to create the textfield on the click, but does not give focus to that text area (it takes a second click to be able to actually enter text).
Is there a good way to achieve this end? I could do something hacky by setting an ID in the template and selecting it with jquery, but that seems inelegant.
Furthermore, to reduce the didInsertElement and this.$().focus(); which can seem as though you're mixing jQuery into your Ember modules -- and something I hate doing, you can use the Ember.JS way of specifying additional attributes for the Ember.TextField.
We can specify that we're interested in the HTML5 autofocus attribute:
Ember.TextSupport.reopen({
attributeBindings: ["autofocus"]
});
We can then place the standard Ember.TextField onto our page without having to create another view to extend Ember.TextField:
{{view Ember.TextField autofocus="autofocus"}}
See JSFiddle: http://jsfiddle.net/MdzhN/
Consider extending Ember.TextField as follows:
App.FocusedTextField = Em.TextField.extend({
didInsertElement: function() {
this.$().focus();
}
});
Then change you handlebars template to use it instead:
<script type="text/x-handlebars">
{{#if isActive}}
{{view App.FocusedTextField}}
{{else}}
<p {{action foo}}> Click Here to Enter text </p>
{{/if}}
</script>
Related
I have a JSON structure that I'm passing into a Toolbar to try out dynamic compartmentalization in EmberJS. It looks like this:
{
draggable: true,
buttons: [
{label: "Portrait", action="vertical"},
{label: "Landscape", action="horizontal"}
]
}
I'm using it in a picture viewer that turns a photo vertically and horizontally. Because it's supposed to be a reusable toolbar for other parts of the application, I made it a Component and hooked the click event to the parent controller so it would turn the picture on click. I wanted the button to also get the active class like it does in other examples, but I think that's not working because of the embedded nature of the buttons. How do I get the button that gets clicked to get the active class so I can add css to it?
I tried setting an isActive property in each of the button objects in the model when init gets called and then setting that as true via the action function but I couldn't get observables to work with nested data structures. Do I have to make each button a separate component or can I avoid that?
Thanks for the help.
Templates
<script type="text/x-handlebars" data-template-name="photo-gallery">
<div id="PictureApp"></div>
{{#if toolbar}}
{{ui-toolbar options=toolbar buttonClicked="changeOrientation"}}
{{/if}}
</script>
<script type="text/x-handlebars" data-template-name="components/ui-toolbar">
{{title}}
<div class="overlay">
<div class="toolbar draggable">
{{#if draggable}}
<div class="header draggable-handle"></div>
{{/if}}
<ul>
{{#each buttons}}
<li{{action "clicked" this}}>{{label}}</li>
{{/each}}
</ul>
</div>
</div>
</script>
JS
App.UiToolbarComponent = App.Component.extend({
actions: {
clicked: function(context){
console.log(context);
this.sendAction("buttonClicked", context.action);
}
},
didInsertElement: function(){
if(this.get("draggable")) {
this.$(".draggable").draggable({handle: ".draggable-handle"});
}
}
});
It seems like you're on the right track. I think you could set the active property property on the button, however, you still need to set clear the active flag on any other button.
Inside the clicked action:
clicked: function(context){
console.log(context);
this.buttons.setEach('active', false);
context.set('active', true)
this.sendAction("buttonClicked", context.action);
}
Then on your template you can bind the class:
{{#each buttons}}
<li {{bind-attr class=active}} {{action "clicked" this}}>{{label}}</li>
{{/each}}
So the concept is simple: You come to the app, you have a default template, with a default navigation element. You click a link in that navigation element it renders a new template: #/rails.
From here the default navigation needs to be hidden, and your new nav needs to be rendered.
The way i attempted to approach this, seems a bit silly: what I did was,
SG.Router.map(function(){
this.resource('rails');
});
$(document).ready(function() {
if($('#rails-nav').length !== 0){
$('#main-nav').hide();
}
});
Now the issue with this is that if you go from the default application template, to the rails template via the link - you get two navs unless you refresh that page. My friend stated that I should use something like:
{{outlet nav}} and then render a navigation based on template. The issue is I don't know how to set this up and I have been looking all over the ember site.
Could some one help me out?
If i understood correctly, when you say default template you mean the application template, where all other templates are rendered within its {{outlet}} helper.
There are several approaches to achieve what you want, but a simple one i think would be to use the index template as your default template. In this case evertyhting will be much simpler and work as you require, since you can specify whether the navigation element is shown by placing it inside a template or not.
http://emberjs.jsbin.com/sume/1/edit
hbs
<script type="text/x-handlebars">
<h2> Welcome to Ember.js</h2>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="index">
This is the default template using <i>index</i>
<br/>
<br/>
<span style="background-color:grey">this is the nav part {{#link-to 'rails'}}go to rails{{/link-to}}</span>
</script>
<script type="text/x-handlebars" data-template-name="rails">
this is the rails app
</script>
js
App = Ember.Application.create();
App.Router.map(function() {
this.resource("rails");
});
Also to make this answer a bit more relevant to the title of the question, in order to do something when a template has rendered one way would be to use the didInsertElement callback of the View class.
App.RailsView = Ember.View.extend({
didInsertElement:function(){
if($('#rails-nav').length !== 0){
$('#main-nav').hide();
}
}
});
http://emberjs.jsbin.com/dido/1/edit
I'm trying to get something very basic to work in Meteor, where when the user clicks a button a Session.set() is called and then a div is shown. The problem is that if I don't call the Session.set() the behaviour is as expected where the div is shown upon clicking the button. But once I include the Session.set() i need to click twice before the message is actually show. To make sure the behaviour can be reproduced make sure the page is a clean load and not a Meteor refresh!
The code for the HTML is:
<head>
<title>test</title>
</head>
<body>
{{> home}}
</body>
<template name="home">
<div>
<input type="button" id="addButton" value="add">
</div>
{{> popup}}
</template>
<template name="popup">
{{#with messageHelper}}
<div id="messageDiv" style="display: none">
message is {{message}}
</div>
{{/with}}
</template>
And here is the Javascript that makes it tick.
Template.home.events({
'click #addButton': function(){
// **** if this line is commented out, it will work
Session.set("messageHelper", {message: 'HERE'});
// ****
$('#messageDiv').show();
}
});
Template.popup.helpers({
messageHelper: function(){
return Session.get("messageHelper");
}
});
I think the changed session variable rerenders your template in its original state which sets style="display: none". The problem is discussed here. The solution there is to reorganise your template so the reactivity is not in the template where display is being toggled.
An easier solution might be just to use handlebars #if helper to display your template whenever there is a message:
<template name="popup">
{{#with messageHelper}}
{{#if message}}
<div id="messageDiv">
message is {{message}}
</div>
{{/if}}
{{/with}}
</template>
No need for .show() in the event handler then.
Am new in emberjs and I am trying to copy a practice using solely jquery. I cannot seem to able to do it. Maybe I should approche the following in a different way?
I have a view:
{{#each clip}}
<div class="large-3 columns">
<div {{action panel_clicked uuid}} class="panel" style="overflow:hidden; height:200px;">
{{view Ember.TextField valueBinding="notes" type='hidden'}}
{{view Ember.TextField valueBinding="uuid" type='hidden'}}
{{{chunk}}}
</div>
</div>
{{/each}}
What I want to do is when I click on the class='panel' I get the uuid and use that to get the hidden text fields.
Usually I will just have a custom id for the hidden field such as id='notes_[uuid]' so in jquery I can just do something like $('#notes_' + uuid).val() However I haven't figure out a way to generate a dynamic id in the Ember.TextField.
So is there a way to dynamically generate id in Ember.TextField or I should think bout it differently?
Thanks
You could just pass in the object to the action.
{{#each clip}}
<div {{action panel_clicked this on="click"}} class"panel">
...
</div>
{{/each}}
Where this refers to the current object in the each loop.
Then your action would just take the object as a parameter:
panel_clicked: function(clip) {
alert(clip.get('someAttr')); // just to show it works
... // what you want to do
}
Check out the documentation as well.
Clicking on a view will generate a 'click' event on that view. The event.context will be the model bound to that view.
App.ActionPanelView = Ember.View.extend({
click: function(evt) {
var model = evt.context;
....
}
});
{{#each clip}}
{{view App.ActionPanelView valueBinding=clip}}
{{/each}}
Ember should maintain all the bindings. If you ever find yourself
I can't seem to get a button, generated within an #each template loop, to bind its click action to its associated model. Here's a quick demo of the problem...
The Ember.js app setup:
window.Contacts = Ember.Application.create();
Contacts.Person = Ember.Object.extend({
first: '',
last: '',
save: function() {
// send updated information to server.
}
});
Contacts.contactsList = Ember.ArrayController.create({
content:[],
init: function() {
this.pushObject( Contacts.Person.create({
first:'Tom',
last:'Riddle'
}));
}
});
The template:
<script type="text/x-handlebars">
{{#each Contacts.contactsList}}
<li>
{{view Ember.TextField valueBinding="first" viewName="firstname"}}
{{view Ember.TextField valueBinding="last" viewName="lastname"}}
<button {{action "save" on="click"}}>Save</button>
</li>
{{/each}}
</script>
The problem:
So, the idea in this simple demo scenario is that the "Save" button for each record will trigger an action to save the state of its own model. However, clicking the Save button gives an error:
Uncaught TypeError: Cannot call method 'call' of undefined
My assumption would be that specifying "save" as the button's action would bind it to the save method on its model. However, this does not appear to be the case. Some other object appears to be handling click actions, wherein a "save" hander is undefined. Am I missing something here? How could I make each line item's button call a handler on its own model?
Thanks in advance for any help!
You can define a target of an action by setting the - surprise - target property, see http://jsfiddle.net/pangratz666/FukKX/:
<script type="text/x-handlebars" >
{{#each Contacts.contactsList}}
<li>
{{view Ember.TextField valueBinding="first" viewName="firstname"}}
{{view Ember.TextField valueBinding="last" viewName="lastname"}}
{{#with this as model}}
<button {{action "save" target="model"}}>Save</button>
{{/with}}
</li>
{{/each}}
</script>
The {{#with}} helper around the action is needed because somehow the action helper does not accept this as a target.
But a note to your design: actions should be called on views or on a controller. The target is then responsible for executing further actions like saving, ...
So I would implement your example as follows, see http://jsfiddle.net/pangratz666/U2TKJ/:
Handlebars:
<script type="text/x-handlebars" >
{{#each Contacts.contactsList}}
<li>
{{view Ember.TextField valueBinding="first" viewName="firstname"}}
{{view Ember.TextField valueBinding="last" viewName="lastname"}}
<button {{action "save" target="Contacts.contactsController" }}>Save</button>
</li>
{{/each}}
</script>
JavaScript:
Contacts.contactsController = Ember.Object.create({
save: function(event) {
console.log('do something with: ', event.context);
}
});
There´re two possible ways
{{#each answer in effort_reasons itemController="module_answer"}}
{{/each}}
So each Item gets its own controller where model is the each item (in this case answer), this is especially usefull for something like an Input View where valueBinding would result in binding every input view to the same value. Note this is the only time where controllers in Ember are not singletons, and are having different ID´s, if you want to save your values in the original controller you can get a reference via
this.get('controller.parentController')
inside your itemController.
Or you use the mentioned action approach inside the each loop with
{{action "actionname" parameter paramter2...}}