JavaScript Inheritance Using .call() - javascript

I need a way to call many DHTMLX attach*() functions with certain defaults already set. This is just one example. If I can figure this one example out then I can apply it to all others.
DHTMLX has many functions similar to this: dhtmlXCellObject.prototype.attachToolbar(), attachTabbar(), attachRibbon(), etc... But for every single toolbar in my app there are certain settings I want to automatically apply like iconSize and iconPath.
dhtmlXCellObject.prototype.attachTheBetterToolbar = function (conf) {
// https://docs.dhtmlx.com/api__dhtmlxlayout_attachtoolbar.html
// dhtmlXToolbarObject.prototype.attachToolbar.call(this, conf); This throws: Cannot read property 'call' of undefined
this.attachToolbar.call(this, conf);
// I want these two settings below on every single toolbar in our app but
// I only want to have to set them once in here. Then throughout my
// entire application, we will only use attachTheBetterToolbar...
// layout.cells('a').attachTheBetterToolbar()
// window.attachTheBetterToolbar()
// accordian.attachTheBetterToolbar()
// tabbar.tabs('a').attachTheBetterToolbar()
// etc...
this.setIconSize(18);
this.setIconsPath(c3.iconPath);
};
The above code doesn't work (errors with: this.setIconSize is not a function) but I think you'll get the idea of what I'm trying to attempt. I'm reading all sorts of articles on JavaScript extend, apply, call, inheritance, etc... I feel like I'm close but something just isn't clicking.
I thought the ".call()" part would cause inheritance to happen like described here: https://stackoverflow.com/a/16058530/3112803 (the Variation 1 - Mixin -> Inheritance example)

This does what I need...
dhtmlXCellObject.prototype.attachTheBetterToolbar = function (conf) {
var tb = this.attachToolbar(conf);
// this.setIconset("awesome");
tb.setIconSize(18);
tb.setIconsPath(c3.iconPath);
return tb;
};

Related

One view for 2 or more pages (backbone.js)

I have two pages. One of them is dashboard with a lot of functionality. The second page is shared dashboard - the simple version of the first page.
The dashboard contains the view of the database (it can contain much other info, but the problem with this one). You can click on the filter button and modal window will be opened. So, simple version of the dashboard doesn't have this possibility. I'd like to add it, but I don't want to copy+past code from the full version of the dashboard because the code of this part is about two thousand lines. I'll add some primitive code example:
DashboardView = SomeAnotherView.extend({
initialize: function() {...},
events: {...} // huge objects of jQuery events,
render: function () {...},
... // 2k lines of functions for events
});
How can I use this View on another page? I tried to call a function from this view:
DashboardView.prototype.filterClicked(event);
But in this case event.curentTarget is null (it is necessary for this function), I also tried to send "this" to get the context, but it was failed.
Is there a possibility in Backbone.js to use one View for 2+ pages without any huge copy/past code?
Ideally if you have a simple version and full version of a view, you should have a "base view" (simple one) and the full version should extend the base view.
It'll look something like:
var SimpleDashbard = Backbone.view.extend({});
var Dashboard = SimpleDashbard.extend({});
In this way Dashboard will have access to the methods from SimpleDashbard.
Your situation sounds like you need to use a method from extended view in base view. Which is not a good idea. Ideally if it's shared you should move it to the base view/extract it into a utility method or service, and of course this involve re-writing this method to be reusable
If you have views that share a large amount of functionality, you could consider using the same View type, but opening it up to some configuration when instancing. For example:
var DashboardView = Backbone.View.extend({
initialize: function(options) {
this.allowFunctionX = (options && options.allowFunctionX);
this.allowFunctionY = (options && options.allowFunctionY);
},
// etc
functionX: function() {
if (!this.allowFunctionX) { return; }
// do the function...
},
functionY: function() {
if (!this.allowFunctionY) { return; }
// do the function...
},
});
Then on one page:
var firstDashView = new DashboardView({allowFunctionX: true});
and on another page:
var secondDashView = new DashboardView({allowFunctionY: true});
This may become not worth it if the functionality diverges too much (and there are likely better ways to configure than passing in a long list of booleans!). If your requirements are significantly different on your two pages, I feel like duplicating the code they both need is not a major sin.

How to trace function calls in Marionette

Somewhere in the global scope:
let App = Backbone.Marionette.Application.extend({});
window.Ext = new App();
Inside Module A:
Ext.vent.trigger('Tracked:Email:send', {
from_email: tracking_data.sender,
to_emails: tracking_data.to,
cc_emails: tracking_data.cc,
email_id: tracking_data.email_id || '',
template: tracking_data.template_id || '',
subject: tracking_data.subject
});
Inside Module B:
Ext.vent.on('all', function (evt_name, params) {
// something else...
console.log(params);
}
The object's properties (from_email, to_emails & cc_emails) are undefined when I call console.log in Module B.
I've tried to debug this using console.trace, but the console doesn't show any functions that are involved in changing the object. I've also tried using Object.observe to capture the act of changing the object but no changes are detected.
Can some please teach me some debugging techniques to trace function calls and events in Marionette.
The scenario is:
our codebase is huge.
I'm a new guy at our company so I'm not sure if there are other functions or events that are involved.
I'm the only front end developer right now.
The good news: there's nothing special about Marionette here. Everyday JavaScript debugging techniques will help you out.
The bad news: as you're aware, debugging large, event-driven applications is difficult.
You could take these steps in Chrome dev tools (YMMV with other browsers):
Split the App.trigger line to get a reference to the parameters object:
let options = { from_email: ... }
App.vent.trigger('Tracked:Email:send', options);
Set a breakpoint on Ext.vent.trigger and run your code.
When execution pauses at the breakpoint, check that options contains the expected values. If not, the problem is somewhere before App.vent.trigger. Look up the call stack for any functions that affect tracking_data. You may need to check the Async checkbox if it is populated by asynchronous code.
If options contains the values you expect, carry on...
Whilst execution is paused use the console to save a global reference to your parameters object:
> OPTIONS = options
Add OPTIONS as a watch expression. Expand the item so you can watch changes to its properties.
Step through (including Marionette and Backbone code) until you see the OPTIONS properties change. If you don't see Marionette code when you step into App.vent.trigger you may need to remove Marionette from your black boxed libraries.

Overwrite Javascript prototype with stub functions

I'm trying to run an A/B test for a new feature I'm adding to a website. In the past, our team has done something like this before showing various features on the page:
someUserActionThatEnablesFeature:function(){
experiments.isUserInControlGroup('new-feature1') && newFeature1Obj.show();
}
someUserActionThatDisablesFeature:function(){
experiments.isUserInControlGroup('new-feature1') && newFeature1Obj.hide();
}
I have found this to be pretty kludgey, since we have to check if the experiment is enabled in every place we use the new feature. What I was thinking about doing instead something like this:
function NewFeature1(){
//constructor
}
NewFeature1.prototype = {
show:function(){
//do something
},
hide:function(){
//do something
},
//etc
};
//before any objects are declared
if (experiments.isUserInControlGroup('new-feature1')) {
for(var prop in NewFeature1.prototype) {
//replace with empty function
NewFeature1.prototype[prop] = function(){};
}
}
The idea here is that I'm replacing the NewFeature1 class's methods with empty stubs before I ever instantiate it, thereby ensuring that none of my calls on the object will ever do anything if the user isn't in the control group.
Is this dangerous in some browsers? I couldn't tell in my initial tests if I was overwriting Object's properties. In webkit, it didn't seem like it was hurting anything. Am I missing something? I only have to worry about webkit, FF, and IE8+.
Thanks!
I think it's acceptable, maybe better to stub only direct properties determined by hasOwnProperty if the class has no inherits.

Netbeans navigator does not show my JavaScript Class methods

Some background, skip to the 2nd paragraph to get to the question. I have tried quite a few editors like your typical developer and still my all-time favorite was Homesite/ColdFusion Studio before it was sucked into Dreamweaver and I trust most of you will agree with me that well, yea.. Dreamweaver. Anyway, I've been running Sublime Text 2 and it's ok but I feel I need more of an IDE than a text editor. To that end I have been using NetBeans for a few months. I'm starting to love it. At home I use a Mac with TextMate and Coda but I wouldn't mind moving to NetBeans completely however there are a few issues that bother me. Most notably its XSL editing is annoying for a few reasons and then secondly this JavaScript issue I've been having.
I like the ability to jump around a JavaScript file using ctrl+click on methods and such, alt+back to move back and being able to see the outline of your methods and classes in the navigator. However my issue is that in my Javascript files NetBeans doesn't seem to be able to figure out my class and its methods. I use a pattern for writing my singleton classes that has proved indispensable for me. I write such classes as follows:
// create class to contain code for this page
var FieldMgmt = function() {
// vars local to the class
var Fields = {}; // Store the form fields of the class
return {
// startup method
init: function() {
// initialize properties
console.log('field management intialized');
// capture the fields
this.Fields = Fields = {
field1: $('select[name=field1]') // field One
,field2: $('select[name=field2]') // field Two
,field3: $('select[name=field3]') // field Three
};
this.initEvents(); // setup events
}
// initialize events
,initEvents: function(){
}
// method 1
,method1: function(arg1, arg2){
}
// method 2
,method2: function(arg1, arg2){
}
}; // end return of FieldMgmt
}(); // end FieldMgmt
// start the code for this page
$(document).ready( function(doc){ FieldMgmt.init(); } );
And below is a picture of what shows up in my navigator for this file:
As you can see, none of my methods show up in the navigator such as initEvents, method1, method2, etc. ctrl+click-ing a method call as well doesn't go to the method declaration. So NetBeans just doesn't know this is a class. I've had similar problems with this pattern before in other editors, for instance NotePad++ and I was able to get the editor to figure out my file by modifying the regular expressions used to parse the file.
I can survive without this feature but if I could get this to work then this would be my editor of choice as these files can get rather large and being able to see all the methods and jump around the file quickly by ctrl+click-ing, etc. would be fantastic.
I'm using NetBeans 7.3 with everything updated to the latest as of today on Windows Server 2003. Any help would be greatly appreciated. Is there anyway for me to modify NetBeans in order for it to be aware of my methods? Are there plugins for this? Thanks in advance.
In your example code you return a closure that keeps a variable named Fields as "private" but the first thing you do in init is expose it publicly by declaring this.Fields=Fields. With the example code posted you might as well declare FieldMgmt as an object literal and have NetBeans recognize it to have it's properties show up in the Navigator.
var FieldMgmt = {
init: function() {
}
,initEvents: function(){
}
,method1: function(arg1, arg2){
}
,method2: function(arg1, arg2){
}
};
Thanks to #HMR for his answer. It put me on the right path. I'm posting this now so that others using the style of coding I mentioned can have an example of how to modify theirs to show up in the navigator without changing how it behaves or losing the advantages of structuring your code this way. So the final outcome looks like this:
// create class to contain code for this page
var FieldMgmt;
(function(){
// vars local to this closure
var Fields = {}; // Store the form fields of the class
FieldMgmt = {
// startup method
init: function() {
// initialize properties
console.log('field management intialized');
// capture the fields
this.Fields = Fields = {
field1: $('select[name=field1]') // field One
,field2: $('select[name=field2]') // field Two
,field3: $('select[name=field3]') // field Three
};
this.initEvents(); // setup events
}
// initialize events
,initEvents: function(){
}
// method 1
,method1: function(arg1, arg2){
}
// method 2
,method2: function(arg1, arg2){
}
}; // end FieldMgmt
})(); // end closure
// start the code for this page
$(document).ready( function(doc){ FieldMgmt.init(); } );
And the navigator now shows the methods and properties:
Hope that helps.
It works in the current version of Netbeans 8.1.

How to create a well formed global javascript object containing special functions

I am creating a small project that heavily relies on JavaScript. I come from php/mysql and now stepping into node.js/javascript/mongodb, and I hve to say it's quite a mindswitch.
I want to create a simple object that has some special function that I can use in the page. I have been looking at some tutorial, and looking at the libraries such as jquery and backbone, but I need some final advice on my decision.
I only need some small functions, and no cross-browser support, that's why I don't choose something like backbone. Maybe ill change to that later when I have a better crasp on JavaScript programming.
What is confusing me is whether to use the new, or maybe wrapping the code into a self-invoking function.
I see jquery creates an object inside the window and than exposes that, but I have no idea how that works.
Enough intro, now to the point. I have created something like this:
var $s = Object.create({
page: Object.create({
title: 'pagetitle',
html: '',
data: {},
render: function(){
// Basic render function
}
}),
socket: Object.create({
// My websocket connection
}),
store: function(key, value) {
localStorage.setItem(key, JSON.stringify(value));
},
retrieve: function(key) {
var value = localStorage.getItem(key);
return value && JSON.parse(value);
},
slugify: function(slug){
return slug.replace(/[^a-zA-Z 0-9-]+/g,'').toLowerCase().replace(/ /g,'-');
}
});
This are just a few random functions I put in.
I haven't tested this yet, it is a draft, I want to know if this is any good.
Now I was thinking i can do some stuff like this:
$s.page.html = 'somehtml';
$s.page.render();
// Maybe
$s.store( $s.page.title, $s.page.html );
I do use jQuery and jQuery templating, so something like this could be possible:
$.tmpl( $s.page.html, $s.page.data ).appendTo( "#content" );
Nothing fancy is needed here. You can create a global javascript object with a method like this:
var myGlobalObject = {};
myGlobalObject.testFunction = function() {
// put your code here
};
You can then call that like this:
myGlobalObject.testFunction();
One slightly more flexible design pattern you will often seen used is this:
var myGlobalObject = myGlobalObject || {};
myGlobalObject.testFunction = function() {
// put your code here
};
This is used when there might be lots of different pieces of code contributing to myGlobalObject and they all want to make sure that it's properly declared before adding properties to it. This way of doing it, creates it if it doesn't already exist and if it does already exist, leaves the methods and properties on it that might already be there. This allows multiple modules to each contribute initialization to myGlobalObject without regards for the order they load.

Categories

Resources