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

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();
}
]);
})

Related

Applying RequireJS to a modular one page application

I actually have two questions concerning requirejs and singleton objects. I want to form a singleton object playing the role of my application core and pass it to modules as a parameter. How should this be done?
The other issue I have is related to a private object inside the application core. It's suppose to act as a container for modules but for some reason when I try to start the application, this container seems to have those modules but it can't be looped through. Any ideas why this is happening?
Here's an example code of the situation:
// applicationConfig.js
require.config({
baseUrl: 'js',
paths: {
jquery: 'jquery-3.1.1.min',
core: 'utils/applicationCore',
domReady: '../lib/domReady'
}
});
require(['modules']);
// modules.js
define(['core', 'domReady'], function(Core, domReady) {
require([
'modules/module1'
]);
domReady(function() {
var modules = Core.getModules();
var name = '';
for (name in modules) {
modules[name].creator(); // Start a module...
}
});
});
// applicationCore.js
define(function() {
return (function() {
var _modules = {};
return {
add: function(name, creator) {
_modules[name] = {
creator: creator
};
},
getModules: function() {
return _modules;
}
}
}());
});
// module1.js
define(['core', 'jquery'], function(Core, $) {
Core.add('module1', function() {
// Module constructor function.
});
});

How can i attach a listener in a base object to the top/extending object

The goal : i want to attach a listener in a base class to the top-most instance of inheritance.
The problem : the listener is attaching to the base class; thus, with every new call, an additional listener is attached.
Details : as the code snippets below show, i'm using require and backbone to create my objects - one object per file. PrimaryObj extends midObj, which extends baseObj, which extends Backbone.Model.
In the view (template) are a field and a button which, when clicked, calls loadThing. The user can fill in the field with new values, then click on the button each time to load new data.
However, every time a new object is built, the attributes are correctly assigned, but it's like i get a reference to the baseObj (which already has a listener attached), instead of a new clean copy/clone (which would have no listeners attached ... yet).
I thought that the reference to this in baseObj would refer to the primary/extending object (primaryObj), not baseObj itself (which is where it seems like it's being attached).
How can i attach a listener in the base object (baseObj) to JUST the top object (primaryObj)?
Thanks!
main.js ---------------
require([ 'backbone', 'routers/router' ], function (Backbone, Router) {
window.DISPATCHER = _.clone(Backbone.Events);
var router = new Router();
Backbone.history.start();
});
baseObj.js ---------------
define([ 'backbone', 'underscore' ], function (Backbone, _) {
return Backbone.Model.extend({
initialize : function (p_thing) {
this.listenTo(window.DISPATCHER, "message", function (p_data) { /* some cool functionality */ });
}
});
});
midObj.js ---------------
define([ 'models/baseObj' ], function (BaseOBJ) {
return BaseOBJ.extend({
initialize : function () {
BaseOBJ.prototype.initialize.apply(this, arguments);
}
});
});
primaryObj.js ---------------
define([ 'models/midObj' ], function (MidOBJ) {
return MidOBJ.extend({
initialize : function (p_id) {
this.set({'ref' : p_id});
MidOBJ.prototype.initialize.apply(this, arguments);
}
});
});
myView.js ---------------
define([ 'jquery', 'underscore', 'backbone', 'primaryObj' ], function($, _, Backbone, MPrimary) {
return Backbone.View.extend({
events : { 'click .bLoad' : 'loadThing', },
initialize : function (p_options) {
this.listenTo(Backbone, 'obj:loaded', function () { this.render("device"); });
this.model = {};
},
loadThing : function (p_id) { this.model = new MDevice(p_id); },
render : function (p_target) { /* ... */ },
template : _.template(TModelTest)
});
});
In the end it was discovered that the problem, as posted, was not really the problem. The listener was being handled correctly but was never getting cleaned up; thus the 'old'/original object was getting garbage collected, but it's listener was (correctly) not.
As stated in the problem, this.listenTo(Backbone, ...) created a listener related to the object on the Backbone object, not the created object; the solution, then, was to explicitly remove the listener on the backbone object.

Cross referencing of 2 models

I have 2 models which are cross referencing each other. This could look like this:
MainModel:
define(
[ 'durandal/app', 'durandal/plugins/router', 'models/Shell', 'models/EditModel' ],
function (app, router, shell, editModel) {
//...
return {
//...
// This function should be accessible by the EditModel
update: function() {
//...
},
showEditView: function() {
// Initialise the EditModel with some data and show the according view afterwards
editModel.init('set some important stuff here...');
router.navigateTo('#/EditView');
}
//...
};
}
);
EditModel:
define(
[ 'durandal/app', 'durandal/plugins/router', 'models/Shell', 'models/MainModel' ],
function (app, router, shell, mainModel) {
//...
return {
//...
// This function should be accessible by the MainModel
init: function() {
//...
},
showMainView: function() {
// Update the the MainModel with some data and show the according view afterwards
mainModel.update('set new data here...');
router.navigateTo('#/MainView');
}
//...
};
}
);
Unfortunately this is not working. If I load my page on the MainView and call showEditView, the variable editView is known and everything works fine but then the variable mainModel in the EditModel is undefined and therefore the call mainModel.update(...) fails.
Same thing happens if I load my page on EditView but in the "opposite direction" (var mainModel in the EditModel is known, but editModel in the MainModel is undefined).
Is this a known issue and if so: How can i circumvent it?
I also posted this question in Durandals Google Group
Thanks
Check requierejs documentation for circular dependencies http://requirejs.org/docs/api.html#circular.
Circular dependencies are rare, and usually a sign that you might want
to rethink the design. However, sometimes they are needed, and in that
case, use require() as specified above.
For main.js add require as dependency and then explicitly require models/EditModel should do the trick. Either replicate that for the other modules or rethink the design ;-).
define(
[ 'require', 'durandal/app', 'durandal/plugins/router', 'models/Shell', 'models/EditModel' ],
function (require, app, router, shell, editModel) {
//...
return {
//...
// This function should be accessible by the EditModel
update: function() {
//...
},
showEditView: function() {
// Initialise the EditModel with some data and show the according view afterwards
require('models/EditModel').init('set some important stuff here...');
router.navigateTo('#/EditView');
}
//...
};
}
);

Making Backbone.js modular with Require.js

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).

Ember.application.create arguments

I am exploring one of Ember.js demo application and I find lot of arguments being passed to Ember.Application.create() in addition to usual VERSION and rootElement. The demo uses require.js which I understood is for AMD.
Does Ember.js does not take care by itself in its v1.0 to load javascripts based on need ? If it does so, I don't fully understand why should require.js be used with it..
Second, if require.js has a use case, what is the use of passing as many arguments like controller names and view names to Ember.Application.create() to bootstrap application.
// Define libraries
require.config({
paths:{
jquery:'lib/jquery-1.8.0.min',
handlebars:'lib/handlebars',
ember:'lib/ember_1.0pre',
ember_data:'lib/ember-data5',
text:'lib/require/text',
md5:'lib/md5',
//domready:'lib/require/domReady',
spin:'lib/spin'
},
shim:{
'ember':{
deps:[ 'jquery', 'handlebars'],
exports:'Ember'
},
'ember_data':{
deps:[ 'ember'],
exports:'DS'
}
},
waitSeconds:15,
urlArgs:"bust=" + (new Date()).getTime() //cancel caching for network requests,for development.
});
// Define application
define('application', [
'routes/app_router',
'controllers/application_controller',
'controllers/contacts_controller',
'controllers/contact_controller',
'controllers/edit_contact_controller',
'controllers/login_controller',
'views/application_view',
'views/contact_in_list_view',
'views/contacts_view',
'views/contact_view',
'views/edit_contact_view',
'views/login_view',
'models/contact',
'jquery',
'handlebars',
'ember',
'ember_data',
// 'domready',
'spin'
], function (Router,
ApplicationController,
ContactsController,
ContactController,
EditContactController,
LoginController,
ApplicationView,
Contact_In_List_View,
ContactsView,
ContactView,
EditContactView,
LoginView,
Contact )
{
return Ember.Application.create({
VERSION: '1.0.0',
rootElement:'#main',
// Load router
Router:Router,
//Load Controllers
ApplicationController:ApplicationController,
ContactsController:ContactsController,
ContactController:ContactController,
EditContactController:EditContactController,
LoginController:LoginController,
//Load associated Views
ApplicationView:ApplicationView,
Contact_In_List_View:Contact_In_List_View,
ContactsView:ContactsView,
ContactView:ContactView,
EditContactView:EditContactView,
LoginView:LoginView,
//Load Contact Model
Contact:Contact,
//Persistence Layer,using default RESTAdapter in ember-data.js.
store:DS.Store.create({
revision:5,
adapter:DS.RESTAdapter.create({
bulkCommit:false,
serializer:DS.Serializer.create({
primaryKey:function (type) {
return type.pk;
}
}),
mappings:{
contacts:Contact
},
namespace:'api' //you should change the first segment according to the application's folder path on the server.
})
}),
ready:function () {
}
});
}
);
Ex - application_controller.js
define('controllers/application_controller',
['ember' ],
function () {
return Ember.Controller.extend({
loggedin:false
});
}
);

Categories

Resources