I have a component in my application.It have a form with text fields.It will have a submit button.When submit is pressed it will send a post request to the server.I also handled a keyboard event in components js file.When enter is pressed it will send a post request to the server.When the enter key is pressed two times continuously it is making two post request to the server with first request success and second request failed.
I want to make my app in such away even if the user presses the enter key two times continuously it should send only one post request to the server.Can any one help me solve this issue.Thanks in advance.
components js file:
export default Component.extend({
keyDown:function(event){
let self = this;
if(event.keyCode === 13){
self.send('submitform');
return false;
}
actions: {
submitform(){
//logic to handle the post request to the server
}
}
Try usig Ember.run.debounce,
export default Ember.Component.extend({
keyDown: function(event) {
let self = this;
if (event.keyCode === 13) {
// self.send('submitform');
Ember.run.debounce(self,self.get('submitform'),400);
return false;
}
},
submitform(){
//handle submit form logic
}
});
You can play with twiddle here
You will want to disable submitForm() until your POST request is complete. You can do this by setting a property submitting on the component and turning it on before the POST and off once the promise is resolved. Perhaps try something like:
export default Ember.Component.extend({
submitting: false,
keyDown: function(event) {
if (event.keyCode === 13) {
this.submitform();
}
},
submitform() {
// Run only if not currently submitting
if (!this.get('submitting')) {
// What to do when submit succeeds
const success = () => {
this.set('submitting', false);
}
// What to do when submit fails
const fail = () => {
this.set('submitting', false);
}
// Do the POST request
this.set('submitting', true);
this.get('someModel').save().then(success).catch(fail);
};
}
});
And, unrelated, this allows you to do fun things with your template such as disabling and styling the submit button for as long as the POST promise is not resolved yet:
<button {{action 'submitForm'}} disabled={{submitting}} class="{{if submitting 'loading'}}">
{{#if submitting}}
Submitting ...
{{else}}
Submit
{{/if}}
</button>
Oh and lastly, no need to use let self = this; anymore. Use ES6 arrow functions () => { ... } instead so you can keep using this inside.
Related
I have installed the ember-g-recaptcha addon in my ember app using ember install ember-g-recaptcha. I'm able to see the recaptcha in the UI. But how do I check whether that box is checked or not. If it's not checked my form should not submit and should display an error message.
I want to display this error message when the response is empty. I have written this in my controllers:
onCaptchaExpired() {
$("#message").show();
$("#message").css("color", "red");
$("#message").html("Recaptcha response cannot be empty.");
},
First you really should rely on ember to manage the DOM, and don't do it manually with jQuery.
A simple solution could be to just toggle a boolean when the g-recaptcha component fires the actions:
template:
{{g-recaptcha onSuccess=(action "onCaptchaResolved") onExpired=(action "onCaptchaExpired")}}
{{captchaError}}
<button disabled={{isInvalid}} />
component:
Ember.Component.extend({
isInvalid: true,
captchaError: null,
actions: {
onCaptchaResolved(captchaResult) {
this.set('isInvalid', false);
},
onExpired() {
this.set('isInvalid', true);
this.set('captchaError', 'Recaptcha response cannot be empty.')
}
}
})
This should give you an idea how you could do this.
have bootstrap alert messages as an ember component (they display success error warning messages...). How could I insert a message on an event? Lets say form validation is not successful, I want to pass a message with the folowing component:
{{alert-mes message="The passwords must match" type="error"}}
Embner has two way binding, so you don't need to pass a different message everytime, instead you can have an attribute that changes in the controller, and have your component listen to changes:
// controller.js
showModal: false,
message: null,
actions: {
somethingHapened: function() {
this.set('message', 'The passwords must match');
this.set('showModal', true);
}
}
// template
{{alert-mes message=message type="error" show=showModal}}
// component
onShowModal: function() {
if (this.get('show')) {
// display the modal somehow
// this.$().show(this.get('message'));
} else {
// hide the modal
}
}.observes('show')
First of all I don't use Ruby nor Devise :) (all my searches led me to plugins that kind of rely on Devise)
I want to do pretty simple authentication with Ember, I have a REST backend that blocks requests without a proper cookie(user-pass) and i want Ember to watch when it gets 403 forbidden (won't let you to transition into protected URLs) and then pop up a user-login dialog.
So when a user tries to send a new message for example(lets say i've built a forum) Ember will fire the request and if it gets 403 it will block the transition and popup a login form and will retry the transition after the login have completed
Also is there a way to get the errors from ember-data and respond to them? (if a user tries to change an attribute he can't access i would like to inform him about it[Access denied or something like that])
I want to use custom errors that my server will send to ember data not just error numbers but words like "Sorry you can't change this before 12 PM"
You can simply listen to the response of your server and transition to your LOGIN (or whatever you call it) route. In my apps I happen to keep two types of routes (LOGIN and AUTHENTICATED). When they access the authenticated routes without logging in, they get a 401 unauthorized error and get transitioned to the LOGIN route.
// AuthenticatedRoute.js
redirectToLogin: function(transition) {
// alert('You must log in!');
var loginController = this.controllerFor('login');
loginController.set('attemptedTransition', transition);
this.transitionTo('login');
},
events: {
error: function(reason, transition) {
if (reason.status === 401) {
this.redirectToLogin(transition);
} else {
console.log(reason);
window.alert('Something went wrong');
}
}
},
model: function () {
return this.store.find('post');
},
So now when the user requests for post he gets a 401 and gets transitioned to LOGIN controller.
// LoginController.js
login: function() {
var self = this, data = this.getProperties('username', 'password');
// Clear out any error messages.
this.set('errorMessage', null);
$.post('/login', data).then(function(response) {
self.set('errorMessage', response.message);
if (response.success) {
alert('Login succeeded!');
// Redirecting to the actual route the user tried to access
var attemptedTransition = self.get('attemptedTransition');
if (attemptedTransition) {
attemptedTransition.retry();
self.set('attemptedTransition', null);
} else {
// Redirect to 'defaultRoute' by default.
self.transitionToRoute('defaultRoute');
}
}
});
}
The basic answer you need is capturing the events in the route and transitioning accordingly. I just happened to include the code for attempted transition as it comes in handy at times.
I use the RESTadpater to persist data. When a validation error occurs, I want to return a 422 response and then log the errors and show an indication next to each incorrect field.
My REST response status code is as follows:
Status Code:422 Unprocessable Entity
My REST response body is as follows:
{
"message": "Validation failed",
"errors": [
{
"name": "duplicate"
}
]
}
In my controller, the becameInvalid fires correctly.
App.AuthorsNewController = Ember.ObjectController.extend({
startEditing: function () {
//Create a new record on a local transaction
this.transaction = this.get('store').transaction();
this.set('model', this.transaction.createRecord(App.Author, {}));
},
save: function (author) {
//Local commit - author record goes in Flight state
author.get('transaction').commit();
//If response is success: didCreate fires
//Transition to edit of the new record
author.one('didCreate', this, function () {
this.transitionToRoute('author.edit', author);
});
//If response is 422 (validation problem at server side): becameError fires
author.one('becameInvalid', this, function () {
console.log "Validation problem"
});
}
...
2 QUESTIONS:
I want to log below the 'console.log "Validation problem"', the complete list of errors returned by the server. How can I do that ?
In my hbs template, I want to indicate an error next to the relevant field. How can I do this ?
I am not sure that the data returned via REST adapter is correct. So problem might be at the REST side or at the Ember side ...
Solution:
In controller save function:
author.one('becameInvalid', this, function () {
console.log "Validation problem"
this.set('errors', this.get('content.errors'));
});
In hbs template:
{{view Ember.TextField valueBinding='name'}}
{{#if errors.name}}{{errors.name}}{{/if}}
Here is how I do it, may not be the best practice but it works for me:
instead of using commit(), I use save(), and if you wonder what's the difference, here is the link. I haven't tried your approach of using transaction, but basically I create the record using record = App.Model.createRecord(...), and here is the code of my apiAddShop function inside the AddShopController:
apiAddShop: function() {
//console.log("add shop");
newShop = App.Shop.createRecord({name:this.get('name'), currentUserRole:"owner"});
//this.get('store').commit(); // Use record.save() instead, then() is not defined for commit()
var self = this;
newShop.save().then(function(response){
self.transitionToRoute('shops');
}, function(response){
// if there is error:
// server should respond with JSON that has a root "errors"
// and with status code: 422
// otherwise the response could not be parsed.
var errors = response.errors;
for(var attr in errors){
if (self.hasOwnProperty(attr)) {
self.set(attr+"Error", true);
self.set(attr+"Message", Ember.String.classify(attr)+" "+errors[attr]);
}
console.log(attr + ': ' + errors[attr]);
}
console.log(response.errors.name[0]);
});
},
the above code assume there is a attrError(boolean) and attrMessage(string) for each of the attributes in your form. Then in your template, you could bind the class of your field to these error attributes, such as <div {{bindAttr class=":control-group nameError:error:"}}>, and the error message could be easily display next to the form field such as: <span {{bindAttr class=":help-inline nameError::hidden"}} id="new_shop_error">{{nameMessage}}</span> Here is my example handlebar gist (have to use gist here, since SO is escaping my html inputs).
I have seen this question in SO several times. Most of cases user called facebook js (all.js) twice or did not provide the application id. But my case is different. I have included all.js once and I also have set application id. But still I am getting this error "FB.login() called before calling FB.init()" when I click the login button. The markup for login button is as follows
<fb:login-button autologoutlink="true" perms="email,user_birthday,user_about_me,publish_stream"></fb:login-button>
And the javascript codes are
<script type="text/javascript">
FB.init({appId: '${section.parameters['facebook.app.id']}', status: true, cookie: true, xfbml: true});
/* All the events registered */
FB.Event.subscribe('auth.login', function(response) {
window.location.reload();
});
FB.Event.subscribe('auth.logout', function(response) {
// do something with response
//logout();
});
function setFacebookStatus(form) {
var status = $('#comment-form-body').val();
var params = {};
params['message']= status;
params['link'] = '${article.url}';
FB.api('/me/feed', 'post',params, function(response) {
if (!response || response.error) {
alert('Error occured');
}
else {
alert('<fmt:message key="comment.form.facebook.success" />');
$("#facebookComment").overlay().close();
form.submit();
}
});
}
</script>
I have added all.js in the header of my html page. I am really pissed off this issue. I would be very grateful if you help me.
Edit
One more thing to mention. Sometimes it works and sometimes it shows me the warning. Say I was logged in to facebook from another tab and then I logged out from facebook. Then I refresh my website page that has the facebook integration. Then I get the warning. Main problem is that sometimes it is working sometimes not.
I have modified my javascript as follows and now it is working.
$(function() {
window.fbAsyncInit = function() {
FB.init({appId: '${section.parameters['facebook.app.id']}', status: true, cookie: true, xfbml: true});
};
$('body').append('<div id="fb-root"></div>');
$.getScript(document.location.protocol + '//connect.facebook.net/en_US/all.js');
})
setFacebookStatus function remain same. Adding those scripts on document ready removes the problem of facebook javascript warning and non deterministic login behavior. My guess is that on document ready initialization of FB scripts ensures execution of all calls in required order.