Instantiate model from existing model in Backbone - javascript

What is the preferred way, if any, to instantiate a Backbone model from an existing model, assuming that the model to be instantiated is of a derived type of the existing model?
The case I have in mind arises when dealing with nested models. For instance, let's say I am using DeepModel and I define a function on my "parent" model that returns this.get("childModel"). Now the child model is likely of type Backbone.Model but I would like it to be of type ChildModel which extends Backbone.Model. I have been doing this by literally copying over the interesting attributes one at a time. Surely there must be a better way...

You can create new instance of the same model by using Backbone.Model#clone() method or just using new model.constructor().
var ChildModel = Backbone.Model.extend({
...
});
var child = new ChildModel({ key: "value" });
var new_child = child.clone();
If we see the source of clone method:
clone: function() {
return new this.constructor(this.attributes);
},
we can use the same approach to create new instance but with our data
var new_child = new child.constructor({ new_key: "new_value" });

Related

mongoose model, why do I need to use "new"? (TypeScript)

I don't understand this completely, as you will see.
But I create a new mongoose.model like this:
let MyModel = moongoose.model<IMyModel>("myModel", MyModelSchema);
What is the diffrence on MyModel and let newModel = new MyModel?
I need to create newModelto use function such as .save(). Why is that?
When you use moongoose.model, you're not creating an instance of your model, you're creating a constructor for it - in other words, MyModel is a class, and newModel is an instance of that class.

defineProperty on Backbone model

If i want to add a custom property to my backbone model, is this the best was to do this? Is there a better way or a completely different approach to the functionality i want to achieve?
var myModel = Backbone.Model.extend({
defaults:{
monthly_amount: 100
},
initialize: function(model, options){
var m = this;
Object.defineProperty(this,"yearly_amount",{
get: function() {
return (m.get("monthly_amount") * 12);
},
set: function(value) {
m.set("monthly_amount", (value/12) );
}
});
}
});
Thanks!
Edit: The property is just "virtual", i do not want it to be within the model attributes when saving the model to the server.
So the general problem here is often referred to as "computed properties" and there are plugins for backbone that provide this (see below). Backbone uses get/set method calling style as opposed to defineProperty style so your approach would make the value computation not transparent to views and thus be a pretty strong departure from backbone's design. A plugin that maintains the proper get/set and change interfaces is going to maintain the basic Model API so the view doesn't have to treat this particular model attribute differently.
See also the backbone wiki of plugins.
Available plugins:
Backbone.ModelMorph
Backbone.ComputedModel
Backbone.Spark
Backbone.ComputedFields
When you set your property to defaults oject, it goes to attributes, but it doesn't suit us.
Since Backbone model is an regular object, you can access to it's properties as to objects properties:
var myModel = Backbone.Model.extend({}),
model = new myModel();
model.monthly_amount = 50;
console.log(model.monthly_amount)
or create setter and getter like this:
var myModel = Backbone.Model.extend({
setMonthlyAmount: function (value) {
this.monthly_amount = value;
},
getMonthlyAmount: function () {
return this.monthly_amount;
}
});
//access with getter/setter
var model = new myModel();
model.setMonthlyAmount(20);
var result = model.getMonthlyAmount();
console.log(result);
Working example on jsfiddle

Where to define the model for the view

I looked at some Views from Backbone.js, but i don't see at which point it is declared which model is binded to the view ?
For example here where does the view defines which model is this.model ?
https://github.com/addyosmani/todomvc/blob/gh-pages/dependency-examples/backbone_require/js/views/todos.js
When you pass a model property in the options argument to the View's constructor, Backbone automatically sets it as view.model:
var someModel = new Model();
var view = new View({model:someModel});
console.log(view.model === someModel); // -> true
This feature is documented here.
When creating a new View, the options you pass — after being merged into any default options already present on the view — are attached to the view as this.options for future reference. There are several special options that, if passed, will be attached directly to the view: model, collection, el, id, className, tagName and attributes.
In the Todolist example the model is set in app.js, line 75.
addOne: function( todo ) {
var view = new TodoView({ model: todo });
$('#todo-list').append( view.render().el );
},

In Backbone, can I add model behavior to a collection?

If I have a collection of objects, but also want to store some higher-level information about those objects, is it appropriate to add some model behavior to the collection?
In my situation, I'm looking for a collection of application paths to have a bool field called 'curPath'. If it's changed, the collection should set a flag that indicates the current page. This way outside observers only have to observe one field, not every model in the path collection.
Here's what that might look like:
var PathModel = Backbone.Model.extend({})
var PathCollection = Backbone.Collection.extend({
initialize: function(){ this.model = PathModel }
})
// I want to be able to set observable properties on the collection, so...
var PathManager = _.extend(Backbone.Model, PathCollection)
// Then maybe I can do something like this?
PathManager.each(function(pathModel){
pathModel.on('change:curPath', function(m, value, o){
// I mean for 'this'.set to point to the instance of the PathManager
if (value === true){ this.set('curPath', pathModel.get('id')) }
}, this)
}, this)
Is it appropriate to add observable behavior to a collection (collection+model > model), or do I need to add a wrapping model to the whole thing (model > collection > model), or is there some other solution?
As some of the methods on Model and Collection have the same names that will cause conflicts and possible problems with updating to future versions of Backbone could occur I would advise against this pattern. Rather then doing that create a PathManager class and have PathCollection be initialized and set it as paths property on this model. If from what you are saying
var PathManager = Backbone.Model.extend({
initialize: function() {
this.paths = new PathCollection();
}
});
var pathManager = new PathManager();
pathManager.paths.add({ /* new path */ });
pathManager.on('change', doSomething);
pathManager.paths.on('add', doSomethingElse);
I'd do it something like this

How do i overwrite the default Backbone Model?

I want to overwrite the default Backbone Model variable (Backbone.Model) to use my own custom validation methods (isValid, validate) and to add some properties.
_.extend(Backbone.Model, {
isValid: function() { // custom function },
validate: function() { // custom logic }
});
var myModel = Backbone.Model.extend({
// this adds for example properties to my modified Backbone model.
});
Unfortunatly this doesn't work... when I load the "wrapper, extending"-module with requirejs and create a new Model instance and than call validate. It says that it doesn't know any validate function...
you have to extend Backbone.Model.prototype rather then Backbone.Model itself as all the methods are prototype methods of the constructor function rather then properties on the model. Though it might be better idea to create a custom BaseModel that will extend the Backbone.Model and implement your custom logic so that if backbone gets updated etc. you will avoid possible conflicts even if in this case they are rather unlikely it's still considered a better practice to extend base Backbone classes rather then to modify them.
I prefer to do custom Models for the project instead of "overwrite" that is not OOP. (at the end of the way could be the same but if we try to emulate OOP I feel that is more easy to understand).
Check my example, I define YourAbstractModel that it is the kind of extension of the Backbone.Model, then all of my Models extend that abstract Model instead of the Backbone Model.
var YourProject = {};
YourProject.YourAbstractModel = Backbone.Model.extend({
customProperty1 : null,
customProperty2 : null,
isValid : function(){ },
specificUtility : function(){ }
});
var YourModel1 = YourProject.YourAbstractModel.extend({
customProperty1 : 'aaaaa'
});
var YourModel2 = YourProject.YourAbstractModel.extend({
customProperty1 : 'bbbbb'
});
console.log( new YourModel1().customProperty1 );
console.log( new YourModel2().customProperty1 );
My way is also flexible to have more than one abstract Model, does not conflict with updates of Backbone and I feel is more close to inheritable process.
You can use the Backbone.Validation plugin by thedersen
https://github.com/thedersen/backbone.validation
Its pretty helpful and easy to use. You can also bind your view to the model, so that your view has your custom-error attribute for the specific model property which failed validation.

Categories