I am a total beginner at dojo and am trying to move some of my interface code into a class just to keep the methods out of my main file.
My problem - I am unable to use internal class functions as part of other functions.
After I create an interface object in an external file as shown, I am able to sucessfully:
appInterface = new (interface)
appInterface.showGraphWindow()
appInterface.hideGraphWindow()
However I am unable to work out how to use these functions inside of the toggleGraphWindow function. (Due to context ?)
If I attempt to call:
on(registry.byId("graphBtn"),"click", appInterface.toggleGraphWindow);
It crashes on the line:
this.showGraphWindow()
or
this.hideGraphWindow()
With: "Undefined is a not a function"
How do I code the toggleGraphWindow function?
Iterface.js
define([
"dojo/_base/declare",
"dojo/on",
"dijit/registry"
],
function(
declare,
on,
registry
){
return declare (null, {
hideGraphWindow : function () {
dijit.byId("graphWindowMain").domNode.style.display = 'none';
dijit.byId("applicationWindow").resize();
},
showGraphWindow : function () {
dijit.byId("graphWindowMain").domNode.style.display = 'block';
dijit.byId("applicationWindow").resize();
},
toggleGraphWindow : function (){
if (dijit.byId("graphBtn").checked == true)
{this.showGraphWindow()}
else
{this.hideGraphWindow()}
}
});
});
What's wrong with
toggleGraphWindow : function (){
if (dijit.byId("graphBtn").checked == true) {
this.showGraphWindow();
}
else {
this.hideGraphWindow();
}
}
?
Thanks to you both, you were indeed correct Ken, I had read this similar post a lot of times, and somehow didnt understand the answer within:
Calling object methods internally in dojo
After reading what you have posted, I have somehow understood the answer linked above and now understand what my problem was! Thanks to all.
I fixed it by altering my code in the main application as follows:
var appInterface = new Interface();
on(registry.byId("graphBtn"),"click", appInterface.toggleGraphWindow);
changed to:
var appInterface = new Interface();
var graphToggle = dojo.hitch(appInterface, "toggleGraphWindow");
on(registry.byId("graphBtn"),"click", graphToggle);
I believe the reason for the error, was that the "this" object at runtime, was actually the "graphBtn" instead of the appInterface.
Related
I have a class I am using for creating CRUD Objects for my site.
It stores the form and table paths for adding, listing, editing and deleting the data, as well as reloading your view with ajax after each edit.
Here is my class definitions:
class CRUDObj{
constructor(containerSel, links) {
this.links = links;
this.containerSel = containerSel;
this.formCallBack = function(){};
}
setActive(obj_id){
$.post(this.links.editURL+'?'+obj_id, {status:"active"}, this.reload);
}
reload(returnData){
this.formCallBack(returnData);
this.formCallBack = function(){};
if($(this.containerSel).length > 0){
ajaxLoad(this.links.listURL, $(this.containerSel));
}
}
}
A basic instance of initializing it:
var contactObj = new CRUDObj('#contacts', {
editURL: '/contact.edit.php',
listURL: '/contacts.list.php',
});
contactObj.formCallBack = function(){
console.log('Custom Reload Callback');
};
The problem appeared when I tried to add the callback, so that I could run a custom function during the refresh.
Running contactObj.setActive(); works properly, and my refresh function is called after the form submits, but when it hits my callback I get:
Uncaught TypeError: this.formCallBack is not a function
Calling it manually contactObj.refresh(); works smoothly.
How can I pass this callback function through better?
The problem is that you're passing method as function, so you loose this context. this will be window object or undefined (if using strict mode):
You need this:
var self = this;
lightboxForm(this.links.editURL+'?'+obj_id, function(x) { self.reload(x) });
or using ES6
lightboxForm(this.links.editURL+'?'+obj_id, x => this.reload(x));
or using bind to return function with given context:
lightboxForm(this.links.editURL+'?'+obj_id, this.reload.bind(this));
I use angularJS(1.4) for frontend only.
I have passed the JS-class DummyClass to an angularJS-Service called TLSService, and I added this service to an angularJS-Controller named mLxController.
I'm having problems accessing variables and methods of the DummyClass from the mLxController.
For example, as you will see in the code below, I can't retrieve a class variable String.
I use window.alert(String) to check that.
Instead of the String from the DummyClass, 'undefined' is displayed in the window.
I think it's worth mentioning, that when adding the window.alert("DummyClass calls.") in the constructor of the DummyClass, the alert will immedialtely be shown after loading the corresponding URL.
That's the code of the mLxController.js :
angular.module('mApp')
.controller('mLxController', function('TLSService', $scope, $state, $stateParams){
...
//this function is called in `index.html`
$scope.callTLSService = function(){
window.alert(TLSService.response);
}
...
});
Here's the code for dummyClass.js :
class DummyClass {
constructor() {
this.response = "Hi Controller! Service told me you were looking for me.";
}
}
Here's tlsService.js :
angular.module('mApp').service('TestClaServScript', function(){new DummyClass()});
UPDATE:
I have managed to make the DummyClass usable to the mLxController.
Although I'm pretty sure that my solution is not recommendable practice.
Basically, I moved the DummyClass into the same file as the TLSService.
Also, DummyClass and it's path isn't mentioned in the main index.html, anymore.
Accordingly, tlsService.js looks like this, now:
angular.module('mApp').service('TestClaServScript', function(){
this.clConnect = function(inStr){
var mDummy = new DummyClass(inStr);
return mDummy;
}
});
class DummyClass {
constructor(inStr){
this.inStr = inStr;
this.response =
"DummyClass says: \"Hi Controller! Service told me you were looking for me.\"";
this.charCount = function(inStr){
var nResult = inStr.length;
var stRes = "btw, your String has "
+(nResult-1)+", "+nResult+", or "+(nResult+1)+" characters.\nIDK."
return stRes;
}
}
}
and mLxController.js:
angular.module('mApp')
.controller('mLxController', function('TLSService',$scope,$state, $stateParams){
...
$scope.makeDummyCount = function(){
var mDummy = TestClaServScript.clConnect("This string is for counting");
window.alert(mDummy.charCount(mDummy.inStr));
}
...
});
There must be a way to properly import DummyClass, so that I can keep separate files.
I will do some more research and I will keep trying.
UPDATE 2: Problem solved
The provided answer to my question helped me implementing TLSService in the originally planned way.
I'd like to post the final version of the code here, in hope that it will help some beginner, like I am.
tlsService.js:
angular.module('mApp').service('TLSService', function(){
this.mCwParam = function(inputStr){
return new DummyClass(inputStr);
}
});
DummyClass stays the same like I posted it in the first Update, but it has its own file dummyClass.js, again.
mLxController.js:
angular.module('mApp')
.controller('mLxController', function('TLSService', $scope, $state, $stateParams){
...
//this function is called in the mLx-view's `index.html`
$scope.askDummyCount = function(){
var mService = TLSService.mCwParam("String, string, string, and all the devs that sing.");
window.alert(mService.charCount());
}
...
});
Also, TLSService and DummyClass ar added in the apps main index.html.
A problem in your original setup is when you register your class as a service, you're not returning the instance of the class:
function(){new DummyClass()}
Should be:
function(){return new DummyClass()}
Autoreturning only works when you don't use curly braces, like
() => new DummyClass()
I am trying to add a functionality to a web page that uses a jquery library which doesn't seem to have any documentation. (unknown origin) my problem is mainly due to the lack of understanding on jquery plugin model and/or inner workings of javascript.
1. the plugin is initiated as follows
jQuery('div.carousel').scrollGallery({
mask: 'div.mask',
slider: 'div.slideset',
slides: 'div.slide', ............ });
2. the plugin is defined in jquery as follows
;(function($){
function ScrollGallery(options) {
this.options = $.extend({
mask: 'div.mask', ...... }, options);
this.init();
3. in the Object.prototype declaration i see the following function numSlide defined.
ScrollGallery.prototype = {
....................
numSlide: function(c) {
if(this.currentStep != c) {
this.currentStep = c;
this.switchSlide();
}
},
.......... };
Question.
How do i reference numSlide(int) function externally?.
I tried the following methods and it did not work.
myx = jQuery('div.carousel').scrollGallery({ // var myx was added in the global scope
myx.numSlide(1); //error undefined is not a function
i tried adding return this; at the end of myx = jQuery('div.carousel').scrollGallery({ but it still returns the jQuery object.
i also tried
jQuery.scrollGallery().numSlide(2); //error undefined is not a function
jQuery.scrollGallery.numSlide(2); //same error
Do i need to add LIGHT BULB
// jquery plugin
$.fn.scrollGallery = function(opt){
return this.each(function(){
$(this).data('ScrollGallery', new ScrollGallery($.extend(opt,{holder:this})));
});
};
}(jQuery));
ANSWER (I think)
it looks like the ScrollGalary object is stored in a data for the selector. So i believe i can do the following jQuery('selector').data('ScrollGallery').numSlide(2);
I decided to post this anyway in-case if anyone in the future had a similar gullible situation.
One way of doing this will be to initiate ScrollGallery object first and then use it.
var test = new ScrollGallery();
test.numSlide();
if you want to extend jQuery and use the function you can assign it as follows
$.fn.scrollGallery = new ScrollGallery();
and use it
$("window").scrollGallery.numSlide();
I am very new to JavaScript, and when working with my object's prototype I try to call the current object to extend a method but it is not working. So I google'd my problem but didn't really get anywhere as it is practically impossible to phrase. However, I found the this keyword which I thought should work but didn't. Here's what I have:
(function( window, document, undefined ) {
var myObj = function ( ) { }; // not a noop
var ua = function() { return navigator.userAgent.toLowerCase(); }
function noop() { }; // empty noop function
myObj.prototype = {
constructor: myObj,
renderizr: {
presto: ua().match(/(opera|presto)/i),
trident: ua().match(/trident/i), // don't parse "msie" as opera uses this sometimes
webkit: ua().match(/(chrome|safari|webkit)/i),
gecko: ua().match(/(firefox|gecko)/i), // don't parse "netscape" as a lot of strings use this
val: '' // keep empty for now
}
};
// renderizr.val extension
// use this so the user can print the value of
// the rendering engine instead of using multiple
// conditional statements.
if(this.renderizr.presto) { this.renderizr.val = "Presto" }
else if(this.renderizr.trident) { this.renderizr.val = "Trident") }
else if(this.renderizr.webkit) { this.renderizr.val = "Webkit") }
else if(this.renderizr.gecko) { this.renderizr.val = "Gecko") }
window.myObj = new myObj();
}( window, document ));
This way, you can do alert(myObj.renderizr.val); instead of doing monotonous conditional statements.
I don't want to do generic browser name detection because you're only supposed to test for the features which you need, not the browser. However, some rendering engines have different habits for rendering web pages, so I do want to include engine detection in my script. (However, I don't suggest using this, like I said, I just want to get to know javascript and how it works, and it's not working!).
So my question is, what am I doing wrong here and how can I fix it? Why doesn't the this keyword work?
You are using this in a context where you are not in the instance of a myObj object. this will be the global scope (ie. window).
Also, all your code is running immediately, you are not defining any functions in your prototype.
I believe you want those checks inside your constructor:
var myObj = function () {
// renderizr.val extension
// use this so the user can print the value of
// the rendering engine instead of using multiple
// conditional statements.
if(this.renderizr.presto) { this.renderizr.val = "Presto" }
else if(this.renderizr.trident) { this.renderizr.val = "Trident" }
else if(this.renderizr.webkit) { this.renderizr.val = "Webkit" }
else if(this.renderizr.gecko) { this.renderizr.val = "Gecko" }
};
Also, you have some extra ) inside your else if statements, causing syntax errors. Check a working version here: http://jsfiddle.net/SnKSB/.
I have written some relatively simple jQuery plug-ins, but I am contemplating writing something more advanced in order to keep commonly used methods on the site easily accessible and DRY
For example, I might have something like this for a structure:
plugin
- popup
- element
...
=== popup ===
- login
- product
...
=== element ===
- shoppingCart
- loginStatus
...
So, to bind a popup login popup event, I'd like to be able to do:
$('#login_button').plugin.popup.login();
What's the best way to do this? Is there a better way of achieving what I want to do?
Cheers,
The way farhan Ahmad did it was pretty much right... it just needs deeper levels to suit your needs your implementation would look like this:
jQuery.fn.plugin = function(){
//"community" (global to local methods) vars here.
var selectedObjects = this; //-- save scope so you can use it later
// return the objects so you can call them as necessary
return {
popup: { //plugin.popup
login: function(){ //plugin.popup.login
//selectedObjects contains the original scope
console.log(selectedObjects);
},
product: function(){} //plugin.popup.product
},
element: { //plugin.element
shoppingCart: function() {}, //plugin.element.shoppingCart
loginStatus: function() {} //plugin.element.loginStatus
}
}
}
So now if you call:
$("#someDiv").plugin.login(); the result will be as expected. I hope this helps.
jQuery.fn.messagePlugin = function(){
var selectedObjects = this;
return {
saySomething : function(message){
$(selectedObjects).each(function(){
$(this).html(message);
});
return selectedObjects; // Preserve the jQuery chainability
},
anotherAction : function(){
//...
return selectedObjects;
}
};
}
We use it like this:
$('p').messagePlugin().saySomething('I am a Paragraph').css('color', 'red');
The selected objects are stored in the messagePlugin closure, and that function returns an object that contains the functions associated with the plugin, the in each function you can perform the desired actions to the currently selected objects.