Using arbitrary/different Backbone models in a view - javascript

Can one use differently defined models defined via require.js/AMD in a single central view? I mean separately defined models, not ones of a collection.
If yes, how they are referenced in the json part of the callback function of define() that defines that central view, in its vars, in functions of its attributes etc. There can only one this.model, right?
Is it possible to Render different templates, possibly populated by vars from those different models, conditionally, from within this single central view?
To extend my question:
Can one use differently defined collections defined via require.js/AMD in a single central view?
Can one use differently defined models defined via require.js/AMD in a single collection? (this alone could achieve first goal with referencing only this capable collection.)

Can one use differently defined models defined via require.js/AMD in a
single central view? I mean separately defined models, not ones of a
collection.
If yes, how they are referenced in the json part of the callback
function of define() that defines that central view, in its vars, in
functions of its attributes etc. There can only one this.model, right?
A View's this.model is just one way to provide a view with a model. You can also pass whatever other options you want to a view, like so:
var YourView = Backbone.View.exend({
initialize: function(options) {
this.foo = options.foo;
}
});
var modelA = new Backbone.Model();
var modelB = new Backbone.Model();
var yourView = new YourView({model: modelA, foo: modelB});
// yourView.model == modelA
// yourView.foo == modelB
Is it possible to Render different templates, possibly populated by
vars from those different models, conditionally, from within this
single central view?
Yup. For instance, here's an example if we add a render method to YourView:
render: function() {
if (this.model.get('bar')) {
this.$el.html(this.templateA(this.model.toJSON());
} else {
this.$el.html(this.templateB(this.foo.toJSON());
}
}
Can one use differently defined collections defined via require.js/AMD
in a single central view?
Yup, the same way as you pass in multiple models. It doesn't matter if you use Require; you can pass around Backbone objects/classes through it just fine.
Can one use differently defined models defined via require.js/AMD in a
single collection? (this alone could achieve first goal with
referencing only this capable collection.)
Yup, just throw all the models in to a single collection, like so:
var modelA = new ModelClass();
var modelB = new SomeOtherModelClass();
var collection = new Backbone.Collection([modelA, modelB]);
The only limit is that a Collection can only have a single model property, which means that whenever you create a new Model through the Collection (eg. via fetch or create) they will all be of that model.
(It's possible to get around even that with if you replace the model with a custom function, but you shouldn't need to do that.)

Related

How to create an instance of the Model Class in MVC Pattern - SapUI5

I am currently trying to implement the Model-View-Controller in my SAPUI5 / Fiori Project.
I managed to create an Instance of the Controller with: new sap.ui.core.mvc.Controller('controller.js')
This does not work for the Model (sap.ui.core.mvc does not contain a Model attribute).
Now I am searching a way to call functions of the Model from the Controller, to get my data.
I already tried this code: oObjModel = new sap.ui.mode.Model(), using this I cannot call functions from my Model.
I recommend you look at the walkthrough on the SAPUI5 documentation site. It shows how to initialize all the aspects of MVC in the correct way.
Models in SAPUI5 come in different classes to support different forms of data. For example, there is JSONModel, XMLModel, ODataModel, etc.
So to create a model, you need to first determine the specific type of model you need and use its specific constructor. For example, if you have JSON data (or simply a JavaScript object), you use the JSONModel:
var yourData = { "hello": "world" };
var oModel = new JSONModel(yourData);
Note that the above code assumes you are following the recommended way to use modules and that this code is wrapped with a sap.ui.define or sap.ui.require, where the module sap/ui/model/json/JSONModel is assigned to the variable JSONModel. The walkthrough shows this correct usage pattern. Accessing the constructor directly like the below is not recommended:
// Also probably works, but not the recommended way
var oModel = new sap.ui.model.json.JSONModel(yourData);
Your way of creating a controller is also not correct. You should preferably let the view instantiate the controller for you by providing it a controllerName, as shown in the walkthrough for Controllers.
<mvc:View xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" controllerName="name.of.your.controller">
<!-- ... -->
</mvc:View>
If you need to manually instantiate a controller from code, use this:
Controller.create({ name: "name.of.your.controller" }).then(function(oController) {
// Do something with oController
});
This again assumes you have the module sap/ui/core/mvc/Controller linked to the variable Controller.
Before version 1.56, you can use the now-deprecated sap.ui.controller function to create controllers instead:
sap.ui.controller("name.of.your.controller", null, /*async=*/true).then(function(oController) {
// Do something with oController
});
Be aware that both of these examples load the controller asynchonously, as synchronous XHR is being globally deprecated outside of Workers, and thus the framework recommends you to use async only. In fact, the new way of loading does not even provide an option for sync loading.

Binding data into view - Is it better to pass data down from parent views to child/grandchild views or initialize/query data whenever creating views?

I am working on a Backbone/Marionette project. This project implements a way to cache data on local memory after loading them from server. Therefore data can be access anytime, anywhere within the project.
This makes me wonder what is the better way to populate data to view in my case:
const ChildView = marionette.View.extend({/*...*/});
const ParentView = marionette.View.extend({
// ...
onRender() {
// 1: pass data to child view from parent view
const childView = new ChildView({
data: this.options.data,
}));
// 2: initialize data when creating new child view
const childView = new ChildView({
data: SomeModel.new({/* some properties */}),
}));
},
// ...
});
new ParentView({
data: SomeModel.new({/* some properties */}),
}).render();
Both methods work correctly. However, the project view structure is pretty deep and complicated so I prefer the second way because with the first one I would need to go up and down a lot to check what data is and where it comes from.
Do you think if there are any possible problems with this method?
I prefer the 1st way, passing data from parent to child, but it depends on what your views are doing.
For me, a big advantage of sharing a data object is that updating it within one view updates it in all other views (this will work if you pass an existing backbone Model, or any object as data). This can save a lot of work... when a user updates their background color (for example), you can update it once in your BackgroundColorChoose view, and know that it is already updated everywhere else that data is in use.
In a sense, it doesn't matter where the data came from, only what it represents (because it can be accessed/modified from within any of your views).
I can imagine scenarios where this approach is not good, but I've found it makes a good baseline to start from (and avoids the need to trust browser-caching)

Is it possible to change the model of a Backbone.Collection at runtime

Is there a clean way to change the model of a Backbone collection at runtime? In other words, I have a collection called BaseCollection where by default its model is called BaseModel. The model acts as a base class for other models. Say AModel, BModel, etc.
Now during runtime the collection, based on specific params, needs to understand if it have to call the parse method (with a specific override) of the BaseModel or one of the parse methods used in models that extend from BaseModel.
Normally, this could achieved simply extending the collection each time I instantiate it. So, for example, by default is the defined as follow.
var BaseCollection = Backbone.Collection.extend({
model : BaseModel,
// other stuff here
});
Now if I want to have a collection where AModel has to be the model
BaseCollection.extend( { model: AModel } );
Here the complicated stuff. What if the collection does not contain model of the same type. In other words, what if the BaseCollection contains AModels, BModels, etc? Note that I need to call the parse method for each model, since they differ a little bit.
The magic of creating a collection of different models is by implementing a model function.
here is the examples from http://backbonejs.org/#Collection-model
var Library = Backbone.Collection.extend({
model: function(attrs, options) {
if (condition) {
return new PublicDocument(attrs, options);
} else {
return new PrivateDocument(attrs, options);
}
}
});
in your case you should use the attributes to decide which model you want to create

Useful nodejs library for a Rails JSON API

I'm making a Titanium Mobile app.
It's relation with Rails JSON API.
I must make some model objects for Rails model objects. It's too annoying. (paging etc.)
I want to know javascript library that mapping javascript model class to Rails model class. (like a model in backbone.js)
I searched npm registory, but I can't find it.
If you're not set on Backbone, you could look at Knockout.js with the mapping plugin. While you still have to create classes for each model, you don't need to fully populate them. A pattern I've been using a lot lately for this:
function SubModel(data, parent){
var self = this;
ko.mapping.fromJS(data,{},this);
//Various computed items and functions to work with this model
}
function Model(data, parent){
var self = this;
ko.mapping.fromJS(data,{
subModel:{
create: function(options){
return new SubModel(options.data, self);
}
}
}, this);
//Various computed items and functions to work with this model
}
You then take the JSON you get from the service, do a new Model() and pass it the data, and Knockout will create all the various properties on that class from the JS. Any nested objects can be handled in the same manner as the SubModel mapping, down to an arbitrary depth.
In addtion, the mapping plugin also includes a toJS function, that will allow you to re-serialize a model that has been created from fromJS back to JSON.

Implementing Backbone.Subset.js in Backbone.js to filter Models from a parent Collection

In this stackoverflow post i read about filtering backbone collections and using subsets.
One answer (by sled) recommends using backbone.subset.js (usage example).
I could not find any further resources on backbone.subset.js and I failed implementing it into my project.
It seems like backbone.subset.js is the perfect solution for what i'm trying to achieve.
(Having one "parent" collection that holds all models at all times, and depending on user input filtering the relevant models from the parent collection into a backbone.subset collection.)
My "parent" collection, holding all tasks:
var TasksAll = Backbone.Collection.extend({
url: '/tasks', // the REST url to retrieve collection data
model: Task // the models of which the collection consists of
});
var allTasks = new TasksAll();
Now i want to create a subset collection for e.g. tasks where task.status = 0:
var TasksTrash = new Backbone.Subset({
superset: allTasks,
filter: function(Task) {
return Task.isTrash();
}
});
var trashTasks = new TasksTrash();
Whereas inside the Task model, the method "isTrash" returns true if:
this.get('status') == 0
a) Are there any more resources on backbone.subset.js?
b) How do I implement above scenario?
c) Can I pass 'superset' and 'filter' options as params to the Backbone.Subset init function?
d) I looked into the backbone.subset.js code, when I 'reset' my parent Collection my subset Collections should be updated straight away, right?
PS: I'm fairly new to Backbone. Thanks for your help.
Looking at the source for backbone-subset, it looks as though there is a pre-initialization hook which you could utilize in order to make the 'sieve' or filter available as an option or argument:
https://github.com/masylum/Backbone.Subset/blob/master/backbone.subset.js#L50
As for providing parent as an argument, there is an outstanding patch to add that exact functionality:
https://github.com/masylum/Backbone.Subset/pull/5
With it, you can pass in parent as an option, if it is not an option the library will fall back to looking for it on the object Prototype

Categories

Resources