Invalid model event is not fired in the ItemView - javascript

I have defined the following events in an ItemView:
modelEvents: {
"change": "refresh",
"invalid": "handleValidation"
}
and the validate function in my Model is:
validate: function(attrs) {
if(attrs.Code == "")
return "Error in Code field";
else if(attrs.Name == "")
return "Error in Name field";
}
The problem is that when I save an instance of my model, validate function is called in the model and returns string messages succesfully, but the invalid event in the ItemView is not fired.
Thanks

What you have right now should be working. There must be some disconnect in the code that you've provided. I've create a simple JSFiddle that samples the functionality you're wanting: http://jsfiddle.net/craigjennings11/DZtDm/
var View = Backbone.Marionette.ItemView.extend({
el: '#content',
template: _.template('<button>Hello World</button>'),
events: {
'click button': 'tryToSave'
},
modelEvents: {
'invalid': 'failedValidation'
},
tryToSave: function() {
this.model.save();
},
failedValidation: function(err) {
this.$el.append('<div>' + err.validationError + '</div>');
}
});

You should trigger 'invalid' event and return error meggase as attribute.
validate: function(attrs) {
if(attrs.Code == "")
this.trigger('invalid', 'Error in Code field');
else if(attrs.Name == "")
this.trigger('invalid', 'Error in Name field');
}
Like this.

Related

Why is `this` undefined in a Blaze event handler?

I'm stuck in a reply function to intern messages: the email reply-sending function works fine (if I choose manually in the code the to field), but I'm failing, when I choose the message to reply, to select automatically the email in the contact-messages collection (field email) with my Meteor.methods.
In few words :
var to = "bob#bob.com" => ok
var to = this.email => no value catched
Here below my event on the reply form submit and the method
Event (can't catch var to = this.email)
Template.ContactReplyModal.events({
'click .send-message':function(e) {
e.preventDefault();
Meteor.call('replyMessage', this._id, function(error) {
if(error) {
Bert.alert({
title: 'Error',
message: error.reason,
type: 'danger'
});
} else {
var to = this.email;
var from = "my#mail.com";
var subject = $('#reply-subject').val();
var message = $('#reply-message').val();
if(message != '' && subject != '') {
Meteor.call('sendEmailContact', to, from, subject, message, function (error) {
if(error) {
Bert.alert({
title: 'Error',
message: error.reason,
type: 'danger'
});
} else {
$('#reply-message').val('');
$('#reply-subject').val('');
Bert.alert({
title: 'Success',
message: 'Message sended.',
type: 'success'
});
}
});
} else {
Bert.alert({
title: 'Error',
message: 'Message error.',
type: 'danger'
});
}
}
});
},
//Close events for ContactReplyModal
'click .close-login': ()=> {
Session.set('nav-toggle-contactreply', '');
},
'click .modal-overlay-contactreply': ()=> {
Session.set('nav-toggle-contactreply', '');
}
});
Method (using here the replyMessage function)
//Contact Method
Meteor.methods({
insertMessage: function(message) {
ContactMessages.insert(message);
},
openMessage: function(messageId) {
ContactMessages.update({_id: messageId}, {$set: {new: false}});
},
replyMessage: function(messageId) {
ContactMessages.findOne({_id: messageId});
},
deleteMessage: function(messageId) {
ContactMessages.remove({_id: messageId});
}
});
EDIT
The bind of the variable email with an arrow function doesn't work.
So maybe it is an issue of capturing the variable?
I cant' read console.log (this); and console.log (this.email); says undefined.
Here below is my message collection.
"_id": "6c3478WugEajr6zaw",
"name": "bob",
"email": "bob#bob.com",
"message": "This is a try.",
"submitted": "2017-01-05T15:19:04.642Z",
"new": true
I really don't understand, cause this below event works on the openMessage method (so the right message is correctly identified from the others)
//CLIENTSIDE
'click .open-message':function() {
Meteor.call('openMessage', this._id, function(error) {
if(error) {
Bert.alert({
title: 'Error',
message: error.reason,
type: 'danger'
});
}
});
}
//SERVERSIDE
Meteor.methods({
insertMessage: function(message) {
ContactMessages.insert(message);
},
openMessage: function(messageId) {
ContactMessages.update({_id: messageId}, {$set: {new: false}});
},
replyMessage: function(message) {
ContactMessages.findOne({_id: message});
},
deleteMessage: function(messageId) {
ContactMessages.remove({_id: messageId});
}
});
EDIT 2
As asked, below the template & the js linked to. The method is already showed and an example of the data in collection too.
template (contact-reply.html)
<template name="ContactReply">
<h3>Reply</h3>
<h3>To: {{email}}</h3>
<input class="form-control" type="text" name="reply-subject" id="reply-subject" placeholder="Subject"/>
<br>
<textarea class="form-control" name="reply-message" id="reply-message" rows="6"></textarea>
<br>
<button class="btn btn-success send-message">Send</button>
</template>
<template name="ContactReplyModal">
<div class="contactreply-modal {{$.Session.get 'nav-toggle-contactreply'}}">
<i class="fa fa-close close-login"></i>
<h3>Send a reply</h3>
{{> ContactReply}}
</div>
<div class="modal-overlay-contactreply"></div>
</template>
js of the template (contact-reply.js)
import './contact-reply.html';
Template.ContactReplyModal.events({
'click .send-message':function(e) {
e.preventDefault();
console.log(this);
Meteor.call('replyMessage', this._id, (error) => {
if(error) {
Bert.alert({
title: 'Error',
message: error.reason,
type: 'danger'
});
} else {
console.log (this.email);
const to = this.email;
var from = "my#mail.com";
var subject = $('#reply-subject').val();
var message = $('#reply-message').val();
if(message != '' && subject != '') {
Meteor.call('sendEmailContact', to, from, subject, message, (error) => {
if(error) {
Bert.alert({
title: 'Error',
message: error.reason,
type: 'danger'
});
} else {
$('#reply-message').val('');
$('#reply-subject').val('');
Bert.alert({
title: 'Success',
message: 'Message sended.',
type: 'success'
});
}
});
} else {
Bert.alert({
title: 'Error',
message: 'Message error.',
type: 'danger'
});
}
}
});
},
//Close events for ContactReplyModal
'click .close-login': ()=> {
Session.set('nav-toggle-contactreply', '');
},
'click .modal-overlay-contactreply': ()=> {
Session.set('nav-toggle-contactreply', '');
}
});
First, it is important to be sure that the data context is correct.
Each element within the template is rendered with a certain data context. If you target them in a template event handler, the data context will be available to the handler via this.
If you target an element that is not rendered by the current template (e.g, rendered by a third-party library or belongs to a sub-template), it will not have a data contest, which is what causes your data context to be undefined).
Having that fixed, assuming the data context (the external function's this) is indeed what you expect in the event handler (i.e, has an email field), you need to make it available to the callback. You can capture it in a local variable and make it available in a closure or lexically bind it with an arrow function:
Template.ContactReplyModal.events({
'click .send-message':function(e) {
e.preventDefault();
console.log(this); // to make sure that it is what you are expecting.
Meteor.call('replyMessage', this._id, (e) => { // note the arrow function
if(e) {
// ...
} else {
const to = this.email;
// ...
if(message != '' && subject != '') {
Meteor.call('sendEmailContact', to, from, subject, message, (e) => {
if(e) {
// ...
} else {
// ...
}
});
} else {
// ...
}
}
});
},
// ...
});
However, it does not seem like a good idea to use multiple nested method calls. It would probably be better to do it all in a single method call.
You can not access the template variable in template events using this, you can access them by the 2nd parameter in your events, here is your code, hope it will work
Template.ContactReplyModal.events({
'click .send-message'(e, instance) {
e.preventDefault();
Meteor.call('replyMessage', this._id, function(error) {
if(error) {
Bert.alert({
title: 'Error',
message: error.reason,
type: 'danger'
});
} else {
var to = instance.email;
var from = "my#mail.com";
var subject = $('#reply-subject').val();
var message = $('#reply-message').val();
if(message != '' && subject != '') {
Meteor.call('sendEmailContact', to, from, subject, message, function (error) {
if(error) {
Bert.alert({
title: 'Error',
message: error.reason,
type: 'danger'
});
} else {
$('#reply-message').val('');
$('#reply-subject').val('');
Bert.alert({
title: 'Success',
message: 'Message sended.',
type: 'success'
});
}
});
} else {
Bert.alert({
title: 'Error',
message: 'Message error.',
type: 'danger'
});
}
}
});
},
});

I am unable to execute validation in Backbone.js.

Whenever I set the age attribute to negative value it doesn't return false.
I have also tried executing this code in the console and still nothing happens
<script>
var Human = Backbone.Model.extend({
// If you return a string from the validate function,
// Backbone will throw an error
defaults: {
name: 'Guest user',
age: 23,
occupation: 'worker'
},
validate: function( attributes ){
if( attributes.age < 0){
return "Age must me positive";
}
if( !attributes.name ){
return 'Every person must have a name';
}
},
work: function(){
return this.get('name') + ' is working';
}
});
var human = new Human;
human.set("age", -10);
human.on('error', function(model, error){
console.log(error);
});
</script>
There are a few things wrong with your code:
The event for validation is invalid, error is for ajax requests.
Validation on set doesn't happen by default, you need to pass { validate: true } as an option.
You are listening to the event AFTER setting, so it won't get called for that set.
i.e:
human.on('invalid', function(model, error) {
console.log(error);
});
human.set("age", -10, { validate: true });

autogenerated getter is undefined - ExtJS 4

This may be a duplicate question but in either case I wanted to ask.
I am a beginner ExtJS 4 developer and I am learning ExtJS using Loiane Groner's book, Mastering ExtJS 4. So far so good, but when I got to use refs the app breaks telling me that the autogenerated method is unavailable:
Here is my Login controller code:
Ext.define('Packt.controller.Login', {
extend: 'Ext.app.Controller',
requires:[
'Packt.util.MD5'
],
views:[
'Login',
'authentication.CapsLockTooltip'
],
refs: {
ref: 'capslocktooltip',
selector: 'capslocktooltip',
autoCreate : true
},
init: function(){
this.control({
"login form button#submit":{
click: this.onButtonClickSubmit
},
"login form button#cancel": {
click: this.onButtonClickCancel
},
"login form textfield": {
specialkey:this.onTextfieldSpecialKey
},
"login form textfield[name=password]": {
keypress: this.onTextfieldKeyPress
}
});
},
onTextfieldKeyPress: function(field, e, options){
var charCode = e.getCharCode();
if((e.shiftKey && charCode >= 97 && charCode <= 122) ||
(!e.shifKey && charCode >= 65 && charCode <= 90)){
if(this.getCapsLockTooltip() === undefined) {
Ext.widget('capslocktooltip');
}
} else {
if(this.getCapsLockTooltip() !== undefined) {
this.getCapsLockTooltip().hide();
}
}
},
onTextfieldSpecialKey: function(field, e, options){
if(e.getKey() == e.ENTER){
var submitBtn = field.up('form').down('button#submit');
submitBtn.fireEvent('click', submitBtn, e, options);
}
},
onButtonClickSubmit: function(button, e, options){
console.log('login submit');
var formPanel = button.up('form'),
login = button.up('login'),
user = formPanel.down('textfield[name=user]').getValue(),
pass = formPanel.down('textfield[name=password]').getValue();
if (formPanel.getForm().isValid()){
Ext.get(login.getEl()).mask("Authenticating... Please wait...", 'loading');
pass = Packt.util.MD5.encode(pass);
Ext.Ajax.request({
url:'php/login.php',
params:{
user:user,
password:pass
},
success: function(conn, response, options, eOpts){
Ext.get(login.getEl()).unmask();
var result = Ext.JSON.decode(conn.responseText, true);
if(!result){
result = {};
result.success = false;
result.msg = conn.responseText;
}
if(result.success){
login.close();
Ext.create('Packt.view.MyViewport');
} else {
Ext.Msg.show({
title:'Fail!',
msg: result.msg,
icon:Ext.Msg.ERROR,
buttons: Ext.Msg.OK
});
}
},
failure: function(conn, response, options, eOpts){
Ext.get(login.getEl()).unmask();
Ext.Msg.show({
title: 'Error!',
msg: conn.responseText,
icon: Ext.Msg.ERROR,
button: Ext.Msg.OK
});
}
});
}
},
onButtonClickCancel: function(button, e, options){
console.log('login cancel');
button.up('form').getForm().reset();
}
});
In firebug is see this:
TypeError: this.getCapsLockTooltip is not a function
I also was checking the Ext object inside Firebug and the closest thing to my function was this:
Ext.app.Application.instance.getController('Login').getAuthenticationCapsLockTooltipView();
But i didn't find the required function. What do I do wrong?
I follow the book and the above code is what you get.
Here is the caps lock view:
Ext.define('Packt.view.authentication.CapsLockTooltip', {
extend: 'Ext.tip.QuickTip',
alias: 'widget.capslocktooltip',
target: 'password',
anchor: 'top',
anchorOffset: 60,
width: 300,
dismissDelay: 0,
autoHide: false,
title: '<div class="capslock">Caps Lock is On</div>',
html:'<div>Having caps log on may cause you the enter password incorrectly.</div>'
});
The ref is case sensitive so the function what is created is getCapslocktooltip
When using refs see also Blessing and Curse of refs article
I found in the ExtJS 4 docs that refs is and array so when using it don't forget to add square brackets lik this:
refs:[
{
ref: 'capsLockTooltip',
selector: 'capslocktooltip'
}
]
http://docs.sencha.com/extjs/4.2.0/#!/api/Ext.app.Controller-cfg-refs
So now when you search JS memory with
Ext.app.Application.getController('Login').getCapsLockTooltip();
getCapsLockTooltip() function will exist. Also selector would be the alias name of the components you are trying to access.
Also just to note, Mastering ExtJS 4 by Loiane Groner has code errors.

backbonejs validation on create

this is my model
Msg = Backbone.Model.extend({
validate: function(attr){
if(attr.msg === undefined || attr.msg === ''){
return "empty messege";
}
},
initialize: function(){
this.on('invalid',function(model,error){
console.log(error);
});
}
});
and I have collection of Msgs msgCollection
so if I do msgCollection.create({msg:''});
this model gets added to collection
how can I prevent this
For the record!
Pass
{wait:true}
as an option when you call create:
msgCollection.create({msg:''}, {wait:true});

Jquery.Validate error message on top of form

I was wondering how to display a single error message above the form instead of individual field messages. like this form has http://jquery.bassistance.de/validate/demo/marketo/step2.htm
I know it has something to do with handles but not exactly sure how or where to put them
<script>
$(document).ready(function(){
$("#valform").validate();
});
</script>
this is the code i have that uses all default validation
You should use invalidHandler for this functionality. Something like this should do:
$("#myform").validate({
invalidHandler: function(form, validator) {
var errors = validator.numberOfInvalids();
if (errors) {
$("#error-message").show().text("You missed " + errors + " field(s)");
} else {
$("#error-message").hide();
}
}
});
Example: http://jsfiddle.net/KheRr/1/
If you want to hide the default error messages, you should specify "" as the error message for the field and validation type:
$("#myform").validate({
invalidHandler: function(form, validator) {
var errors = validator.numberOfInvalids();
if (errors) {
$("#error-message").show().text("You missed " + errors + " field(s)");
} else {
$("#error-message").hide();
}
},
messages: {
field1: {
required: "" // You'll have to do this for each field and validation type.
}
}
});
Example: http://jsfiddle.net/KheRr/2/

Categories