Knockout JS - Function is not a constructor - javascript

I am getting the error 'TabsViewModel is not a constructor' with the following code. I've looked at other posts regarding this error, but most suggest that the function name is in use somewhere else, but as you can see this is a very simple example and TabsViewModel is not used elsewhere.
define(['utils','ko','text!tmpl/risersandfallerstabs_partial.html','text!tmpl/errorPage_partial.html'], function(utils,ko,tmplrisersandfallerstabsStr,tmplErrStr) {
let tabsmodel = {};
$(function() {
tabsmodel = new TabsViewModel();
ko.components.register('risersandfallerstabs', {
viewModel: utils.createVM(tabsmodel),
template: tmplrisersandfallerstabsStr
});
utils.applyBindings(tabsmodel,'risersandfallerstabs');
var TabsViewModel = (function(){
let self = {};
self.test = "123";
return self;
});
});
})
Why am I getting this error?

You're trying to call TabsViewModel before it exists. Move your function definition above the function execution.
var TabsViewModel = (function() {
let self = {};
self.test = "123";
return self;
});
tabsmodel = new TabsViewModel();

I was running into a similar issue, the problem was that my class was an anonymous function instead of a normal function.
Didn't work:
var TabsViewModel = () => { ... }
Worked:
var TabsViewModel = function() { ... }

Related

Why is Click binding undefined when using this declared in a returned RequireJS function

I am using Require JS as illustrated in the code below. However, I cannot get the click binding to work if I declared this within the returned function
If I place this outside of the function, the code works.
This does not work:
return function viewModelA() {
var self = this;
self.SelectedTableRow = function(selectedRowData){
// Do something with return value
};
}
This works:
var self = this;
return function viewModelA() {
self.SelectedTableRow = function(selectedRowData){
// Do something with return value
};
}
Complete code:
define(function(require){
var $ = require ('jquery');
var ko = require ('knockout');
var viewModelB = require ('ViewModelB/ViewModelB');
var self = this;
return function viewModelA() {
var self = this;
self.member = {};
self.member.countries = ko.observableArray();
$.getJSON('https://restcountries.eu/rest/v1/all', function(data) {
self.member.countries(data);
});
self.SelectedTableRow = function(selectedRowData){
// Do something with return value
};
return{
member: self.member
}
}
});
Abbreviated HTML:
<tbody data-bind="foreach: member.countries">
<tr data-bind="click: SelectedTableRow, clickBubble: false">
this inside/outside viewModelA are different based on how the function is invoked. You are returning viewModelA which is being invoke by some one else.
Try this
return function viewModelA() {
var self = this;
self.SelectedTableRow = function(selectedRowData){
// Do something with return value
};
}.bind(this)

Assign an element to a variable

I have an Javascript object following the Module Pattern
var foo = (function() {
var obj = (function() {
var $button = $('#myButton');
var init = function() {
$button.hide();
};
return {
init: init
};
})();
return { obj: obj };
})();
If I call foo.obj.init(), the button should be hidden, and this does not occur.
I saw different questions here about the assignment of an element to a variable, but I think that the problem is with the object. Can't I access a private variable from a public method?
From my comment:
Do it as part of init... you can just declare the var in order to isolate the scope, and then modify it to actually set the button as part of init
Example:
var foo = (function() {
var obj = (function() {
var $button; //$('#myButton');
var init = function() {
if (typeof $button === 'undefined') {
// i would probably make the selector an argument to `init`
// if i were you.
$button = $('#myButton');
}
$button.hide();
};
return {
init: init
};
})();
return { obj: obj };
})();

binding this keyword on anonymous & async function

In JavaScript I am looking for a way to use bind() on an anonymous and async function.
Example:
exports.foo = function () {};
exports.foo.prototype = {
load : function(id) {
var query = new Parse.Query("SomeObject");
query.get(id).then(function(object) {
this.object = object; // this is the wrong this
});
}
};
I got this working by making the functions non-anonymous, but I think it makes my code look ugly. Especially after having 4 different anonymous functions in a row.
exports.foo = function () {};
exports.foo.prototype = {
load : function(id) {
function _load(object) {
this.object = object;
}
var _loadThis = _load.bind(this);
var query = new Parse.Query("SomeObject");
query.get(id).then(_loadThis);
}
};
Is there a better way?
Well it's not necessarily "better", but you can call .bind() directly after the closing brace of your function instantiation expression:
query.get(id).then(function(object) {
this.object = object; // this is the wrong this
}.bind(this));
A function instantiation expression gives you a function object reference, so putting a . after it and calling bind makes sense. What gets passed to the .then function, therefore, is the return value from the call to .bind.
This syntax is not correct:
exports.foo.prototype = {
load = function(id) {
var query = new Parse.Query("SomeObject");
query.get(id).then(function(object) {
this.object = object; // this is the wrong this
});
}
};
The prototype is an object who's properties are defined as load: function() {}, not load = function() {}.
It should be:
exports.foo.prototype = {
load: function(id) {
var query = new Parse.Query("SomeObject");
query.get(id).then(function(object) {
this.object = object; // this is the wrong this
});
}
};
A simple way to do it is to declare a variable to the correct 'this' and use closuers to keep a reference to it.
exports.foo = function () {};
exports.foo.prototype = {
load : function(id) {
var self = this;
var query = new Parse.Query("SomeObject");
query.get(id).then(function(object) {
self.object = object; // this is the wrong this
});
}
};

JavaScript getting constructor is undefined

this is my code:
window.myApp= window.myApp|| {};
myApp.jira = (function () {
var getId = function () {
return ...;
}
var init = function() {
var id = myApp.jira.getId();
}
})();
$(document).ready(function () {
myApp.jira.init(); // here jira is null and getting undefined
});
when the page is loaded it says jira is undefined.
Try this:
window.myApp= window.myApp|| {};
// Function here is being immediately invoked. No "return" statement
// in your code is equivalent to "return undefined;".
myApp.jira = (function () {
var getId = function () {
return ...;
}
var init = function() {
var id = myApp.jira.getId();
// Bonus note: you can simplify this:
// var id = getId();
}
// If we return an object with functions we want
// to expose (to be public), it'll work,
return {
init: init,
getId: getId
};
})(); // <-- here you'll invoking this function, so you need return.
$(document).ready(function () {
// Without 'return' above, myApp.jira evaluated to undefined.
myApp.jira.init();
});
Working DEMO
Or you can use object literal pattern instead:
var myApp = {};
myApp.jira = {
getId: function () {
return ...;
},
init: function() {
var id = this.getId();
}
};

Add function to object

I have the following code
var PROMO = PROMO || {};
PROMO.Base = (function () {
var _self = this;
var Init = function () {
WireEvents();
};
var WireEvents = function () {
//wire up events
};
} ());
In the same file I have the code to call the above function
I am trying to get to an end point where I can use the following code
$(document).ready(function () {
PROMO.Base.Init();
});
this gives the error
Cannot call method 'Init' of undefined
Now I know there are many ways to write javascript, but in this case I want to be able to call my functions, or least the Init method in the way shown above.
var PROMO = PROMO || {};
PROMO.Base = (function () {
var _self = this;
var Init = function () {
WireEvents();
};
var WireEvents = function () {
//wire up events
};
var reveal = {
Init: Init
};
return reveal;
} ());
You need to return the public facing functions. See updated code.
Working fiddle with both patterns, using IIFE and direct attribution.
Using var makes the definition private and your function is returning nothing. Use this:
PROMO.Base = {
Init: function() {
},
WireEvents: function() {
};
};
You are wrapping the definition with an IIFE(Immediately Executed Function Expression). So your PROMO.Base object will be assigned the value of that (function(){//blabla})(); returns. But your function doesn't have a return statement. By default it will return undefined.
Which is way your PROMO.Base will be undefined and you get this:
Cannot call method 'Init' of undefined
If you really want that IIFE:
var PROMO = PROMO || {};
// NEVER use _self = this inside static functions, it's very dangerous.
// Can also be very misleading, since the this object doesn't point to the same reference.
// It can be easily changed with Function.prototype.call and Function.prototype.apply
PROMO.Base = (function () {
_PROMO = {
Init : function () {
document.body.innerHTML += "itworks";
},
WireEvents : function () {
//wire up events
}
}
return _PROMO;
} ());
PROMO.Base.Init();
Update
The better and easier pattern is to simply assign the functions to PROMO.Base. Dully note you should not capitalize static functions, but only constructors. So if something is not meant to be instantiated, don't call it Init, it should be init. That is the convention.
var PROMO = {};
PROMO.Base = {};
PROMO.Base.init = function() {
console.log("this works");
};
PROMO.Base.wireEvents = function() {
console.log("this is a static function too");
};
You can attach it to the window object like ...
window.PROMO = (function($, _){
// this will access PROMO.Base
PROMO.Base = {
// inner functions here
Init:{}
};
})(jQuery, _);
Then load it as you do.
Or if you depend from jQuery
(function($){
var PROMO = {
// inner functions
Init: function(){},
WireEvents: function(){}
};
$.PROMO = PROMO;
})(jQuery);
On DOM ready
jQuery(function ($) {
var promo = $.PROMO || undefined;
promo.Base.Init();
});

Categories