Trigger an action in a text field from a button - ember.js

I'm looking for advice on how to trigger this view function insertNewLine from a button (see view and template below). I'm guessing there's probably a better way to structure this code. Thanks for your help.
// view
App.SearchView = Ember.TextField.extend({
insertNewline: function() {
var value = this.get('value');
if (value) {
App.productsController.search(value);
}
}
});
// template
<script type="text/x-handlebars">
{{view App.SearchView placeholder="search"}}
<button id="search-button" class="btn primary">Search</button>
</script>

You could use the mixin Ember.TargetActionSupport on your TextField and execute triggerAction() when insertNewline is invoked. See http://jsfiddle.net/pangratz666/zc9AA/
Handlebars:
<script type="text/x-handlebars">
{{view App.SearchView placeholder="search" target="App.searchController" action="search"}}
{{#view Ember.Button target="App.searchController" action="search" }}
Search
{{/view}}
</script>
JavaScript:
App = Ember.Application.create({});
App.searchController = Ember.Object.create({
searchText: '',
search: function(){
console.log('search for %#'.fmt( this.get('searchText') ));
}
});
App.SearchView = Ember.TextField.extend(Ember.TargetActionSupport, {
valueBinding: 'App.searchController.searchText',
insertNewline: function() {
this.triggerAction();
}
});

Related

template not bind a model in Ember

I will try to bind model,controller and template in ember
Here is my js
App = Ember.Application.create({});
App.Person = Ember.Object.extend({
firstName: "r",
lastName: "issa"
});
App.TestingRoute = Ember.Route.extend({
model: function () {
return App.Person.create();
},
setupController: function (controller, model) {
controller.set("model", model);
}
});
App.TestingController = Ember.ObjectController.extend({
submitAction: function () {
alert("My model is :" + this.get("model"));
}
});
my template is :
<script type="text/x-handlebars" data-template-name="application">
{{render testing}}
</script>
<script type="text/x-handlebars" data-template-name="testing">
{{input valueBinding="model.firstName"}}
{{input valueBinding="model.lastName"}}
<button {{action submitAction target="controller"}} class="btn btn-success btn-lg">Pseudo Submit</button>
<p>{{model.firstName}} - {{model.lastName}}</p>
</script>
what s wrong why model not binding in template and alert retunn model is null
Your setupController and model methods from TestingRoute aren't being called. Because your controller is created by the render view helper, not by a transition.
For example using the following works:
template
<script type="text/x-handlebars" data-template-name="testing">
{{input valueBinding="model.firstName"}}
{{input valueBinding="model.lastName"}}
<button {{action submitAction target="controller"}} class="btn btn-success btn-lg">Pseudo Submit</button>
<p>{{model.firstName}} - {{model.lastName}}</p>
</script>
javascript
App = Ember.Application.create({});
App.Router.map(function() {
this.route('testing', { path: '/' })
});
App.Person = Ember.Object.extend({
firstName: "r",
lastName: "issa"
});
App.TestingRoute = Ember.Route.extend({
model: function () {
return App.Person.create();
},
setupController: function (controller, model) {
debugger
controller.set("model", model);
}
});
App.TestingController = Ember.ObjectController.extend({
actions: {
submitAction: function () {
alert("My model is :" + this.get("model"));
}
}
});
Here is the fiddle http://jsfiddle.net/marciojunior/8DaE9/
Also, the use of actions in controllers is deprecated in favor of using the actions: { ... } object

How to use CollectionView inside View to not use the defaultContainer in Ember JS

I want to insert CollectionView into View. It works but displays:
DEPRECATION: Using the defaultContainer is no longer supported. [defaultContainer#lookup]
How correctly insert CollectionView in View?
App = Ember.Application.create();
App.Router.map(function() {
this.route("index", { path: "/" });
});
App.FirstView = Em.View.extend({
templateName: 'first'
});
App.SecondView = Em.View.extend({
templateName: 'second'
});
App.MyCollection = Em.CollectionView.extend({
content: ['f','s'],
createChildView: function(viewClass, attrs){
if (attrs.content == 'f') {
viewClass = App.FirstView ;
};
if (attrs.content == 's') {
viewClass = App.SecondView ;
};
return this._super(viewClass, attrs);
}
});
App.IndexView = Em.View.extend({
myChildView: App.MyCollection.create()
});
templates:
<script type="text/x-handlebars">
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="index">
{{view view.myChildView}}
</script>
<script type="text/x-handlebars" data-template-name="first">
search
</script>
<script type="text/x-handlebars" data-template-name="second">
client
</script>
Sorry for my english, i am from Russia and understand it a little))
Your IndexView is directly instantiating the view. This style of instantiation is deprecated with nested views, so as to allow child views to get their parent Container.
Change that to declare the myChildView directly, and the deprecation warning will go away.
App.IndexView = Em.View.extend({
myChildView: App.MyCollection
});

Ember.js: Upload file component

I need to create an Ember component to select a file.
My page will include multiple "upload component"
I have read a post trying to implement that: (https://stackoverflow.com/questions/9200000/file-upload-with-ember-data) BUT the UploadFileView is directly linked to the controller.
I would like to have something more generic...
I would like to remove the App.StoreCardController.set('logoFile'..) dependency from the view or pass the field (logoFile) from the template...
Any idea to improve this code ?
App.UploadFileView = Ember.TextField.extend({
type: 'file',
attributeBindings: ['name'],
change: function(evt) {
var self = this;
var input = evt.target;
if (input.files && input.files[0]) {
App.StoreCardController.set('logoFile', input.files[0]);
}
}
});
and the template:
{{view App.UploadFileView name="icon_image"}}
{{view App.UploadFileView name="logo_image"}}
I completed a full blown example to show this in action
https://github.com/toranb/ember-file-upload
Here is the basic handlebars template
<script type="text/x-handlebars" data-template-name="person">
{{view PersonApp.UploadFileView name="logo" contentBinding="content"}}
{{view PersonApp.UploadFileView name="other" contentBinding="content"}}
<a {{action submitFileUpload content target="parentView"}}>Save</a>
</script>
Here is the custom file view object
PersonApp.UploadFileView = Ember.TextField.extend({
type: 'file',
attributeBindings: ['name'],
change: function(evt) {
var self = this;
var input = evt.target;
if (input.files && input.files[0]) {
var reader = new FileReader();
var that = this;
reader.onload = function(e) {
var fileToUpload = reader.result;
self.get('controller').set(self.get('name'), fileToUpload);
}
reader.readAsDataURL(input.files[0]);
}
}
});
Here is the controller
PersonApp.PersonController = Ember.ObjectController.extend({
content: null,
logo: null,
other: null
});
And finally here is the view w/ submit event
PersonApp.PersonView = Ember.View.extend({
templateName: 'person',
submitFileUpload: function(event) {
event.preventDefault();
var person = PersonApp.Person.createRecord({ username: 'heyo', attachment: this.get('controller').get('logo'), other: this.get('controller').get('other') });
this.get('controller.target').get('store').commit();
}
});
This will drop 2 files on the file system if you spin up the django app
EDIT (2015.06): Just created a new solution based on a component.
This solution provides an upload button with a preview and remove icon.
P.S. The fa classes are Font Awesome
Component handlebars
<script type="text/x-handlebars" data-template-name='components/avatar-picker'>
{{#if content}}
<img src={{content}}/> <a {{action 'remove'}}><i class="fa fa-close"></i></a>
{{else}}
<i class="fa fa-picture-o"></i>
{{/if}}
{{input-image fdata=content}}
</script>
Component JavaScript
App.AvatarPickerComponent = Ember.Component.extend({
actions: {
remove: function() {
this.set("content", null);
}
}
});
App.InputImageComponent = Ember.TextField.extend({
type: 'file',
change: function (evt) {
var input = evt.target;
if (input.files && input.files[0]) {
var that = this;
var reader = new FileReader();
reader.onload = function (e) {
var data = e.target.result;
that.set('fdata', data);
};
reader.readAsDataURL(input.files[0]);
}
}
});
Usage example
{{avatar-picker content=model.avatar}}
Old Answer
I took Chris Meyers example, and I made it small.
Template
{{#view Ember.View contentBinding="foto"}}
{{view App.FotoUp}}
{{view App.FotoPreview width="200" srcBinding="foto"}}
{{/view}}
JavaScript
App.FotoPreview= Ember.View.extend({
attributeBindings: ['src'],
tagName: 'img',
});
App.FotoUp= Ember.TextField.extend({
type: 'file',
change: function(evt) {
var input = evt.target;
if (input.files && input.files[0]) {
var that = this;
var reader = new FileReader();
reader.onload = function(e) {
var data = e.target.result;
that.set('parentView.content', data);
}
reader.readAsDataURL(input.files[0]);
}
},
});
Marek Fajkus you cannot use JQuery's .serialize, it makes no mention of file uploads in the documentation at JQuery UI docs
However, you could use JQuery Upload Plugin
Actually it does mention it, it says:
". Data from file select elements is not serialized."
In case of uploading multiple files, you may want to use
{{input type='file' multiple='true' valueBinding='file'}}
^^^^
This is a solution that you would use in normal HTML upload.
Additionally, you can use 'valueBinding' which will allow you to set up an observer against that value in your component.

Ember Handlebars helper view not updated

I'm trying to use Handlebars helper, but the helper view does not get updated.
The view,
<script type="text/x-handlebars">
{{#view App.NumberView}}
<button {{action changeNumber}}>Change number</button><br>
{{formatNumber view.number}} <br>
{{view.number}}
{{/view}}
</script>​
The code,
App = Ember.Application.create({});
App.NumberView = Ember.View.extend({
number: 5,
changeNumber: function(e) {
this.set('number', this.get('number') + 1);
}
});
Em.Handlebars.registerHelper('formatNumber', function(timePath, options) {
var number = Em.Handlebars.getPath(this, timePath, options);
return new Handlebars.SafeString("Formated number: " + number);
});
​
The live example in jsfiddle http://jsfiddle.net/LP7Hz/1/
So what's wrong ?
Because Handlebars helpers in Ember which aren't bound helpers. So you can instantiate an auxiliary view to do that like this fiddle:
http://jsfiddle.net/secretlm/qfNJw/2/
HTML:
<script type="text/x-handlebars">
{{#view App.NumberView}}
<button {{action changeNumber}}>Change number</button><br>
{{formatNumber view.number}} <br>
{{view.number}}
{{/view}}
</script>​
Javascript:
App = Ember.Application.create({});
App.NumberView = Ember.View.extend({
number: 5,
changeNumber: function(e) {
this.set('number', this.get('number') + 1);
}
});
App.registerViewHelper = function(name, view) {
Ember.Handlebars.registerHelper(name, function(property, options) {
options.hash.contentBinding = property;
return Ember.Handlebars.helpers.view.call(this, view, options);
});
};
inlineFormatter = function(fn) {
return Ember.View.extend({
tagName: 'span',
template: Ember.Handlebars.compile('{{view.formattedContent}}'),
formattedContent: (function() {
if (this.get('content') != null) {
return fn(this.get('content'));
}
}).property('content')
});
};
App.registerViewHelper('formatNumber', inlineFormatter(function(content) {
return new Handlebars.SafeString("Formated number: " + content);
}));
This link is useful: http://techblog.fundinggates.com/blog/2012/08/ember-handlebars-helpers-bound-and-unbound/ from #Jo Liss
​
You're looking for a bound helper, which doesn't exist just yet. There is a Pull Request and associated discussion.

Ember.js view for object

I have simple view in my Ember.js application, like this. Each "content" element consists of two objects, first and second:
{{#each App.myController.content}}
{{view for content.first}}
{{view for content.second}}
{{/each}}
I'd like to define view for each content separately (so as not to have to write it twice), in another handlebars template script. How can I pass the first and second variables to the view?
Here is a code sample, see http://jsfiddle.net/Zm4Xg/5/:
Handlebars:
<script type="text/x-handlebars" data-template-name="contact-view">
<div>{{name}}</div>
<img {{bindAttr src="avatar"}} {{bindAttr alt="name"}}>
</script>
<script type="text/x-handlebars">
{{#each App.contactsController.pair}}
<div class="menu_vertical_group">
{{#with this.first}}
{{view App.contactView}}
{{/with}}
{{#with this.second}}
{{view App.contactView}}
{{/with}}
</div>
{{/each}}
</script>
​JavaScript:
App = Ember.Application.create();
App.Contact = Em.Object.extend({
name: null,
avatar: null
});
App.contactView = Ember.View.extend({
templateName: 'contact-view'
});
App.contactsController = Em.ArrayController.create({
content: [],
initData: function(data) {
var contacts = data.map(function(contact) {
return App.Contact.create({
"name": contact.name,
"avatar": contact.avatar
});
});
this.pushObjects(contacts);
},
pair: (function() {
content = this.get('content');
var result = [];
for (ii = 0; ii < content.length; ii += 2) {
result.pushObject({
"first": content[ii],
"second": content[ii + 1] ? content[ii + 1] : null
});
}
return result;
}).property('content')
});
App.contactsController.initData([{
"name": "John Doe",
"avatar": "/john.jpg"},
{
"name": "Someone Else",
"avatar": "/else.jpg"}]);​
Something like this?
{{#each App.myController.content}}
{{view MyView contentBinding="content.first"}}
{{view MyView contentBinding="content.second"}}
{{/each}}
You can extend the View class with a templateName function that evaluates to a different view based on a property of the model, like this:
App.customView = Ember.View.extend({
templateName:function(){
if(this.get('content').get('index') === 1){
return 'view1';
}
else{
return 'view2';
}
}.property('content.index') // custom template function based on 'index' property
});
Check out this fiddle: http://jsfiddle.net/lifeinafolder/7hnc9/