Ember.js server side form validation display - ember.js

I have a form in Ember JS and I want to:
1. Display the errors for the fields right next to each field in error ;
2. Display any general errors at the top of the form ;
3. Have these errors persist while the user correct the form.
Edit: JSBin here
I have the following template for the form:
{{#if isSaving}}
<p>Saving Record</p>
{{/if}}
{{#if isError}}
<p>There was an error saving the record</p>
Base errors( {{errors.base}} )
{{/if}}
<form {{action 'create' this on='submit'}}>
<p>Title: {{input type="text" value=title}}</p>
<p>Title Errors( {{errors.title}} )</p>
<p>Body: {{textarea value=body}}</p>
<button>Create</button>
</form>
Right now my server is returning the following
{"errors":{"body":["can't be blank"],"title":["should begin with a capital letter"],"base":["General error message here"]}}
errors.title above is returning an object. How can I get the message out of it.
When the user starts typing, the object message is wiped out.
The isError never seems to fire.
What am I doing wrong?

First: Your errors.title is (like all the other properties of your server response) an Array so you'd get the title with errors.title[0]. As you cannot reference it like this from Handlebars directly you'd either have to provide it from the controller or pass your server response to a custom helper.
Second: It's hard (or better to say impossible) to tell why isError is never triggered/set without code...

errors is an array, and the proper way to iterate over them is the following:
{{#each errors.fieldname}}
{{this.message}}
{{/each}}

Related

Inputs on Ember refresh page when a user hits Enter key

I'm using Ember CLI and have noticed odd behaviour. When the user clicks into the input and presses the enter key, the page refreshes.
My page has a basic element like this that is NOT part of any form:
<input type="text" class="form-control" id="per_page" value="50">
I am currently serving the page via:
ember cli
So node is hosting and has the fancy live reload thing going on so that when I update a page that is part of the underlying app.
So what is causing a page reload the enter key pressed inside an input? Could it be node or live reload? Are inputs just supposed to refresh a page when a user presses the enter key and I missed that in my HTML for dummies book?
**Better still, how can I intercept and instead call a function via:
{{action** "myFunction"}}
That happens because when you hit Enter, form gets submitted which results in page reload. what you need to do is set onsubmit="return false" on the form so nothing happens during submit. you can bind input to execute some action by adding action attribute action="doSomething"
<form onsubmit="return false">
{{input type="text" action="createComment" value=topic id="inputTopic"}}
</form>
Edit: In Ember 3+ you now use the {{on}} modifier to setup events on elements.
<form {{on 'submit' this.submitForm}}>
<!-- the rest of your form here -->
<button type='submit'>Submit</button>
</form>
And the action defined like so
#action
submitForm(event) {
event.preventDefault();
// Your code
}
Historically Ember has handled this use case with the following code:
<form {{action 'submitForm' on='submit'}}>
<!-- the rest of your form here -->
<button type='submit'>Submit</button>
</form>
This prevents the form from refreshing the page.
There is another method that gives you more control, by giving you the event so you can manage that yourself:
<form onsubmit={{action 'submitForm'}}>
<!-- the rest of your form here -->
<button type='submit'>Submit</button>
</form>
In this case, you will get an event and will have to call event.preventDefault() to stop the page refresh.
actions: {
submitForm(event) {
event.preventDefault();
}
}
This is a running example of the two: https://ember-twiddle.com/827820958e054f7af57b7677630729fc?openFiles=controllers.application.js%2C
I had the same problem - what worked for me, was to overwrite the keyPress Event in the input component like this:
keyPress: function (e) {
var keyCodeEnter = 13;
if (e.keyCode === keyCodeEnter) {
return false;
}
}
Hope it will help someone in the future! :)

ember.js attribute binding and the event object

So far, it looks like Ember does not work as I expected, and I'm hoping I've just missed something. What I need to do is iterate over my model, a blob of JSON made up of arrays and objects, and build out a form. When the user marks a checkbox, the controllers Action updates the model.
Here's how I want it to work...
<form {{action 'answerSupplied'}}>
{{#each model.questions}}
<h3>{{text}}</h3>
{{#each answers}}
{{input type='../type' answerId='id' data-bind-questionNum='../id' text}}
{{/each}}
{{/each}}
</form>
Here's how I can get close to that...
<form {{action 'answerSupplied' this}}>
{{#each model.questions}}
<h3>{{text}}</h3>
{{#each answers}}
{{formbuilder ../type id ../id text}}
{{/each}}
{{/each}}
</form>
==================
Handlebars.registerHelper('formbuilder', function(type, id, qnum, text, options)
{
// console.log(options);
var q_type = options.contexts[0][type],
a_id = options.contexts[1].id,
q_number = options.contexts[0][qnum],
a_text = options.contexts[1].text;
return new Handlebars.SafeString(
'<input type='+ q_type +' id='+ a_id +' name='+
q_number +'>'+ a_text + '</input><br/>'
);
}
});
The big problem wit this is, I can not identify which element was clicked because I don't have access to the event object.
Can I manually bind the action with something like 'data-ember-action', and pass in params? Or, is this too far outside the Ember way?
== update ==
Here's the above JSFiddle, improved by passing parameters to the Action. The event propagation seems to get halted in the Action resulting in the inputs not getting properly marked. Radio buttons loose their grouping, and checkboxes do not get checked.
Ember can easily handle what you're doing here. First it's easier to keep your scope and generate named each loops.
<form {{action 'answerSupplied'}}>
{{#each question in model.questions}}
<h3>{{question.text}}</h3>
{{#each answer in question.answers}}
{{input type=question.type answerId=answer.id data-bind-questionNum=question.id placeHolder=answer.text}}
{{/each}}
{{/each}}
</form>
You may have to do some if statements for labels etc around your input statements.
http://emberjs.jsbin.com/zofoqeje/1/edit

ember.js does not {{bindAttr}} the <label> For attibute to the correct inputField.elementId in a collection

I'm trying to link a label to an input field using the {{bindAttr}} and the input field's [viewName].elementId. It works on a single entry view, but not when there are several records being displayed: it just links the label to the last input field in the collection. (This used to work in a previous iteration using an older ember library but now it doesnt.) I've created a fiddle but the gist of it is:
{{#each controller}}
<fieldset>
<label {{bindAttr for="view.tbFullName.elementId"}}>Full Name</label>
{{view App.DetailTextField viewName="tbFullName" placeholder="Full Name" valueBinding="fullName" readonly="readonly"}}
</fieldset>
{{/each}}
I thought maybe I could create a collectionView and create a calculated property for viewName which would generate a unique ID for each item in the collection, sort of mentioned in answer to another problem here. But that is getting WAY too complicated - just so that I can have the input field highlight itself if the user clicks on the corresponding label.
Any help appreciated.
Create a wrapper Ember.View around the label and input field. Let's call it App.FieldView:
App.FieldView = Ember.View.extend({
tagName: 'fieldset'
});
Then in your template:
{{#each controller}}
{{#view App.FieldView}}
<label {{bindAttr for="view.tbFullName.elementId"}}>Full Name</label>
{{view App.DetailTextField viewName="tbFullName" placeholder="Full Name" valueBinding="fullName" readonly="readonly"}}
{{/view}}
{{/each}}
Fiddle: http://jsfiddle.net/NQKvy/26/
Panagiotis Panagi, has answered the question correctly. I'll just add why this is happening, ie:- linking to the incorrect view.
The view property inside a template refers to the Ember View wrapping the html markup. This property however has different value depending on the context it is in.
This value is dependent on the view block it placed in. By default the template itself corresponds to a view in this case, ListOfPeopleTemplateView.
So when you are binding to view.tbFullName.elementId, you are actually binding to an {instance of ListOfPeopleTemplateView}.tbFullName.elementId. And when the loop finishes the only tbFullName visible is the last one.
Panagiotis Panagi's solution is to wrap the label inside another view, so the value of view changes to within that block, and hence points to the correct tbFullName
Finally an even easier way to achieve the same result is to wrap the textfield inside the label. Then you do not need the label for binding at all.
<label>Full Name
{{view App.DetailTextField viewName="tbFullName" placeholder="Full Name" valueBinding="fullName" readonly="readonly"}}
</label>
See this jsfiddle
Forms are somewhat tricky I must admit if you want to do things right. But there are is an ember add-on that comes to the rescue, for example easyForm.
Have a look it might helps you solving exact the problems you are facing, like the ones on having unique labels for your form fields etc.
Hope it helps.

emberjs-RC2 render helper scope and action bubbling not allowing form to save

The jsfiddle.
From the posts#index template, I can create a new comment by using the #linkTo helper which goes to the PostNewComment Route and renders the post/newcomment form. If I click save the newly created comment is persisted using the 'save event' inside the PostNewComment Route.
You can uncomment the line below in post/comments" template, to see it working
{{#linkTo "post.newComment"}} Add comment{{/linkTo}}
I changed my UI to use a controller isAddingNew button and the render helper to determine When to display the form and now if I click the save button, I get:
Uncaught TypeError: Cannot call method 'one' of null
This how I render it:
<p> {{render "post.newComment" }} </p>
I suspect it is a scope issue because the error is only triggered when 'save' is clicked after using the render helper.
To reach the 'add new comment' button:
click -> post -> a post title -> click comments link -> add comment
Is there a way to make the 'Post/newComment form' displayed via the 'render helper' in the post/comments template to use the 'save event' defined in the PostNewComment Route.
Right now clicking on the 'save button' which is defined in that form goes directly to the parent route ie PostCommentsRoute instead of going to its own route probably because I displaying the form via the render helper.
I thought calling 'save' should go to its own controller and then bubble to its own route where it is actually defined, before attempting to bubble up the hierarchy to the PostComments Route.
There's probably a few alternatives, but this works and is pretty idiomatic: http://jsfiddle.net/GabSY/4/
In particular:
{{#if model}}
<form {{action save content on='submit'}}>
{{view Ember.TextArea valueBinding="content.body" placeholder="body"}}
<button type="submit"> save comment </button>
<button {{action cancel}}> Cancel</button>
</form>
{{else}}
<button {{action open}}> Add comment </button>
{{/if}}
The reason you were getting the Uncaught TypeError: Cannot call method 'one' of null error was that the PostNewCommentController's model was never set. What I ended up doing was using the open action on the PostNewCommentController to set the model of the controller, which can be used in a Handlebars {{if}} to determine whether the form should be displayed or not.
I prefer this approach to the alternative of setting content/model (they are aliases to each other) of the PostNewCommentController from within the PostCommentsRoute's setupController method because if you go down that route, it's easy to start mixing concerns between not-very-related controllers and routes. In my approach, all the logic for setting the content/model of the new comment takes place in the controller for new comments, which makes sense since a new comment no longer has its own route to initialize this data.

Prevent TextField with an action to submit its form

I have a {{view Ember.TextField action="foo"}} nested in a <form> tag:
My form:
<form>
{{view Ember.TextField action="foo"}}
</form>
I hoped pressing enter in this textfield will call the action foo, without triggering a submit event on its form (because, by default, Ember.TextField#bubbles is set to false). But it is not the case: the page is reloaded.
For semantic and integration purpose, I would like to keep the <form> tag, and do not write an Ember.Form view.
You can test it in this JSFiddle.
How could I achieve this ?
PS: I'm using ember-latest:
version: v1.0.0-pre.4-31-g16442c5
last commit: 16442c5 (2013-01-23 23:48:09 -0800)
<form {{ action "" on="submit" }}> will prevent the form submission. (This is basically equivalent to the onsubmit="return false;" suggestion in another answer.)
I think the simpliest way is to add onsubmit="return false;" on the form element. Or with jQuery , preventDefault();
I'm sure this is not the best way but it work!