I have a model called score and a collection called scores. However, the model does not seem to be inheriting the localStorage property (or for that matter, any property) from the parent collection. Am I missing something here?
Running Backbone with RequireJS.
models/score.js
define([
'underscore',
'backbone',
'localstorage'
], function(_, Backbone, Store){
var ScoreModel = Backbone.Model.extend({
defaults: {
board_id: null,
ns_pair: null,
ew_pair: null,
ns_score: null
},
validate: function(attrs, options){
if( isNaN(attrs.board_id) || attrs.board_id < 1 ){
return 'Invalid Board ID!';
}
},
localStorage: new Store("ScoreCollection")
});
return ScoreModel;
});
collections/scores.js
define([
'underscore',
'backbone',
'models/score',
'localstorage'
], function(_, Backbone, ScoreModel, Store){
var ScoreCollection = Backbone.Collection.extend({
model: ScoreModel,
localStorage: new Store("ScoreCollection")
});
return ScoreCollection;
});
main.js
require.config({
paths: {
// Major libraries
jquery: 'libs/jquery/jquery.min',
underscore: 'libs/underscore/underscore.min',
backbone: 'libs/backbone/backbone.min',
// Require.js plugins
text: 'libs/require/text',
// Backbone.js plugins
localstorage: 'libs/backbone/localstorage',
// Just a short cut so we can put our html outside the js dir
// When you have HTML/CSS designers this aids in keeping them out of the js directory
templates: '../templates'
}
});
// Let's kick off the application
require([
'app'
], function(App){
App.initialize();
});
Backbone Models don't inherit from Backbone Collections. They're just extensions of the base Backbone.Model that you 'extend' with your own properties and methods. Collections, the same deal. You can specify that a collection's model is based on a particular model you've defined so that when collections are added to it, it uses the model constructor to create instances for each model in that collection, but there is no direct inheritance relationship there. You can define a property on a model that happens to be an instance of a collection if that suits your needs.
Related
Good day all.
I'm into a big project that uses EXTjs (i guess it's 4.0), the project is huge and have several years behind.
I'm not into Extjs so I'm trying to learn what to do and how to do it, and my new task is to create a persistent, global object, available into the whole application in which I need to store some information that are used in different parts of the project (let's say for example that the user can set a particular property of this object to "true" while doing some actions and this "true" it will be used into another viewcontroller to enable some functions, things like this).
so, I've created a new file called userJsonMainModel.js :
Ext.define('Tac3.userJsonMainModel', {
extend: 'Ext.data.Model',
constructor: function() {
var userJsonMainModel = this;
userJsonMainModel.callParent(arguments);
userJsonMainModel.data.tmp = {};
},
testProperty:{foo:"bar"},
testMethod: function (){
console.log("testFunction called");
}
});
and in Application.js :
requires: [
...
'Tac.userJsonMainModel'
],
stores: ['Countries', 'Kpis', 'Dimensions'],
autoCreateViewport: false,
init: function() {
var controller = this
Ext.tip.QuickTipManager.init();
Ext.setGlyphFontFamily('FontAwesome');
var userJsonMainModel = controller.createUserJsonMainModel();
console.log("into init: ", this.userJsonMainModel.testProperty);
...
createUserJsonMainModel: function() {
var controller = this;
controller.userJsonMainModel = Ext.create('Tac3.userJsonMainModel', {
controller: controller
});
console.log("check if the jsonmainmodel exist ",controller.userJsonMainModel.testProperty);
},
this is actually working, now the second step is to access the same object from another view (or its viewcontroller), this is what I've done into a a viewController:
Ext.define('Tac3.view.udesign.UdesignController', {
extend: 'Ext.app.ViewController',
alias: 'controller.udesign',
init: function(view) {
...
console.log("into init: ", this.userJsonMainModel.testProperty);
}
and this is actually throwing a:
Uncaught TypeError: Cannot read property 'testProperty' of undefined
I was pretty sure the objects defined into application.js would be globally accessible, but I guess I'm wrong, or doing something in a wrong way.
since I've found quite no examples on this topic (which is probably because it is not a standard way to do this), I'd like to ask what I'm doing wrong?
Just define a class and require it in your application:
Ext.define('MyApp.Globals', {
singleton: true,
foo: 100,
bar: 'baz'
});
Collection
define([
'jquery',
'underscore',
'backbone'
], function($, _, Backbone){
console.log("Loaded");
var Jobs = Backbone.Collection.extend({
url: function () {
return 'http://domain.com/api/jobs?page='+this.page+''
},
page: 1
});
return Jobs;
});
Model
define([
'underscore',
'backbone'
], function(_, Backbone){
var JobFilterModel = Backbone.Model.extend({
defaults: {
T: '1',
PT: '1',
C: '1',
I: '1'
}
});
// Return the model for the module
return JobFilterModel;
});
In one of my view , i SET the models
var jobListFilterModelUpdate = new JobListFilterModel();
jobListFilterModelUpdate.set({value:isChecked});
I'm trying to retrieve the MODEL from Collection so i can send the correct QUERY with the URL.
Question 1
How do i retrieve from Model from Collection
Question 2
Will the retrieved collection be the updated Model with the data i Set in View?
When you declare a Collection you need to specify a model property, something like :
var Jobs = Backbone.Collection.extend({
url: function () {
return 'http://punchgag.com/api/jobs?page='+this.page+''
},
page: 1,
model: JobFilterModel
});
After creating a new model you need to add it to collection (assuming you have jobsCollection created):
var jobListFilterModelUpdate = new JobListFilterModel();
jobListFilterModelUpdate.set({value:isChecked});
jobsCollection.add(jobListFilterModelUpdate);
Answer 1
You can retrieve a model from a collection based on id, collection.get(id). Here JobFilterModel doesn't seem to have any id (you can set idAttribute property of Model to create custom id property). Backbone also creates unique ids at client side but I don't know how would they be of any help to you. If you want to retrieve a model based on any of model's property you can use collection.findWhere() or collection.where().
Answer 2
Yes. It will be but it depends on how link your View to Collection.
I'm setting up a nested categories structure in Backbone with RequireJS.
In this structure, a categories collection contains category models, and a single category model can contain a categories collection.
Unfortunately this seems to cause the dreaded circular dependencies problem in RequireJS. I have read the docs on RequireJS (http://requirejs.org/docs/api.html#circular) however I am finding the explanation with 'a' and 'b' confusing.
Here is my code, which is causing the problem:
define([
"jquery",
"underscore",
"backbone",
"collections/categories"
], function( $, _, Backbone, CategoriesCollection ) {
var Category = Backbone.Model.extend({
defaults: {
title: "Untitled"
},
parse: function(data) {
this.children = new CategoriesCollection( data.children, {parse: true} );
return _.omit( data, "children" );
}
});
return Category;
});
...
define([
"jquery",
"underscore",
"backbone",
"models/category"
], function( $, _, Backbone, CategoryModel ) {
var Categories = Backbone.Collection.extend({
model: CategoryModel
});
return Categories;
});
I am wondering if anyone who has experienced this before can help steer me in the right direction.
Thanks (in advance) for your help,
You just need to use require the collection again when you need it in the model, as the Collection passing initially can be undefined:
define([
"jquery",
"underscore",
"backbone",
"collections/categories"
], function( $, _, Backbone, CategoriesCollection ) {
var Category = Backbone.Model.extend({
defaults: {
title: "Untitled"
},
parse: function(data) {
if(!CategoriesCollection){
CategoriesCollection = require("collections/categories");
}
this.children = new CategoriesCollection( data.children, {parse: true} );
return _.omit( data, "children" );
}
});
return Category;
});
In the example they import also require but it should also work without the import.
For this you should consider to use a plugin like Backbone Relational.
I'm trying to implement backbone.localstorage (https://github.com/jeromegn/Backbone.localStorage) in my application, but for some reason it's including it but not actually saving anything to localStorage, but it's also not throwing any errors either.
Here is my model code (I am using RequireJS):
define([
'backbone',
'common',
'localstorage'
],
function(Backbone, Common) {
//Define the App Namespace before anything else
var APP = Common.app_namespace || {};
APP.Models.ExampleModel = Backbone.Model.extend({
localStorage: new Backbone.LocalStorage("ExampleModel"),
//Set up default values
defaults: {
"user_name" : "awesome name",
"field 2" : "awesome field"
}
});
}
);
And here is where I'm calling it (using Marionette's regions):
var exModel = new APP.Models.ExampleModel({
"user_name" : "name!",
"field2" : "field!"
});
main_app_layout.header.show(new APP.Views.ExampleView({model: exModel}));
In terms of require, the page is loading, but I just don't think it's doing anything. Can anyone help?
I think you need to call the exModel.save() method for it to save to localStorage.
If an Ext.application has the following controllers:
Ext.Loader.setConfig({enabled:true});
Ext.application({
name: 'MyApp',
appFolder: 'app',
controllers: [
'Ctrl1',
'Ctrl2'
],
launch: function() { ... }
});
should it also include the controllers in controllers in the requires section, i.e. add
requires: [
'MyApp.controller.Ctrl1',
'MyApp.controller.Ctrl2'
],
within the above class?
The short answer is NO.
The long answer is that the controllers, models, views and stores configs all translate to requires. The bit that does the magic is in the Ext.app.Controller class:
onClassExtended: function(cls, data, hooks) {
var Controller = Ext.app.Controller,
className, namespace, onBeforeClassCreated, requires, proto, match;
className = Ext.getClassName(cls);
namespace = Ext.Loader.getPrefix(className) ||
((match = className.match(/^(.*)\.controller\./)) && match[1]);
if (namespace && namespace !== className) {
onBeforeClassCreated = hooks.onBeforeCreated;
requires = [];
hooks.onBeforeCreated = function(cls, data) {
proto = cls.prototype;
Controller.processDependencies(proto, requires, namespace, 'model', data.models);
Controller.processDependencies(proto, requires, namespace, 'view', data.views);
Controller.processDependencies(proto, requires, namespace, 'store', data.stores);
Controller.processDependencies(proto, requires, namespace, 'controller', data.controllers);
// this is the line to look at!!!
Ext.require(requires, Ext.Function.pass(onBeforeClassCreated, arguments, this));
};
}
},
Your application is just an Ext.app.Application class that inherits from Ext.app.Controller; thus the controllers config also translates to requires.
No, that is not necessary. Here is an example of working app.js I am using right now:
Ext.Loader.setConfig({enabled:true});
Ext.Loader.setPath('Ext.ux', '../extjs/examples/ux');
Ext.application({
name: 'FPPP',
autoCreateViewport: true,
controllers: [
'Main',
'List',
'Report'
]
});
There's also the Sencha MVC guide