Making Backbone.js modular with Require.js - javascript

I am attempting to make my Backbone.js components, models and views modular through Backbone.js. However whenever I attempt to require() one it returns:
function (){return i.apply(this,arguments)}
instead of the Backbone wizardry I require.
I have set up my Require.js like so:
// Configure require.js
require.config(
{
paths: {
"data": "config"
, "jquery": "libs/jquery.min"
, "underscore": "libs/underscore-min"
, "backbone": "libs/backbone-min"
, "events": "collections/events"
, "eventModel": "models/eventModel"
, "eventView": "views/eventView"
}
, shim: {
underscore: {
exports: '_'
}
, jquery: {
exports: '$'
}
, backbone: {
deps: ["underscore"]
, exports: "Backbone"
}
}
}
);
// Initiate app
require(
[
"data"
, "jquery"
, "underscore"
, "backbone"
, "events"
, "eventModel"
, "eventView"
], function(data, $, _, Backbone, Events, EventModel, EventView) {
console.log(Events);
_.each(["data/general.xml"], function(URI) {
var general = new Events({url: URI});
});
}
);
And here is my collections/events.js:
define(
[
"backbone"
, "eventModel"
]
, function(Backbone, EventModel) {
"use strict";
var Events = Backbone.Collection.extend({
model: EventModel
, parse: function(data) {
var parsed = [];
$(data).find('Event').each(function(index) {
parsed.push({
title: $(this).find('title').text(),
date: $(this).find('date').text(),
content: $(this).find('content').text()
});
});
return parsed;
}
, fetch: function(options) {
options = options || {};
options.dataType = "xml";
Backbone.Collection.prototype.fetch.call(this, options);
}
});
return Events;
}
);
I would expect that to return the Events collection, however it clearly isn't. Can anyone see what I am doing wrong?

Everything seems fine. What you see:
function (){return i.apply(this,arguments)}
is the constructor of your class. Pay no attention to it. Instead, try to log new myClass.
Edit:
You don't see any of the methods because they're stored in the prototype of your class. The i function that is called is the "real" constructor (named i because it's been minified).

Related

Is there a way to access dojo functionality inherited from base modules?

Assume two template based widgets that inherits properties from a single base module, what if the template based widgets need to use functionality from a dojo module like for example "dojo/on" Is there a way to give each widget the dojo/on functionality without requiring it in each widget? Because once you go beyond a couple widgets, then having to make sure you require that module in each one gets tiresome. So can we require it only once in the base module from which they inherit?
Giving you some easy button example below.
widget_base.js
define([
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/on",
"dijit/form/Button"
], function(declare, lang, on, Button){
return declare(/* path to widget_base */, null, {
constructor: function() {
},
createButton: function() {
if (!this.button) this.button = new Button();
},
hookFunc: function() {
func = function() {/* activity */}
if (!this.button) this.createButton();
on(this.button, /* event */, lang.hitch(this, func));
}
});
})
widgetA.js
define([
"dojo/_base/declare",
/* path to widget_base */
], function(declare, widget_base){
return declare(/* path to widgetA */, widget_base, {
constructor: function() {
this.inherited(arguments);
},
});
})
Thus, in widgetA, you do not need to require dojo/on anymore.
Below is my test case.
test.js
define([
"doh/runner",
/* path to widget_base */
/* path to widgetA */
], function(doh, widget_base, widgetA) {
doh.register("test", [{
runTest: function() {
wb = new widget_base();
wb.createButton();
},{
runTest: function() {
wba = new widgetA();
wba.createButton();
wba.hookFunc();
}
]);
})

Override method of an existing instance

I'm trying to extend an existing Durandal router plugin instance already created with the help of RequireJS.
The method map() should be overriden to add extra mapping parameters.
How should I access the original method from the modified one?
index.js
define([ 'durandal/app', 'app/childRouter'], function(
app, childRouter) {
childRouter.map([ {
route : 'details/:id',
moduleId : 'details/index',
}, {
route : 'details/tabs/base',
moduleId : 'details/tabs/base',
} ]);
childRouter.buildNavigationModel();
return {
router : childRouter
};
});
childRouter.js
define([ 'durandal/app', 'plugins/router'], function(
app, router) {
var childRouter = router.createChildRouter();
childRouter._map = childRouter.map;
childRouter.map = function(data) {
data.unshift({
route : [ '', 'grid' ],
moduleId : 'grid/index',
});
childRouter._map(data);//CALLS THE OVERRIDEN METHOD AGAIN INSTEAD OF ORIGINAL
};
return childRouter;
});
If you want to still call the original "map" function, you'll need to store it before you overwrite it. It's a bit "hacky" to replace functions in this way, but if you REALLY had to do it, this will work:
var childRouter = router.createChildRouter();
childRouter.originalMap = childRouter.map; // Save original
childRouter.map = function(data) {
data.unshift({
route : [ '', 'grid' ],
moduleId : 'grid/index',
});
childRouter.originalMap(data); // Call original
};

BackboneJS Search Filter System

I'm using Controller to Fetch URL. I need a way to put Parameter in this POST. These Parameters are selected by users on View & Not Stored yet(I dont know how to store)
Currently I managed to
1) Display & Route The View with search result coming from API
2) Display and refresh the page when someone selects a Filter Option
Problem
1) I got no idea how to record what the users clicked
2) How do i "re-post" so i can get the new set of results
3) I read and say people saying POST Fetch should be done in Model , Conllection is for Store Multiple Models which i don't know in this scenario?
Collections
Jobs.js
define([
'jquery',
'underscore',
'backbone',
'models/filter'
], function($, _, Backbone,JobListFilterModel){
var Jobs = Backbone.Collection.extend({
url: function () {
return 'http://punchgag.com/api/jobs?page='+this.page+''
},
page: 1,
model: JobListFilterModel
});
return Jobs;
});
Collections Filter.JS
define([
'jquery',
'underscore',
'backbone',
'models/filter'
], function($, _, Backbone,JobListFilterModel){
console.log("Loaded");
var Jobs = Backbone.Collection.extend({
url: function () {
return 'http://punchgag.com/api/jobs?page='+this.page+''
},
page: 1,
model: JobListFilterModel
});
// var donuts = new JobListFilterModel;
// console.log(donuts.get("E"));
return Jobs;
});
Models
Filter.js
define([
'underscore',
'backbone'
], function(_, Backbone){
var JobFilterModel = Backbone.Model.extend({
defaults: {
T: '1', //Task / Event-based
PT: '1', //Part-time
C: '1', //Contract
I: '1' //Internship
}
});
// Return the model for the module
return JobFilterModel;
});
Models
Job.js
define([
'underscore',
'backbone'
], function(_, Backbone){
var JobModel = Backbone.Model.extend({
defaults: {
name: "Harry Potter"
}
});
// Return the model for the module
return JobModel;
});
Router.js
define([
'jquery',
'underscore',
'backbone',
'views/jobs/list',
'views/jobs/filter'
], function($, _, Backbone, JobListView, JobListFilterView){
var AppRouter = Backbone.Router.extend({
routes: {
// Define some URL routes
'seeker/jobs': 'showJobs',
'*actions': 'defaultAction'
},
initialize: function(attr)
{
Backbone.history.start({pushState: true, root: "/"})
},
showJobs: function()
{
var view = new JobListView();
view.$el.appendTo('#bbJobList');
view.render();
console.log(view);
var jobListFilterView = new JobListFilterView();
jobListFilterView.render()
},
defaultAction: function(actions)
{
console.info('defaultAction Route');
console.log('No route:', actions);
}
});
var initialize = function(){
console.log('Router Initialized');// <- To e sure yout initialize method is called
var app_router = new AppRouter();
};
return {
initialize: initialize
};
})
;
Capturing what a user has done should be completed within a view. For example:
filterView.js
var View = Backbone.View.extend({
initialize: function() {
_.extend(this, Backbone.Events);
},
render: function() {
// Your normal render routine
return this;
},
events: {
"submit form": "submit"
},
submit: function() {
var query = $("input[type=search]", this.el).val();
this.trigger("submit", query);
}
});
return View;
...whatever implements filterView and jobCollection...
// Implement our collections, views, etc
var jobCollection = new JobCollection();
var jobsView = new JobsView();
var filterView = new FilterView().render();
// Add listeners on our view
filterView.on("submit", updateJobs);
// Implement the functions for our view (this can be done in a number of ways)
function updateJobs(query) {
jobCollection.fetch({
data: {
query: query
}
}).done(function(response) {
// Technically you could just provide "jobsView.render" to the done() method, but I wanted to be a little more verbose here regarding parameters
jobsView.render(response);
});
}
Your view is only aware of itself (input structure, etc). The thing that implements the view and collection is the broker between these two modules.
You specify parameters within the fetch statement by providing an object which implements a data parameter. In this case, we're going to pass the query using the query key. fetch returns a promise, so once that's done, we return that response to the jobsView and pass it to the render function, which should be set up to accept the collection.
updateJobs is unaware of the view implementation, all it knows is it expects a query to be included.
This code is not meant to be directly implemented or copy/pasted, but it's meant to provide an outline for how you might accomplish what you're looking to do.

backbone require.js access to models

Im studying require and modular programming with backbone.
My question specifically is how can I access the models I have created in the View module as shown below from the main page, (example from the console), as is allways telling me undefined.
I understand that as its encapsulated in the view module, but is being hard to me to understand where I should create the instances of the model and collection as if I do it in init.js I get them to be undefined in the view module when i define collections or model.
If I instance them from model or collections modules I get a bunch of undefined errors
I have this init.js;
requirejs.config({
enforceDefine: true,
baseUrl: 'js',
urlArgs: "bust=" + (new Date()).getTime(),
shim: {
underscore: {
exports: '_'
},
backbone: {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
}
},
paths: {
jquery: 'lib/jquery-1.10.2.min',
backbone: 'lib/backbone.min',
underscore: 'lib/underscore.min',
text: 'lib/require/text',
Plato: 'app/models/plato',
Carta: 'app/collections/carta',
MainView: 'app/views/mainView',
mainTemplate: 'app/templates/mainTemplate.html'
}
});
define(['jquery', 'underscore', 'backbone', 'MainView'], function($, _, Backbone, MainView) {
console.log(typeof $);
console.log(typeof _);
console.log(typeof Backbone);
var mainView = new MainView;
});
Then I have mainView.js as:
define(['backbone', 'text!mainTemplate', 'Plato', 'Carta'], function(Backbone, mainTemplate, Plato, Carta) {
var pizza = new Plato({precio:120, nombre:'pizza', foto:'n/a', ingredientes: 'harina, tomate, oregano', diabeticos:false}),
empanada = new Plato({precio:40, nombre:'empanada', foto:'n/a', ingredientes: 'harina, carne picada', diabeticos:false}),
lasagna = new Plato({precio:200, nombre:'lasagna', foto:'n/a', ingredientes: 'pasta, queso', diabeticos:false}),
carta = new Carta([pizza, empanada, lasagna]),
MainView = Backbone.View.extend({
tagName: 'div',
id: 'mainView',
events: {'click td': 'clickAction'},
collection: carta,
template: _.template(mainTemplate, this.collection),
initialize: function() {
this.render();
},
render: function() {
this.collection.each(function(item) {
console.log(item.toJSON() + item.get('nombre'));
this.$el.append( this.template( item.toJSON() ));
}, this);
$('#content').html(this.$el);
return this;
},
clickAction: function() {
alert(this);
}
});
return MainView;
});
I also have the model and collection modules if that helps you out to help me.
My main purpose would be to be able to access them and then put a listener or an on in the elements to be able to play with the data of those models.
Sorry If I am confused and mixing concepts with the variable scope of the modules using require.js and backbone, but I have read whatever I was able to find in the internet and Im still confused.
EDIT
Should I create and entire module just to instantiate them and then export the values as an object??
Should I create and entire module just to instantiate them and then
export the values as an object??
Yes. That's one way to accomplish what you are looking to do:
define(['backbone', 'text!mainTemplate', 'Plato', 'Carta', 'carta'],
function(Backbone, mainTemplate, Plato, Carta, carta) {
...
});
Where Carta is the collection module and carta is the object that contains the data.

TypeError: this.parts[1].reviewMoment is not a function

I am working on this bug and I keep getting the following error -
TypeError: this.parts[1].reviewMoment is not a function
I am using jQuery and backbone. Unfortunately, I'm not really familiar with JS and not sure why this line broke.
define([
"jquery",
"underscore",
], function($, _) {
reviewMoment: function(place) {
this.collection.bind("add", _.once(_.bind(this.triggerReview, this)));
this.collection.addMomentByPlace(place);
},
triggerReview: function() {
this.parts[(this.matchView ? 2 : 1)].reviewMoment();
if(this.matchView) {
this.matchView.search.close();
}
}
});
});
Why is reviewMoment not considered a function?
Thanks.
It's not a function because you're not actually creating an object literal {} in which you can use the identifier:property notation. To create valid function definitions place a return statement with an object literal around your functions:
define([
"jquery",
"underscore",
], function($, _) {
return {
reviewMoment: function(place) {
this.collection.bind("add", _.once(_.bind(this.triggerReview, this)));
this.collection.addMomentByPlace(place);
},
triggerReview: function() {
this.parts[(this.matchView ? 2 : 1)].reviewMoment();
if(this.matchView) {
this.matchView.search.close();
}
}
}
});
});

Categories

Resources