Extending existing singleton - javascript

I like the idea of using Singleton mentioned here http://www.adobe.com/devnet/html5/articles/javascript-design-patterns-pt1-singleton-composite-facade.html:
var Namespace = {
Util: {
util_method1: function() {…},
util_method2: function() {…}
},
Ajax: {
ajax_method: function() {…}
},
some_method: function() {…}
};
Let's say I have to add some methods and new namespace too (Namespace.Util2) later, how can I add methods without modifying the above code

It is simply:
Namespace.Util.newUtilMethod = function () { };
To add a new namespace,
Namespace.Util2 = { /* definitions */ };

namespace.util.newFunc = function () { };
or, if you're using jquery and want to add a bunch at once:
var newStuff = {
newThing1: function () {...},
newThing2: function () {...},
newThing3: function () {...}
};
$.extend(namespace.util, newStuff);

Related

Calling a private/nested javascript function from an outer scope

I have my javascript code like this . Inside that I have an init() function and in that function I have an options JSON object and in that object I have a function defined as objectselected(). How I call that function in a button click event
I have tried like this WorkFlow.init().options.Objectselected() but it is not working,
var WorkFlow = {
connectionData: [],
selectedTouchpoints: [],
init: function () {
var options = {
palleteId: "myPaletteElement",
elementId: "playAreaContainer",
TextStoreList: ['One', 'Two', 'Three'],
LinkTextStoreList: $('#drpLinkType option').map(function () {
return this.text;
}).get(),
shapeList: ['RoundedRectangle', 'Circle', 'Rectangle', 'Ellipse', 'Square', 'Diamond', 'Card', 'Database'],
diagramUpdate: function (e) {
},
objectSelected: function (e) {
},
linkUpdate: function (e) {
},
initialize: function () {
}
myGraph = new Graph(options);
options.initialize();
},
}
How to call that function.
One way around is you can return options and than call it.
init: function () {
var options = {
...your code..}
return options;
},
and call it than
var options = WorkFlow.init();
options.Objectselected();
As it stands, you have no access to options because it's a local variable - that is, local to its scope.
To access its contents, you'll need to return it from init().
Think about it:
WorkFlow.init()
Currently this returns undefined, because your init() returns nothing. You're trying to chain like in jQuery, but that relies on the API always returning the instance. Your path finds a dead-end at init().
To fix this, have init() return options - or at least the part of it you want to access from outside - an "export".
So (basic example)
init: function() {
var options {
my_func: function() { }, //<-- we want outside access to this
private: 'blah' //<-- this can stay private - leave it out of the export
}
//return an export, exposing only what we need to
return {
my_func: options.my_func
}
}
You need to return options as it is inside init function's scope
var WorkFlow = {
connectionData: [],
selectedTouchpoints: [],
init: function () {
var options = {
palleteId: "myPaletteElement",
elementId: "playAreaContainer",
TextStoreList: ['One', 'Two', 'Three'],
LinkTextStoreList: $('#drpLinkType option').map(function () {
return this.text;
}).get(),
shapeList: ['RoundedRectangle', 'Circle', 'Rectangle', 'Ellipse', 'Square', 'Diamond', 'Card', 'Database'],
diagramUpdate: function (e) {
},
objectSelected: function (e) {
},
linkUpdate: function (e) {
},
initialize: function () {
}
myGraph = new Graph(options);
options.initialize();
return options;
},
}
And call it as WorkFlow.init().objectSelected();
Building on Patrick's comment, you'd need to return options from the init function:
var WorkFlow = {
connectionData: [],
selectedTouchpoints: [],
init: function () {
var options = {
palleteId: "myPaletteElement",
...
options.initialize();
return options;
},
}

Vue.js inheritance call parent method

Is it possible to use method overriding in Vue.js?
var SomeClassA = Vue.extend({
methods: {
someFunction: function() {
// ClassA some stuff
}
}
});
var SomeClassB = SomeClassA.extend({
methods: {
someFunction: function() {
// CALL SomeClassA.someFunction
}
}
});
I want to call ClassA someFunction from ClassB someFunction. Is it even possible?
No, vue doesn't work with a direct inheritance model. You can't A.extend an component, as far as I know. It's parent-child relationships work mainly through props and events.
There are however three solutions:
1. Passing props (parent-child)
var SomeComponentA = Vue.extend({
methods: {
someFunction: function () {
// ClassA some stuff
}
}
});
var SomeComponentB = Vue.extend({
props: [ 'someFunctionParent' ],
methods: {
someFunction: function () {
// Do your stuff
this.someFunctionParent();
}
}
});
and in the template of SomeComponentA:
<some-component-b someFunctionParent="someFunction"></some-component-b>
2. Mixins
If this is common functionality that you want to use in other places, using a mixin might be more idiomatic:
var mixin = {
methods: {
someFunction: function() {
// ...
}
}
};
var SomeComponentA = Vue.extend({
mixins: [ mixin ],
methods: {
}
});
var SomeComponentB = Vue.extend({
methods: {
someFunctionExtended: function () {
// Do your stuff
this.someFunction();
}
}
});
3. Calling parent props (parent-child, ugly)
// In someComponentB's 'someFunction':
this.$parent.$options.methods.someFunction(...);
In case someone's interested in a JustWorksTM solution:
var FooComponent = {
template: '<button #click="fooMethod()" v-text="buttonLabel"></button>',
data: function () {
return {
foo: 1,
bar: 'lorem',
buttonLabel: 'Click me',
}
},
methods: {
fooMethod: function () {
alert('called from FooComponent');
},
barMethod: function () {
alert('called from FooComponent');
},
}
}
var FooComponentSpecialised = {
extends: FooComponent,
data: function () {
return {
buttonLabel: 'Specialised click me',
zar: 'ipsum',
}
},
methods: {
fooMethod: function () {
FooComponent.methods.fooMethod.call(this);
alert('called from FooComponentSpecialised');
},
}
}
jsfiddle: https://jsfiddle.net/7b3tx0aw/2/
More info:
This solution is for devs that can't use TypeScript for some reason (which I think allows defining vue components as classes, which in turn allows full inheritance feature-set).
Further elaboration about the solution (whys and hows): https://github.com/vuejs/vue/issues/2977
This ain't that ugly, considering that no rocket science is used here (calling anonymous functions with the this pointer replaced should be no magic for any decent js dev).
How to use Function.prototype.call()
Reference https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call
Sample code:
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
Product.call(this, name, price);
this.category = 'food';
}
console.log(new Food('cheese', 5).name);
// expected output: "cheese"
In case someone asks for a solution here is mine and works fine :
var SomeClassA = {
methods: {
someFunction: function () {
this.defaultSomeFunction();
},
// defaultSomeFunction acts like parent.someFunction() so call it in inheritance
defaultSomeFunction: function () {
// ClassA some stuff
},
},
};
var SomeClassB = {
extends: SomeClassA,
methods: {
someFunction: function () {
// Replace the wanted SomeClassA::someFunction()
this.defaultSomeFunction();
// Add custom code here
},
},
};
using juste extends from https://v2.vuejs.org/v2/api/#extends replaces the usage of Vue.extends()

Starting with module pattern

I'm trying to start using moddule pattern in my JS code from the beginning but I have problems to understand how to perform this kind of code design.
This is a simple event:
$('#docTable').on('dblclick', 'tbody tr.line', function (event) {
$('#modal1').modal({ keyboard: false, backdrop: "static", dismiss: "modal" });
$('#modal1').modal('show');
});
I've created a couple of JS files. View.js:
var task = window.task || {};
task.View = (function () {
function View(rootElement) {
var dom = {
table: $('#docTable'),
},
callbacks = {
onsubmit: undefined
};
return {
};
}
return View;
}());
and Controller.js:
$(document).on('ready', function () {
var View = task.View(document);
});
but I have no idea how to continue and catch the dblclick event.
Could anybody please help me?
Thanks in advance.
You can create 'class' View and add event binding to its prototype. After that you can use it on multiple tables. If you want to have access to element in table you can add classes to them and find them in defineDOM method:
View.js
var task = window.task || {};
task.View = function (table) {
this.$table = $(table);
this.init();
};
task.View.prototype ={
init: function () {
this.defineDOM();
this.bindEvents();
},
defineDOM: function() {
// Search for DOM elements in context of table element
this.$button = $('.docButton', this.$table);
this.$links = $('.docLinks', this.$table);
},
bindEvents: function () {
this.$table.on('dblclick', 'tbody tr.line', this.onDblClick.bind(this))
},
onDblClick: function () {
$('#modal1').modal({ keyboard: false, backdrop: "static", dismiss: "modal" });
$('#modal1').modal('show');
}
}
Usage
$(document).on('ready', function () {
new task.View('#docTable');
});

Setting correct this-value in requestAnimationFrame

I have an app-object constructer that looks like this:
var app = function(loadedsettings) {
return {
init: function() {
this.loop();
},
loop: function() {
this.update();
window.requestAnimationFrame(this.loop);
},
update: function() {
//loop through settings and call update on every object.
},
settings: [
//array of settings objects, all with update methods.
]
};
}
Then when I do:
var theApp = app(settings);
theApp.init();
I get:
Uncaught TypeError: Object [object global] has no method 'update'
because when requestAnimationFrame is called, the this-value inside the loop function is set to window.
Does anybody know how to call requestAnimatinFrame with the 'theApp' object set as the this-value?
You can create a bound function (with a fixed this), and pass that to requestAnimationFrame:
var app = function(loadedsettings) {
return {
init: function() {
this.loop();
},
loop: function() {
this.update();
window.requestAnimationFrame(this.loop.bind(this));
},
update: function() {
//loop through settings and call update on every object.
},
settings: [
//array of settings objects, all with update methods.
]
};
}
I think that a browser which supports requestAnimationFrame will also support Function.prototype.bind, but in case you come across one that doesn't, there are polyfills available.
You need to cache a reference to this:
var app = function(loadedsettings) {
var self = this;
return {
init: function() {
self.loop();
},
loop: function() {
self.update();
window.requestAnimationFrame(self.loop);
},
** snip **
...

How to create a method in a GObject subclass in JS/Seed

I have GObject subclass defined.
BrowserToolbar = new GType({
parent: Gtk.HBox.type,
name: "BrowserToolbar",
init: function (){
}
});
I have defined new function abc using the same syntax as for init.
BrowserToolbar = new GType({
parent: Gtk.HBox.type,
name: "BrowserToolbar",
init: function (){
}
abc: function (){
}
});
But I am not able to call it, it is "undefined". What is wrong?
var tb = new BrowserToolbar();
tb.abc(); // undefined -> error
Thanks
Found it: http://git.gnome.org/browse/seed-examples/tree/browser/TabbedBrowser.js
init: function ()
{
this.close_tab = function (tab) {}
}

Categories