date entries in emberjs templates - ember.js

When I set {{input value=sDate type='date'}} in a handlebar template in emberjs, I get the html5 datepicker when using Chrome. Unfortunately, html5 datepicker is not supported in Firefox. How do I switch over to the jqueryUI datepicker instead?

The best way would be to create your own component and to call element.datepicker(); in your component's didInsertElement hook.

Here is an [Ember.Component][1] implementation of Bootstrap DatePicker:
Note: You should be able to adapt the setupDatePicker function easily to use jqueryUI datepicker.
date_picker_component.js
Chipmunk.DatePickerComponent = Ember.Component.extend({
setupDatePicker: {
var self = this;
return this.$('.datepicker').datepicker({
separator: "-",
autoclose: true
}).on("changeDate", function(event) {
return self.set("value", self.format(event.date));
});
}.on('didInsertElement'),
formattedValue: {
var value = this.get('value');
if (value) {
return this.format(value);
}
}.property('value'),
format: function(value) {
return moment.utc(value).format("YYYY-MM-DD");
}
});
date-picker.handlebars
<div class="date datepicker" data-date-format="yyyy-mm-dd">
<input class="form-control" size="16" type="text" readonly {{bindAttr value="formattedValue" rel="rel"}}>
<span class="add-on"><i class="icon-th"></i></span>
</div>
Usage:
{{date-picker value=sDate}}

Related

EmberJS : How to dynamically reload model and template (after an action, ex 'button pressed')

EmberJS version 1.11.3
I have a button that when pressed, sends an Ajax query to my server and returns some data. I would like to refresh the view under this button with the new data each time.
Here's the simplified handlebar template :
<script type="text/x-handlebars" data-template-name='query'>
<form class="form-vertical" {{action "sendQuery" model}}>
<div class="control-group">
{{input value=this.totoQuery type="text" placeholder="Enter an SQL query...."}}
</div>
<button type="submit" class="btn">Send ! </button>
</form>
</script>
Here's the controller for that template:
App.QueryController = Ember.Controller.extend({
totoQuery: '',
actions: {
sendQuery: function(model, route) {
var promise = asyncAjax(queryservice + '?query=' + this.totoQuery);
promise.success(function(data) {
model=data.entries;
})
}
}
})
The Ajax call works fine and the model defined in the route too ( i tested with a dummy model ). However when i try to update the model with :
model=data.entries; //The template does not update with it!!! The template still displays the data from the dummy model.
I can't modify it with this.set('model',data) because "Undefined function!! this.set"..
My dummy model :
App.QueryRoute = Ember.Route.extend({
model: function() {
return [{
'title': 'A book title like Harry Potter of Fifty Sha... nvm.. '
}];
}
});
Any advice is greatly appreciated!!!
PS: I've been spending way too much time on this :(
You can get the model inside controller action in the following way:
sendQuery: function() {
var self = this,
totoQuery = this.get('totoQuery');
var promise = asyncAjax(queryservice + '?query=' + totoQuery);
promise.done(function(data) {
$.each(data.entries, function (index, entry){
self.get('model').pushObject(entry);
});
})
}
And you do not need to pass model as parameter in action. You can do something like this:
<form class="form-vertical" {{action "sendQuery"}}>
The controller automatically inherit the model property. And one thing is, getting model property using this.totoQuery will be deprecated in Ember. Instead use model.totoQuery.
If you are struggling too much, you can also render something from your controller instead of the model directly from the route, that way you can update the variable from controller and would change easily.
App.QueryController = Ember.Controller.extend({
queryResponse: [],
totoQuery: '',
actions: {
sendQuery: function(model, route) {
var self = this;
var promise = asyncAjax(queryservice + '?query=' + this.totoQuery);
promise.success(function(data) {
//model=data.entries;
self.set('queryResponse', data.entries);
})
}
})
And in your template you can render it directly
<ul>
{{#each item in controller.queryResponse}}
<li>item.name</li>
{{/each}}
</ul>

ember autofocus component after insertion into DOM

I want to display an input field, and immediately autofocus it upon clicking a button. Im still new to Ember so i am not sure this is the correct approach, but I tried to wrap as an ember component
template
{{#if showCalendarForm}}
{{new-calendar focus-out='hideNewCalendar' insert-newline='createCalendar'}}
{{else}}
<button class="btn btn-sm btn-primary" {{action "showNewCalendar"}}>New</button>
{{/if}}
new-calendar component handlebars:
<div class="input-group">
{{input
class = 'form-control'
id = 'newCalendar'
type = 'text'
placeholder = 'New calendar'
value = calendarName
action = 'createCalendar'
}}
</div>
new-calendar component js
import Ember from 'ember';
export default Ember.Component.extend({
didInsertElement: function() {
this.$().focus();
}
});
When I click the button, the text field is displayed, but autofocus and hitting enter doesnt work
The way the jQuery is written, you are trying to set focus on the <div class="input-group">, try this instead:
didInsertElement: function() {
this.$('input').focus();
}
Another way to do this would be to extend the Ember.TextField:
export default Ember.TextField.extend({
becomeFocused: function() {
this.$().focus();
}.on('didInsertElement')
});
Then, in your new-calendar template, use this component:
{{focus-input
class = 'form-control'
id = 'newCalendar'
type = 'text'
placeholder = 'New calendar'
value = calendarName
action = 'createCalendar'
}}
This way you can reuse the focus-input component wherever you need to.
As for hitting enter to create the calendar, I think you want to listen for the keyPress event, check to see if it's the enter key, and then send the action rather than trying to use insert-newline='createCalendar'.
//in FocusInputComponent
keyPress: function(e) {
// Return key.
if (e.keyCode === 13) {
this.sendAction();
}
}
Try wrapping your focus call in an Ember.run and schedule it to be run in the after render queue like this:
didInsertElement: function()
{
Ember.run.scheduleOnce('afterRender', this, function() {
this.$().focus();
});
}
this blog post has helped me a lot in understanding ember's lifecycle hooks:
http://madhatted.com/2013/6/8/lifecycle-hooks-in-ember-js-views

when bootstrap date picker date select some action call in ember js controller

I am new to ember, developing Filtering by date functionality using ember js.
handle bars:
<div class="input-group date" data-behavior="ActiveRock.filterDatePicker" data-date-before-field="#filter_end_date">
<input type="text" class="form-control" id="filter_start_date" {{action filterPortfolios}}/>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
Behaviour:
$ ->
ActiveRock.datePicker = (el) ->
el.datepicker(
format: 'yyyy/mm/dd'
autoclose: true
).on('show', (e) ->
$('.datepicker').css('z-index', '1151')
true
).on('hide', (e) ->
logic
return false
true
)
controller action: filterPortfolios
included bootstrap datepicker
but it is not working, please suggest any solution.
Thanks,
Prasad.
In behavior I written like taht
$(function() {
return ExamplePicker.filterDatePicker = function(el) {
return el.datepicker({
format: 'yyyy/mm/dd',
autoclose: true
}).on('changeDate', function(e) {
var controller;
controller = App.__container__.lookup("controller:<controller_name>");
controller.send("<action_name>");
return true;
});
};
});

Ember: how to set classNameBindings on parent element of view

See http://jsfiddle.net/4ZyBM/6/
I want to use Bootstrap for my UI elements and I am now trying to convert certain elements to Ember views. I have the following problem:
I embed an input element in a DIV with a given class (control-group). If a validation error occurs on the field, then I want to add an extra class "error" to the DIV.
I can create a view based on the Ember.TextField and specify that if the error occurs the ClassNameBinding should be "error", but the problem is that class is the set to the input element and not to the DIV.
You can test this by entering a non alpha numeric character in the field. I would like to see the DIV border in red and not the input field border.
HTML:
<script type="text/x-handlebars">
<div class="control-group">
{{view App.AlphaNumField valueBinding="value" type="text" classNames="inputField"}}
</div>
</script>
JS:
App.AlphaNumField = Ember.TextField.extend({
isValid: function () {
return /^[a-z0-9]+$/i.test(this.get('value'));
}.property('value'),
classNameBindings: 'isValid::error'
})
Can I set the classNameBindings on the parent element or the element closest to the input ? In jQUery I would use:
$(element).closest('.control-group').addClass('error');
The thing here is that without using jQuery you cannot access easily the wrapping div around you Ember.TextField's. Also worth mentioning is that there might be also a hundred ways of doing this, but the simplest solution I can think of would be to create a simple Ember.View as a wrapper and check the underlying child views for validity.
Template
{{#view App.ControlGroupView}}
{{view App.AlphaNumField
valueBinding="value"
type="text"
classNames="inputField"
placeholder="Alpha num value"}}
{{/view}}
Javascript
App.ControlGroupView = Ember.View.extend({
classNameBindings: 'isValid:control-group:control-group-error',
isValid: function () {
var validFields = this.get('childViews').filterProperty('isValid', true);
var valid = validFields.get('length');
var total = this.get('childViews').get('length')
return (valid === total);
}.property('childViews.#each.isValid')
});
App.AlphaNumField = Ember.TextField.extend({
isValid: function () {
return /^[a-z0-9]+$/i.test(this.get('value'));
}.property('value')
});
CSS
.control-group-error {
border:1px solid red;
padding:5px;
}
.control-group {
border:1px solid green;
padding:5px;
}
Working demo.
Regarding bootstrap-ember integration and for the sake of DRY your could also checkout this ember-addon: https://github.com/emberjs-addons/ember-bootstrap
Hope it helps.
I think that this is the more flexible way to do this:
Javascript
Boostrap = Ember.Namespace.create();
To simplify the things each FormControl have the properties: label, message and an intern control. So you can extend it and specify what control you want. Like combobox, radio button etc.
Boostrap.FormControl = Ember.View.extend({
classNames: ['form-group'],
classNameBindings: ['hasError'],
template: Ember.Handlebars.compile('\
<label class="col-lg-2 control-label">{{view.label}}</label>\
<div class="col-lg-10">\
{{view view.control}}\
<span class="help-block">{{view.message}}</span>\
</div>'),
control: Ember.required()
});
The Boostrap.TextField is one of the implementations, and your component is a Ember.TextField. Because that Boostrap.TextField is an instance of Ember.View and not an Ember.TextField directly. We delegate the value using Ember.computed.alias, so you can use valueBinding in the templates.
Boostrap.TextField = Boostrap.FormControl.extend({
control: Ember.TextField.extend({
classNames: ['form-control'],
value: Ember.computed.alias('parentView.value')
})
});
Nothing special here, just create the defaults values tagName=form and classNames=form-horizontal, for not remember every time.
Boostrap.Form = Ember.View.extend({
tagName: 'form',
classNames: ['form-horizontal']
});
Create a subclass of Boostrap.Form and delegate the validation to controller, since it have to be the knowledge about validation.
App.LoginFormView = Boostrap.Form.extend({
submit: function() {
debugger;
if (this.get('controller').validate()) {
alert('ok');
}
return false;
}
});
Here is where the validation logic and handling is performed. All using bindings without the need of touch the dom.
App.IndexController = Ember.ObjectController.extend({
value: null,
message: null,
hasError: Ember.computed.bool('message'),
validate: function() {
this.set('message', '');
var valid = true;
if (!/^[a-z0-9]+$/i.test(this.get('value'))) {
this.set('message', 'Just numbers or alphabetic letters are allowed');
valid = false;
}
return valid;
}
});
Templates
<script type="text/x-handlebars" data-template-name="index">
{{#view App.LoginFormView}}
{{view Boostrap.TextField valueBinding="value"
label="Alpha numeric"
messageBinding="message"
hasErrorBinding="hasError"}}
<button type="submit" class="btn btn-default">Submit</button>
{{/view}}
</script>
Here a live demo
Update
Like #intuitivepixel have said, ember-boostrap have this implemented. So consider my sample if you don't want to have a dependency in ember-boostrap.

Ember valueBinding to Redactor WYSIWYG

I'm using the Redactor WYSIWYG editor and it allows you to use minimal markup before initializing its code like this:
<textarea id="redactor" name="content">
…
</textarea>
However during initialization Redactor will wrap this textarea with the following content:
<div class="redactor_box">
<div class="redactor_ redactor_editor" contenteditable="true" dir="ltr">
…
</div>
<textarea id="redactor" name="content" style="display: none;">
…
</textarea>
</div>
I currently have done this in Ember
Template:
{{ view App.RedactorView valueBinding='contentAttributes.headerContent' class='header-redactor' name='headerContent' }}
View extending Ember.TextArea:
App.RedactorView = Ember.TextArea.extend({
didInsertElement: function() {
$("#"+this.elementId).redactor();
}
});
This still holds a binding to the textarea (now hidden), but I now need to bind the redactor_editor class instead. How can I do this?
After a bit of digging in the Redactor code I found out that if your element destined to be an editor is not a textarea element, Redactor will do the reverse thing and add the textarea if your a using a div instead for example.
Updated my view and tweaked it based on code from Ember.TextArea and Ember.TextSupport so it would get the correct value, this will probably work fine if you're using a contenteditable enabled element as well.
App.RedactorView = Ember.View.extend({
tagName: 'div',
init: function() {
this._super();
this.on("focusOut", this, this._elementValueDidChange);
this.on("change", this, this._elementValueDidChange);
this.on("paste", this, this._elementValueDidChange);
this.on("cut", this, this._elementValueDidChange);
this.on("input", this, this._elementValueDidChange);
},
_updateElementValue: Ember.observer(function() {
var $el, value;
value = Ember.get(this, "value");
$el = this.$().context;
if ($el && value !== $el.innerHTML) {
return $el.innerHTML = value;
}
}, "value"),
_elementValueDidChange: function() {
var $el;
$el = this.$().context;
return Ember.set(this, "value", $el.innerHTML);
},
didInsertElement: function() {
this.$().redactor();
this._updateElementValue();
}
});
Here's a JSBin demonstrating it: http://emberjs.jsbin.com/cefebepa/1/edit
I'm using Ember + Foundation, and kroofy's solution worked like a charm for me.
The height of the contentEditable were loading without paddings (were missing a paragraph), so ive changed to redactor's insertHtml method to update the value.
from:
return $el.innerHTML = value;
to:
return this.$().redactor('insertHtml', value);
thanks kroofy.
First, when you want to access the Ember View's DOM element, you should use this:
this.$()
instead of
$("#"+this.elementId)
About the Redactor issue... I am not sure how wise it is to tie up the Ember code with the WYSIWYG editor's functionality, but if you are determined about it, you can do the following:
App.RedactorView = Ember.TextArea.extend({
didInsertElement: function() {
var box = this.$().closest('.' + this.elementId + '_box');
box.find('.' + this.elementId + '_redactor_editor').redactor();
}
});