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
Related
I am developing a Cordova application with help from Ember. I have many dynamic elements in my application. These are Bootstrap thumbnails that link to other routes when clicked.
I want to make these thumbnails clickable. If I use Views, I will have to write unique views for all the thumbnails.
I have heard about mixins. Can a general View be defined that will :
Pass a model
Render a template for a route with the model
In other words, since each view semantically performs the same action, I want to be able to do something similar to
{{#each}}
{{#view App.AllView this}}
.
{{/view}}
{{/each}}
in the template and in the view :
App.AllView = Ember.View.extend({
click: function(evt, model){
this.controllerFor('route').set('content', model);
this.transitionTo('route');
}
});
UPDATE
Following #givanse's answer, I made the following component
<script type="text/x-handlebars" data-template-name="components/thumbnail-view">
<div {{bind-attr class=class}}>
<div class="thumbnail">
<div class="caption">
{{name}}
</div>
<img {{bind-attr src=image }}>
</div>
</div>
</script>
and used it in my template :
<script type="text/x-handlebars" data-template-name="types">
<div class="row">
{{#each model}}
{{thumbnail-view action="goToCategory" class="col-xs-12" param=this name=name image=image}}
{{/each}}
</div>
</script>
with an Ember component :
Pioneer.ThumbnailViewComponent = Ember.Component.extend({
click: function(){
this.sendAction('action', this.get('param'));
}
});
The action goToCategory is defined in my ApplicationRoute
Hope this helps someone!
What you need is Components, something like:
<script data-template-name="index">
{{#each}}
{{img-thumbnail imgId="id/path/name"}}
{{/each}}
</script>
<script data-template-name="components/img-thumbnail">
{{! whatever you need to make your thumbnail }}
</script>
App.ImgThumbnailComponent = Ember.Component.extend({
// handle events, classes, etc.
});
See:
http://emberjs.com/guides/components/
http://emberjs.com/api/classes/Ember.Component.html
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}}
I have a container view which, among other things, displays a list of objects, like so:
{{#each}}
<div {{bind-attr class="author.first_name task"}}></div>
{{/each}}
I would like to hook a Javascript function everytime a DOM element is added to this list. I've tried doing:
didInsertElement: function() { ... }
But this hook apparently runs only the first time the view is initialized. I figured that maybe the hook doesn't run because the view is actually inserted once, and what's inserted more than once are just the nested element.
So should I use a nested view?
I tried something along these lines:
{{#each}}
{{#view App.SingleItemView}}
<div {{bind-attr class="author.first_name task"}}></div>
{{/view}}
{{/each}}
But in this case, though it works somehow, it doesn't get passed the necessary data that would render the properties such as author.first_name.
render will give you a new scope and is really easy to assign the content as well
<ul>
{{#each item in controller}}
{{render 'ind' item}}
{{/each}}
</ul>
http://emberjs.jsbin.com/alAKubo/1/edit
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>
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...}}