Backbone.js + Require.js and ViewsFactory - javascript

Let's assume that we have testing code like this:
var App = (function () {
var api = {
Router: null,
init: function () {
this.content = $("#content");
Backbone.history.start();
return this;
}
};
var ViewsFactory = {
view1: function () {
var model1 = new model1();
return new api.Views.View1({
model: model1
});
},
view2: function () {
var model2 = new model2();
return new api.Views.View2({
model: model2
});
},
view3: function () {
var model3 = new model3();
return new api.Views.View3({
model: model3
});
},
};
var Router = Backbone.Router.extend({
routes: {
"": "view1",
"2": "view2",
"3": "view3",
},
view1: function () {
var view1 = ViewsFactory.view1();
$(".content").html(view1.render().el);
},
view2: function () {
var view2 = ViewsFactory.view2();
$(".content").html(view2.render().el);
},
view3: function () {
var view3 = ViewsFactory.view3();
$(".content").html(view3.render().el);
},
});
api.Router = new Router();
return api;
})();
And I want to use Require.js. Please don't focus on names, but on the idea.
If I understand it correctly, I have to include in require method every view (View1, View2, View3) and every model (Model1, Model2, Model3). But what is the purpose of using Require.js in such case instead of traditional <script> tags?
Using ViewsFactory is a good practice in backbone projects?

WHy not a view factory. In your case I'm not sure it's really useful though.
requirejs will help to build reusable modules. http://requirejs.org/docs/why.html

The best option in router is using variables like this:
var $ = require('jquery'),
Backbone = require('backbone');

Related

JS works with .include but fails with .extend

I made this JS to add a functionality on a form (backend) that computes a field when the event click is triggered. So far the code recomputes when I use ".include" but the whole JS in all views fail since I'm using ".include". When I try to use extend my code does nothing. Looks like Odoo doesn't add the extended code to the JS engine so my question is, what am I doing wrong here? Is there something else I need to add so my code works as extended?
odoo.define('med_care.TestRenderer', function (require) {
"use strict";
var viewRegistry = require('web.view_registry');
var FormRenderer = require('web.FormRenderer');
var FormView = require('web.FormView');
var TestFormRenderer = FormRenderer.extend({
events: _.extend({}, FormRenderer.prototype.events, {
'click .sign_selector': '_onSignSelectorClicked',
}),
init: function (parent, state, params) {
this._super.apply(this, arguments);
this.fields = state.fields;
this._onSignSelectorClicked = _.debounce(this._onSignSelectorClicked, 300, true);
},
confirmChange: function (state, id, fields, e) {
var self = this;
if (state.model == 'med.test') {
return this._super.apply(this, arguments).then(function () {
self.canBeSaved(self.state.id);
});
}
},
_onSignSelectorClicked: function (event) {
this.state.data.telephone = '333';
if (this.state.model == 'med.test') {
var info_test = {
dataPointID: this.state.id,
changes: {telephone: '333'},
viewType: "form",
notifyChange: true
};
var odoo_event = this.trigger_up('field_changed', info_test);
this.confirmChange(this.state, this.state.id, "telephone",
odoo_event)
}
},
});
var TestFormView = FormView.extend({
config: _.extend({}, FormView.prototype.config, {
Renderer: TestFormRenderer,
}),
});
viewRegistry.add('test_form', TestFormView);
return TestFormView;
});

Are self instantiating views good practice or should I refactor?

I use a Backbone View to start my application using the code below. All it really does is encapsulate other objects I want to instantiate or load.
Is this O.K. or should I re-factor?
// App
//
//
//
var BVApp = Backbone.View.extend({
Name: 'BVApp',
el: window,
initialize: function () {
this.initIndependentConstructors();
this.initBBViews();
this.initComposite();
this.initBVArc();
},
initIndependentConstructors: function (){
new ImageLoader();
new SiteMorpher();
new AccountUpdater();
new SignOut();
},
initBBViews: function () {
new BVAccountExist();
new BVAccountCreator();
new BVAccountButton();
new BVAccountCode();
new BVFaveCreator();
},
initComposite: function () {
var token = ClientStorage.getToken();
this.CV = new BVComposite();
this.CV.renderCommon();
if (token) this.CV.render(token);
},
initBVArc: function () {
this.BVArcInstance = new BVArc({el: window, collection: new BCArc([], {data: {model: "ArcReader"}})});
}
});
var App = new BVApp();
}());

Backbone.js and router.navigate

I'm trying to improve the navigation of my little backbone application. Right now I just have some simple navigation using html links that use to #path/to/page in the href element.
What I'm running into is when I click on one of these and then click the back button, the page doesn't refresh properly, and the HTML content doesn't change. So I'm trying to incorporate the navigate functionality into my code.
The issue I'm running into is that I can't find an example that matches the code layout I'm currently using, and I don't understand how backbone works enough to adapt the things I find into something useful.
Here's what I've got:
app.js - called from the index.html file
require.config({
baseUrl: 'js/lib',
paths: {
app: '../app',
tpl: '../tpl',
bootstrap: 'bootstrap/js/',
},
shim: {
'backbone': {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
'underscore': {
exports: '_'
}
}
});
require([
'jquery',
'backbone',
'app/router',
], function ($, Backbone, Router) {
var router = new Router();
Backbone.history.start();
});
app/router.js - instantiated in app.js
define(function (require) {
"use strict";
var $ = require('jquery'),
Backbone = require('backbone'),
WindowView = require('app/views/Window'),
breadcrumbs = {"Home": ""},
$body = "",
$content = "",
windowView = "";
return Backbone.Router.extend({
initialize: function () {
require([], function () {
$body = $('body');
windowView = new WindowView({el: $body}).render();
$content = $("#content", windowView.el);
});
},
routes: {
'' : 'home',
'profile/login(/)' : 'candidateProfileLogin',
'profile/manage(/)' : 'candidateProfileLogin',
'profile/manage/:id(/)' : 'candidateProfileHome',
'profile/manage/:id/questionnaire/:page(/)' : 'candidateProfileQuestionnaire',
'profile/manage/:id/:section(/)' : 'candidateProfileSection',
},
home: function (){
},
candidateProfileLogin: function () {
require(['app/views/CandidateLogin'], function (CandidateLoginView) {
console.log(Backbone.history.fragment);
var view = new CandidateLoginView({el: $content});
view.render();
});
},
candidateProfileHome: function (id) {
require(["app/views/Candidate", "app/models/candidate"], function (CandidateView, models) {
var candidate = new models.Candidate({id: id});
candidate.fetch({
success: function (data) {
var view = new CandidateView({model: data, el: $content});
view.render();
},
error: function (data) {
var view = new CandidateView({model: data, el: $content});
view.render();
}
});
});
},
candidateProfileSection: function (id, section) {
require(["app/views/Candidate", "app/models/candidate"], function (CandidateView, models) {
var candidate = new models.Candidate({id: id});
candidate.fetch({
success: function (data) {
var view = new CandidateView({model: data, el: $content});
view.render(section);
},
error: function (data) {
//Output the data to the console. Let the template take care of the error pages
console.log(data);
var view = new CandidateView({model: data, el: $content});
view.render();
}
});
});
},
candidateProfileQuestionnaire: function (id, page) {
require(["app/views/Candidate", "app/models/candidate"], function (CandidateView, models) {
var candidate = new models.Candidate({id: id});
candidate.fetch({
success: function (data) {
var view = new CandidateView({model: data, el: $content});
view.render(page);
},
error: function (data) {
//Output the data to the console. Let the template take care of the error pages
console.log(data);
var view = new CandidateView({model: data, el: $content});
view.render();
}
});
});
},
});
});
app/views/Candidate.js - My view I'm trying to process the clicks
define(function (require) {
"use strict";
var $ = require('jquery'),
_ = require('underscore'),
Backbone = require('backbone'),
tpl = require('text!tpl/Candidate.html'),
template = _.template(tpl),
CandidateErrorView = require('app/views/CandidateError'),
errtpl = require('text!tpl/CandidateError.html'),
errTemplate = _.template(errtpl);
return Backbone.View.extend({
events: {
'submit #voters-guide-personalInfo': 'savePersonalInfo',
'submit #voters-guide-essay' : 'saveEssay',
'submit #voters-guide-survey' : 'saveSurvey',
'submit #voters-guide-endorsements': 'saveEndorsements',
'submit #voters-guide-photo' : 'savePhoto',
'click #table-of-contents a' : 'navTOC',
},
savePersonalInfo: function (event) {
console.log(event);
},
saveEssay: function (event) {
console.log(event);
},
saveSurvey: function (event) {
console.log(event);
},
saveEndorsements: function (event) {
console.log(event);
},
savePhoto: function(event) {
console.log(event);
},
navTOC: function (event) {
console.log(event.target);
var id = $(event.target).data('candidate-id');
var path = $(event.target).data('path');
//router.navigate("profile/manage/" + id + "/" + path, {trigger: true});
},
render: function (page) {
//Check to see if we have any errors
if (!this.model.get('error')) {
var dataToSend = {candidate: this.model.attributes};
switch(page) {
case 'personalInfo':
template = _.template(require('text!tpl/Candidate-personalInfo.html'));
break;
case 'essay':
template = _.template(require('text!tpl/Candidate-essay.html'));
break;
case 'survey':
template = _.template(require('text!tpl/Candidate-survey.html'));
break;
case 'endorsements':
template = _.template(require('text!tpl/Candidate-endorsements.html'));
break;
case 'photo':
template = _.template(require('text!tpl/Candidate-photo.html'));
break;
default:
break;
}
this.$el.html(template(dataToSend));
return this;
} else {
this.$el.html(errTemplate({candidate: this.model.attributes}));
return this;
}
}
});
});
Now, in an attempt to stop the 'the page content doesn't reload when I hit the back button' issue, I've been looking into the navigate function that backbone has available (this: router.navigate(fragment, [options]);). There are lots of examples of how this is used, but none of them seem to have anything similar to the file setup that I'm using, so I'm not exactly sure how best to access this functionality from my view. If I include the router file in the view and instantiate a new version of it, the page breaks b/c it tries to run the initialize function again.
I'm just really at a loss on how this is supposed to work.
Can someone point me in the right direction?
Thanks!
--Lisa
P.S. If someone has any better ideas, I am all ears!
You should have access to the Backbone object, which within it, has access to navigate around using the history.navigate function. If you call that passing in trigger: true you'll invoke the route. For instance:
Backbone.history.navigate("profile/manage", { trigger: true });

BackboneJS - Router Functions - Calling Views?

I'm having an issue calling my views from with the router cfunctions besides within initialize.
this is my router code:
var ApplicationRouter = Backbone.Router.extend({
routes: {
"": "home",
//"*actions": "home",
"photo-gallery": "gallery",
"sound-lounge": "sound",
"contact": "contact"
},
initialize: function() {
this.homeView = new window.app.HomeView();
this.homeView.render();
/*
var soundView = new window.app.SoundView();
soundView.render();
var contactView = new window.app.ContactView();
contactView.render();
var galleryCollection = new window.app.GalleryCollection();
var gallery_items = galleryCollection.fetch();
gallery_items.done(function(){
var gallery_item = new GalleryView({ collection: galleryCollection });
});
*/
},
home: function() {
console.log('home');
},
sound: function() {
//var soundView = new window.app.SoundView();
//soundView.render();
console.log('sound');
},
contact: function() {
//var contactView = new window.app.ContactView();
// contactView.render();
console.log('contact');
},
gallery: function() {
console.log('gallery');
}
});
You can see able I have:
var soundView = new window.app.SoundView();
soundView.render();
commented out within the initalize function, this will work but as soon as I put it within the 'sound' function I get this error: Uncaught TypeError: undefined is not a function
It's to do with this part: new window.app.SoundView();
I have it called window.app.SoundView in my code, how do I go about getting this to work (it happens incorrectly for all my sections)
// ADDED soundView Code
// SOUNDVIEW
window.app.SoundView = Backbone.View.extend({
el: $("html"),
events: {
"click #sound-lounge": "render_sound"
},
initialize: function(){
this.render_sound();
},
render: function(model){
return this;
},
render_sound: function(){
this.model=new window.app.Home({id: 2});
var $main=this.$el.find('#content-area');
this.model.fetch().complete(function(data){
$main.html(data["responseJSON"].description);
});
}
});
Thanks
My problem ended up being as simple as removing window.app. from the soundView variable name.
e.g.
window.app.SoundView = Backbone.View.extend({ == SoundView = Backbone.View.extend({
AND
var soundView = new window.app.SoundView(); == var soundView = new SoundView();

Backbone Router with parameter not working

I'm trying to use backbone routes with parameters and for some reason, I just can't seem to make the code below to work:
var App = new Backbone.Marionette.Application();
App.Router = Backbone.Router.extend({
routes: {
"export": "export",
"show": "show/:id", // This just won't work
"providers": "providers"
},
export: function() {
var exportView = new App.ExportView();
exportView.render();
$("#main").html(exportView.el);
},
show: function(id) {
console.log('from here'); // This is not even firing
var show = this.collection.get(id);
showView.render();
$("#main").html(showView.el);
},
providers: function() {
var contentProvidersView = new App.ProvidersView();
providersView.render();
$("#main").html(providersView.el);
}
});
App.addInitializer(function() {
var router = new App.Router();
});
Nothing happens when I try to access this: #show/2 (Where 2 is the show id)
Many thanks.
It's the other way around :
routes: {
"show/:id": "show",
}

Categories

Resources