I want to validate some form field in blur event. How can i do it with Backbone.Form?
I found it. May be useful to someone else.
var oldText= Backbone.Form.editors.Text;
var newText= oldText.extend({
initialize: function(options) {
oldText.prototype.initialize.call(this,options);
this.on("blur",function(){
this.form.fields[this.options.key].validate();
});
}
});
Backbone.Form.editors.Text=newText;
This code change basic text editor and all input[type="text"] and other extends fields will validate on blur event.
If you want create one "blur validate field". You can create new editor.
Backbone.Form.editors.BlurText= Backbone.Form.editors.Text.extend({
initialize: function(options) {
Backbone.Form.editors.Text.prototype.initialize.call(this,options);
this.on("blur",function(){
this.form.fields[this.options.key].validate();
});
}
});
Now you can use it in schema:
var User = Backbone.Model.extend({
schema: {
username: {
type:'BlurText',
validators: ['required']
}
}
});
You should be able to do this:
form.on('password:blur', function() {
form.fields.password.validate();
});
Related
I have multiple container with field. Basically when container is hidden all field's are not visible. but I was checked "hidden" property or "isHidden()" method of field. I am getting as false.
I want make it as true when container is hidden and false when it is visible.
How to make field are hidden and show by using override
Your question is very hard to read. (Poor English) But if I understand correctly you hide a container with fields. If you then check the isHidden() of one of the fields, it returns false. That is standard Ext behavior. The container is hidden not the fields. What you can do is query down and set the fields hidden.
E.g.
Ext.define('MyCustomContainer', {
extend: 'Ext.Container',
hide: function () {
var me = this;
Ext.each(me.query('field'), function (field) {
field.hide();
});
me.callParent(arguments);
},
show: function () {
var me = this;
Ext.each(me.query('field'), function (field) {
field.show();
});
me.callParent(arguments);
}
});
You ask:
I don't want to create custom component. Can I do same thing by using override?
Yes you can!
I hope you don't have an Ext.Container as type it's kind of dirty overriding it for ALL containers, but it will work... => it would be better to replace Ext.Container with the specific type of your container...
Ext.define('YourApp.override.Container', {
override: 'Ext.Container',
hide: function () {
var me = this;
Ext.each(me.query('field'), function (field) {
field.hide();
});
me.callParent(arguments);
},
show: function () {
var me = this;
Ext.each(me.query('field'), function (field) {
field.show();
});
me.callParent(arguments);
}
});
I have a Backbone model that looks like this
...
var Address = Backbone.Model.extend({
urlRoot: '/address/'
});
return { address: Address }
});
I have a template that prints out an address in a form. The template is rendered by a view that is passed an address id in it's 'render' function. The view is reached by a route like this 'address/:id'.
The view looks like this:
var AddressView = Backbone.View.extend({
el: $('#myclass'),
render: function(options) {
var that = this;
var addr = new A.address({id: options.aid});
addr.fetch({
reset: true,
success: function(address) {
var template = _.template(ATemplate, {address: address});
that.$el.html(template);
}
});
return this;
},
events: {
'submit .edit-address-form': 'editAddress'
},
editAddress: function(ev) {
//serializeObject creates JSON object from form data
var addressDetails = $(ev.currentTarget).serializeObject();
addr.save(addressDetails, function(addr) {
R.router.navigate('', {trigger: true});
});
return false;
}
});
return {
addressView: new AddressView()
};
});
There are two problems. The first problem is that the 'editAddress' function is never getting called, even though the class name is correct and the button type = is 'submit'.
The second problem is when I submit the address form the URL is garbled, a query string is interpolated between the base URL and /#/address, as in
http:///ldmanclient/address=2500+Moffitt+Library&address2=University+of+California%2C+Berkeley&city=Berkeley&zipcode=94720&mailcode=6000&aid=1#/address/1
Has anyone seen this type of behavior before? What am I doing wrong?
As mu said, the form is being submitted the standard way before Backbone gets to it. Try preventing the submit action:
editAddress: function(ev) {
ev.preventDefault();
// same code as above
}
Sorry for my title, it could not be relevant. I'll try to explain better in this post :)
I understand my problem and I find a solution but I'm not sur this is the good way to do it, so I would like some advise.
My workflow:
I have a form where the user can enter an id.
I make a validation (empty field etc.) and call an API when he click on submit.
if the id exist, I register all the information in my database and send a response with an User Object(Symfony2 + fosRestBunble)
My problem:
When I click for the first time on the form, it works well and a new user his create. But when I try to register a second user, he makes a PUT request because of the id send with the previous user object.
I understand why when I see my code, because I initialize my user model in the intialize function of my view. (before it was outside)
Here is my view:
define(['backbone',
'views/notification/form',
'models/form',
'text!templates/user-form.tpl'],
function(Backbone,
NotificationForm,
User,
FormTpl) {
var UserForm = Backbone.View.extend({
el: "#user-form",
template: _.template(FormTpl),
initialize: function() {
this.model = new User();
this.model.on("invalid",this.showErrors, this);
this.model.on('request',this.ajaxStart, this);
this.model.on('sync',this.ajaxComplete, this);
},
events: {
submit: 'register'
},
render: function() {
this.$el.html(this.template());
},
register: function(e) {
e.preventDefault();
var attrs = {
counter: 0,
created: new Date(),
updated: new Date(),
stackexchangeId: $('#stackId').val(),
site: $('#site').find(":selected").text()
};
var self = this;
this.model.save(attrs,
{
wait:true,
success: function(model, response) {
console.log('success ajax');
console.log(model);
console.log(response);
self.collection.add(model);
//self.collection.add(new User(response));
var form = { id:'#user', messages: 'User has been registered' };
var success = new NotificationForm({ type: 'success', form: form} );
success.closeSuccessNotification();
},
error: function(model, xhr, options) {
self.ajaxComplete();
if(xhr.status == '500') {
var form = { id:'#user', messages: 'Connection StackExchange API failed' };
} else {
var response = JSON.parse(xhr.responseText);
var form = { id:'#user', messages: response.users };
}
new NotificationForm({ type: 'warning', form: form} );
}
}
);
},
showErrors: function(errors) {
var form = { id:'#user', messages: errors.validationError };
new NotificationForm({ type: 'error', form: form} );
},
ajaxStart: function() {
this.$('#spinner-register').addClass('spinner-anim');
},
ajaxComplete: function() {
this.$('#spinner-register').removeClass('spinner-anim');
}
});
return UserForm;
So when I click a second time my model is the same and the id is here.
I have found a solution but I'm not sur this is a good one because I have to move my event from the initialize function.
So I create that :
test: function(model) {
model.on("invalid",this.showErrors, this);
model.on('request',this.ajaxStart, this);
model.on('sync',this.ajaxComplete, this);
},
and in register I make that:
register: function(e) {
this.model = new User();
this.test(this.model);
e.preventDefault();
etc.
}
It works fine but I totally remove the initialize function, it doesn't sound very good. I would like to keep the initialize like in my first example and to always have a new User model.
Thanks :)
You can use model.clear() to make the model as fresh as new, then on save() the POST request will be sent.
...
this.model.clear();
this.model.save(attrs,
...
I've a model listen on the vent for a event update:TotalCost, which is triggered from (unrelated) Collection C when any model M belonging to collection C changes.
This event is coded in the initialize method as below. On receiving the event I get the following error:
TypeError: this.set is not a function
this.set({ "totalsale": value});
CostModel = Backbone.Model.extend({
defaults: {
totalSale: 0,
totalTax: 0
},
initialize: function(attrs, options) {
if(options) {
if(options.vent) {
this.vent = options.vent;
}
}
this.vent.on("update:TotalCost", function(value) {
this.set({ "totalSale": value}); **//ERROR HERE**
});
}
});
It is highly possible you've forgot to add the new keyword before your model for example you have:
var user = UserModel();
// instead of
var user = new UserModel();
Have you tried using a closure?
CostModel = Backbone.Model.extend({
defaults: {
totalSale: 0,
totalTax: 0
},
initialize: function(attrs, options) {
var self = this;
if(options) {
if(options.vent) {
this.vent = options.vent;
}
}
this.vent.on("update:TotalCost", function(value) {
self.set({ "totalSale": value});
});
}
});
Perhaps you want this to refer to current CostModel instance, to do so you need to pass this to this.vent.on call so event callback will be executed in context of model:
this.vent.on("update:TotalCost", function(value) {
this.set({ "totalSale": value});
}, this);
it may be due to 'set' works on model not on object. so you can, first convert your object in to model then try..
in example:
new Backbone.Model(your_object).set('val', var);
Another cause of this error can be if you try to create a new model without using the "new" keyword
I was getting this mysterious error when using it with Parse. I had:
Parse.User().current().escape("facebookID")
... when I should have had:
Parse.User.current().escape("facebookID")
Removed the extra () and it works fine now.
Another cause:
// render() method in view object
setInterval(this.model.showName, 3000);
// showName() method in model object
showName: function(){
console.log(this.get('name')); // this.get is not a function
}
I am having problems including an additional model into my view which is based on a collection. I have a list of comments which is created by a parent view. Its need that I have the current user name when rendering the comments to show delete button and to highlight if its his own comment. The problem is now that I cant access in CommentListView the model session, so this.session in initialize or a call from a method like addAllCommentTo list is undefinied. What I am doing wrong here? I thought its easily possible to add another object to an view appart from the model.
CommentListView:
window.CommentListView = Backbone.View.extend({
el: $("#comments"),
initialize: function () {
this.model.bind('reset', this.addAllCommentToList, this);
this.model.bind('add', this.refresh, this);
this.model.bind('remove', this.refresh, this);
},
refresh: function(){
this.model.fetch();
},
addCommentToList : function(comment) {
console.log("comment added to dom");
//need to check why el reference is not working
$("#comments").append(new CommentView({model:comment, sessionModel: this.session}).render().el);
},
addAllCommentToList: function() {
$("#comments").empty();
this.model.each(this.addCommentToList);
}
});
Call from parent list in initialize method:
window.UserDetailView = Backbone.View.extend({
events: {
"click #newComment" : "newComment"
},
initialize: function () {
this.commentText = $("#commentText", this.el);
new CommentListView({ model: this.model.comments, session: this.model.session });
new LikeView({ model: this.model.like });
this.model.comments.fetch();
},
newComment : function() {
console.log("new comment");
this.model.comments.create(
new Comment({text: this.commentText.val()}), {wait: true}
);
this.commentText.val('');
}
});
Model:
window.UserDetail = Backbone.Model.extend({
urlRoot:'/api/details',
initialize:function () {
this.comments = new Comments();
this.comments.url = "/api/details/" + this.id + "/comments";
this.like = new Like();
this.like.url = "/api/details/" + this.id + "/likes";
this.session = new Session();
},
...
});
I see one problem, but can there be others.
You are initializing the View like this:
new CommentListView({ model: this.model.comments, session: this.model.session });
And you are expecting into your View to have a reference like this this.session.
This is not gonna happen. All the hash you send to the View constructor will be stored into this.options, from Backbone View constructor docs:
When creating a new View, the options you pass are attached to the view as this.options, for future reference.
So you can start changing this line:
$("#comments").append(new CommentView({model:comment, sessionModel: this.session}).render().el);
by this other:
$("#comments").append(new CommentView({model:comment, sessionModel: this.options.session}).render().el);
Try and tell us.
Updated
Also change this line:
this.model.each(this.addCommentToList);
by this:
this.model.each(this.addCommentToList, this);
The second argument is the context, in other words: what you want to be this in the called handler.