Get text value passed to valueBinding in Ember.TextField (ember-validations) - ember.js

I'm writing an extension to Ember.TextField to change the class of the text field if the parent object is invalid. I'm using the ember-validations library to do the validations on my ember-data object. I have this working right now, but I'd love to be able to do it without passing in the validationMethod variable. How can I get just the text string passed in to valueBinding from within the view?
address.js.coffee
App.Address = DS.Model.extend(Ember.Validations,
street_1: DS.attr('string')
street_2: DS.attr('string')
...
validations:
street_1:
presence: true
)
validated_text_field.js.coffee
Ember.ValidatedTextField = Ember.TextField.extend(
validationMethod: null
classNameBindings: 'error'
focusOut: ->
object = #get('controller').get('content')
object.validateProperty(#get('validationMethod'))
error: (->
object = #get('controller').get('content')
if object.get("isValid")
return false
else
error_keys = object.get("validationErrors." + #get('validationMethod') + ".keys")
if error_keys
return error_keys.length > 0
else
return false
).property('controller.content.isValid')
)
edit.handlebars
{{view Ember.ValidatedTextField validationMethod="street_1" valueBinding="street_1" id="street_1" placeholder="Street 1" required="true"}}
...

Although I can't suggest it because it's internal code, you can get the strings from the bindings themselves.
validationMethod = #get("valueBinding._from").split(".").get("lastObject")
Check out how we handle the label for Ember-Bootstrap for another example: https://github.com/emberjs-addons/ember-bootstrap/blob/master/packages/ember-bootstrap/lib/forms/field.js

Related

Django select2 with ModelChoiceField/ createTag (how to create a create new record)

How do I handle using select2 with ModelChoiceField, but enable adding a new record
I have the Select2 JS in place, and everything works well. I can use my queryset for the ModelChoiceField, and that works. However, if I try to add a new record all I get is the error "Select a valid choice. That choice is not one of the available choices". Which is true - in the view I tried to grab "ID 0" to then create a new record, but can't get past validation without the above error
Also, if I do get this to work, it will provide the "0" ID, but ultimately I require the "term" for the new record, but can't see how this is done
<script type="text/javascript">
$("#id_indoor_cooler").select2({
theme:"bootstrap4",
search_fields: ['model_number'],
tags: true,
createTag: function (params) {
var term = $.trim(params.term);
if (term === '') {
return null;
}
return {
id: 0,
text: term,
newTag: true, // add additional parameters,
value: "myCustomValue"
}
}
});
</script>

Ember 2, Handle two or more properties in just one computed property. How to filter by search text and category

My code is here:
https://ember-twiddle.com/b894cec64a1d78a71e15b642d512cfcf
I need to use this computed property: "postsFiltered" with both Category and Search but when I change category on clickCategory() I need to reset the search text (if present).
But then the computed property is already called? No?
And the same when I search something I need to reset category to null.
postsFiltered: Ember.computed('category', 'search', function () {
var posts = this.get('posts');
var search = this.get('search');
console.log('computed postsFiltered() with category: ' + this.get('category') + ', search: ' + search);
return posts.filter((item) => item['categoryId'] === this.get('category'));
// or this when I search, but I don't know how to do one or the other:
// return posts.filter((item) => item['name'].includes(search));
})
How to handle two properties in the same computed property?
You need to introduce search:'', in controller, and pass it down to posts component {{my-posts posts=posts category=category search=search}} and your clickCategory should reset search property when category clicked
clickCategory(categoryId) {
this.set('category', categoryId);
this.set('search','');
}
This will ensure that you are following Data Down Actions Up strategy. twiddle
Edit:
Ember.computed.filterBy here the last argument is an value not the property name
Ember.computed.filter We can't use it either since we need to include one more dependancy toocategory
So finally implemented our own computed property instead inbuilt macros,
categoryPosts: Ember.computed('posts.[]','category', function(){
return this.get('posts').filter(post => post.categoryId === this.get('category'));
}),

EmberJS Formatting hasMany relation

I have the following model setup:
deliveryMethods: DS.hasMany("delivery-method", { async: true })
With this computed property:
### COMPUTED PROPERTIES ###
formattedDeliveryOptions: (->
#get('deliveryMethods').map((dm) ->
console.log dm.toJSON()
return { key: dm.get('name').underscore, value: dm.get('name') }
)
).property("deliveryMethods.#each")
And I am trying to access this property in a controller like so:
deliveryMethodsArray: (->
org = #get('controllers.application.currentOrganization')
console.log org.get('formattedDeliveryOptions')
return org.get('formattedDeliveryOptions')
).property()
But when the console.log dm.toJSON() runs, the organization property is set but nothing else. Not sure what I am doing wrong
console.log output:
Because the async is true, i believe you need to do a then() on the get promise.
org.get('formattedDeliveryOptions').then((fmtOpts) => { /* do something*/ });
Please excuse my syntax, you use a slightly different shorthand version than i do. The concept should be the same though.

Emberjs-1.0.0-rc.6 using enumerable to list events occurring on a particular date

When I define a controller action to display dates occuring a particular date, it works correctly, but If I convert that controller action to a property it stops displaying the date occuring on a particular event. The jsfiddle
App.EventsController = Em.ArrayController.extend({
todayEvent: function(date){
return this.get('content').filter(function(event) {
return (moment(event.get('start')).unix() == moment(date).unix());
});
}
});
I can fetch an instance of the controller:
u = App.__container__.lookup("controller:events")
on the event 25th, there are 2 events and I can fetch it with
u.todayEvent(new Date('2013-07-25').toString())
which correctly returns
[> Class, > class]
But in the CalendarEvent controller, I want to display the events for a particular date just like above but this time using computed-property, so I redefine todayEvent asa computed property as shown below, only this time, it only returns true or false instead returning class objects containg the events for that day.
The date property is set using controllerFor in the router serializers hook instead of passing it in as we did when we defined todayEvent as a controller action previously.
App.CalendarEventController = Em.ObjectController.extend({
date: null,
needs: ['appointments'],
todayEvent: function(){
var _self = this;
var appoint = _self.get('controllers.appointments');
var appCont = appoint.get('content');
return appCont.map(function(appointee) {
return (moment(appointee.get('event.start')).unix() == moment(_self.get('date')).unix());
});
}.property('date')
});
Now I click on the link for appointment, then the link for calendar and then click one of the dates in red from the calendar, so the serializer hook can set the controller date and I then go into the console:
u = App.__container__.lookup("controller:calendarEvent")
try to fetch the events occuring on that date in the console with:
u.get('todayEvent')
I either get an empty array like this [ ] or if I filter using map() instead of filter(), then it returns [false, false, false]
The jsfiddle
It looks like you need to add 'content.#each' to your computed property.
As it stands now 'todayEvent' will only be computed when 'date' changes I am guessing date is being set before or at the same time as the content.
todayEvent is returning [false, false] because you are using map not filter.
todayEvent: function(){
var _self = this;
var appoint = _self.get('controllers.appointments');
var appCont = appoint.get('content');
return appCont.filter(function(appointee) {
return (moment(appointee.get('event.start')).unix() == moment(_self.get('date')).unix());
});
}.property('content.#each', 'date')

Emberjs and Validation

How are people handling client side validation and ember?
Is there anything out of the box or a plugin that handles validation or are people just rolling their own?
https://github.com/dockyard/ember-validations might be useful. It also hooks up to Ember-easy-form
I would extend Ember.TextField (or whatever input type your validating) and use classBinding with a computed property. Here is the sample: http://jsfiddle.net/caligoanimus/7UNRd/
template:
<script type="text/x-handlebars" >
{{view App.AlphaNumField
placeholder="alpha-numeric data only"
valueBinding="App.alphaNumInput"}}
</script>
application:
App = Ember.Application.create({
AlphaNumField: Ember.TextField.extend({
isValid: function() {
return /^[a-z0-9]+$/i.test(this.get('value'));
}.property('value'),
classNameBindings: 'isValid:valid:invalid'
})
});
Another fully supported option and very logical if you are using bootstrap is to use bootstrap-validation plugin. In ember (ember-cli) this should be installed using bower:
bower install --save bootstrap-validation
then in ember-cli-build you must import dependencies:
//bootstrap-validator
app.import('bower_components/bootstrap-validator/dist/validator.js');
app.import('bower_components/bootstrap-validator/dist/validator.min.js');
This solution allows you to validate at html level, letting bootstrap do the 'dirty' job. For standard validations this will do the job simple and effortless.
I have been handling it in a very similar way to #caligoanimus, but validating on the focus out of the text box and appending an error message.
code:
App.TextFieldEmpty = Ember.TextField.extend({
focusOut: function() {
var valid = this.get('value') ? valid = true : valid = false;
this.$().next(".err").remove();
if(!valid){
this.$().addClass("invalid").after("<span class='err'>This field is required</span>");
} else {
this.$().removeClass("invalid")
}
}
});
Template:
<script type="text/x-handlebars">
{{view App.TextFieldEmpty}}
</script>
JSBIN:
http://jsbin.com/uriroYO/6/edit?html,js,output
I've had a lot of success with jQuery Validate:
App.MyView = Ember.View.extend({
templateName: 'my-form-template',
didInsertElement: function(){
$("#myForm").validate({
rules:{
fname:{
required: true,
maxlength: 50,
},
lname:{
required: true,
maxlength: 50,
},
email: {
required: true,
email: true,
maxlength: 200,
},
},
messages: {
email: {
email: "Enter a valid email address.",
},
},
});
}
});
Just using the Ember input helper, it's made my form validation very clean. You can take your jQuery Validate script and place it in a .js file as a function and just call that on didInsertElement.
jQuery Validate adds error messages below your fields with the message relating to the rule, and also allows you to trigger validation from any of your actions or events through the .valid() method.
We have created our own text fields which raise validation errors on focus out, and other events and other text fields extend them:
App.PhoneNumberField = App.TextField.extend({
validate: function(value) {
var self = this.$('input');
var id = self.attr("id");
var e164PhoneNumber = formatE164("AU",value);
var valid = true;
if(self.val().trim().length == 0 ){
valid = true;
}else{
valid = isValidNumber(e164PhoneNumber);
}
if (!valid) {
self.trigger(Storm.invalidInputEvent(id));
this.setErrorMessage("error","Phone Number does not look right");
}else {
self.trigger(Storm.validInputEvent(id));
this.clearMessages();
}
},
keyUp: function(evt) {
if(evt.keyCode >= 37 && evt.keyCode <=40)
{
return;
}
var textValue = this.$("input").val();
var input = this.$().find('input');
var formattedNumber = this.formatInput(textValue);
input.val(formattedNumber);
this.set('data',formattedNumber);
},
value: function() {
var phoneNumber = this.get('data');
if (phoneNumber) {
return phoneNumber;
} else {
return "";
}
}.property('data'),
data: null,
placeholder: function() {
return "";
}.property('placeholder'),
formatInput: function(textValue){
var formattedPhoneNumber = formatLocal("AU",textValue);
return formattedPhoneNumber;
}
});
I would use a model / persistance layer which uses a conventional "errors" object to save validation errors on the model.
Since Ember shines when it comes to observing changes, I would observe the changing errors object to determine whether or not should there be shown a validation message.
In my current setup I'm using Tower.js as framework, because it uses Ember as the View layer, and has a strong model / persistance layer. This layer allows me to define validations on model level. Each time I try to persist a model, it is validated and an error is thrown. In my views, this error aborts the "ideal" path and does not keep executing the workflow, instead it renders the validation errors in the template.