Using 'this' inside a link generated by a javascript object - javascript

Javascript is pretty shaky for me, and I can't seem to find the answer to this. I have some code along the lines of
var Scheduler = function(divid,startDate,mode){
this.setHeader = function(){
header.innerHTML = 'Show';
}
this.showScheduler = function period(){
...
}
};
My problem is, how do I put the onclick into the HTML so that it properly calls the showScheduler function for the appropriate instance of the current scheduler object that I'm working with?

I wouldn't do whatever it is you're doing the way you're doing it, but with the code the way you have it, I would do this (lots ofdo and doing :) ):
var Scheduler = function(divid, startDate, mode){
var that = this;
this.setHeader = function(){
header.innerHTML = 'Show';
header.firstChild.onclick = function() { that.showScheduler(1); };
}
this.showScheduler = function period(){
...
}
};

You should use a framework for this type of thing. If you don't use one then you gotta declare each instance of schedular as a global object, and you will need the name of the instance in order to call it from the link. Look at the following link
http://developer.yahoo.com/yui/examples/event/eventsimple.html
They only show a function being applied, but you can also do something like this
YAHOO.util.Event.addListener(myAnchorDom, "click", this.showScheduler,this,true);
Where myAnchorDom is the achor tag dom object. This will have showScheduler function execute within the scope of your scheduler object.

Instead of working with innerHTML use the DOM methods.
Try replacing this:
header.innerHTML = 'Show';
with this:
var x = this; // create a closure reference
var anchor = document.createElement('a');
anchor.href= '#';
anchor.innerHTML = 'Show';
anchor.onclick = function() { x.showScheduler(1); }; //don't use onclick in real life, use some real event binding from a library
header.appendChild(anchor);
Explanation:
The "this" in the original code refers to the element which fired the event, i.e. the anchor ("this' is notoriously problematic for things like, well, like this). The solution is to create a closure on the correct method (which is why you have to create something like the var x above) which then only leaves the problem of passing in the parameter which is accomplished by wrapping the method in another function.
Strictly speaking it would be much preferable to bind eventhandlers with the addEventListener/attachEvent pair (because direct event assignment precludes the ability to assign multiple handlers to one event) but it's best handled using a library like jquery if you're new to JS anyway.

You can add an event handler to the header object directly:
var me = this;
this.setHeader = function(){
header.innerHTML = 'Show';
header.addHandler("click", function(e) { me.showScheduler(1); });
}
Insite the passed function, this will refer to the header element.

var Scheduler = function(divid, startDate, mode)
{
var xthis = this;
this.setHeader = function()
{
var lnk = document.createElement("a");
lnk.addEventListener("click", xthis.showScheduler, false);
lnk.innerText = "Show";
lnk.setAttribute('href', "#");
header.appendChild(lnk);
}
this.showScheduler = function period(){
...
}
};

When using "this" inside the onclick attribute, you're actually referring to the anchor tag object. Try this and see if it works:
this.setHeader = function(){
header.innerHTML = 'Show';
}

Related

Swapping hardcoded arguments for variables

I've got a functional script on my site that allows me to open a link in a new window when a specific class is added to the link. I need a lot of those on my site though so I figured I'd make the script a bit easier to edit by working with variables.
In the process of changing out hardcoded strings for variables my script stopped working though. The only one that works is the var where I set the url.
I'm learning that ${} doesn't work everywhere. Hope that someone can point out where my thinking is wrong. Also hope that I got the terminology right, trying to learn though! :-)
var function1Name = "test_function";
var function1Url = "https://www.google.com";
var function1Class = ".test_function_class";
function ${function1Name}() {
window.open(function1Url, "_blank", "height=200");
}
jQuery("${function1Class}").click(function(){
${function1Name}()
});
None of your uses of ${} are valid JavaScript syntax.
Your function declaration van be replaced with:
window[function1Name] = function () {
window.open(function1Url, "_blank", "height=200");
}
Please note that the function will no longer be hoisted when declared this way, so order of operation matters.
The click handler can be written as follows:
jQuery(function1Class).click(function() { // Note that I just used the variable there.
window[function1Name]();
});
There is a ${} concept in JavaScript, but that is only in template literals:
const myVariable = "Foo";
const message = `myVariable contains: "${myVariable}"!`;
console.log(message);
There's several syntax issues here.
Firstly, function ${function1Name}() is not valid syntax. Function names must be defined before runtime. If you want to dynamically access a function, place it in an object and set the key with the variable reference.
Secondly, ${function1Name}() is again not valid syntax. You cannot invoke a function like that dynamically. Referring to the suggestion above, you can access an object dynamically so the first point fixes this problem.
Thirdly, string interpolation only works within template literals, so you need to delimit the string with backticks: ``. However it's completely redundant here as you can just use $(function1Class)
With those issues in mind, here's an updated example:
var function1Name = "test_function";
var function1Url = "https://www.google.com";
var function1Class = ".test_function_class";
var funcObj = {
[function1Name]: function() {
console.log(`function called, window would open here containing ${function1Url}...`);
// window.open(function1Url, "_blank", "height=200");
}
}
$(function1Class).click(function() {
funcObj[function1Name]()
});
/*
alternative using a template literal, although note that it's redundant here
$(`${function1Class}`).click(function() {
funcObj[function1Name]()
});
*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Click me
One last thing to note is that no version of IE supports template literals, so be sure of your browser support requirements before using them.
So cool, I got it to work!
var function1Name = "test_function_1";
var function1Url = "https://www.google.com";
var function1Class = ".test_function_class1";
var function2Name = "test_function_2";
var function2Url = "https://www.cnn.com";
var function2Class = ".test_function_class2";
// Function 1
window[function1Name] = function () {
window.open(function1Url, "_blank", "toolbar=no,status=no,scrollbars=yes,resizable=yes,top=500,left=500,width=600,height=745");
}
jQuery(function1Class).click(function() {
window[function1Name]();
});
// Function 2
window[function2Name] = function () {
window.open(function2Url, "_blank", "toolbar=no,status=no,scrollbars=yes,resizable=yes,top=500,left=500,width=600,height=745");
}
jQuery(function2Class).click(function() {
window[function2Name]();
});
I can now add a bunch of url's and corresponding classes as was my intention. Super happy about that.
A follow up question though, as I'll have to experiment with what the ideal window parameters will be I'm trying to make those arguments variables as well. I've tried the examples of how to insert a variables output from the functional code but those methods don't work there. Here's that code:
var windowWidth = 250
var function1Name = "test_function_1";
var function1Url = "https://www.google.com";
var function1Class = ".test_function_class1";
var function2Name = "test_function_2";
var function2Url = "https://www.cnn.com";
var function2Class = ".test_function_class2";
// Function 1
window[function1Name] = function () {
window.open(function1Url, "_blank", "toolbar=no,status=no,scrollbars=yes,resizable=yes,top=500,left=500,width=[windowWidth],height=745");
}
jQuery(function1Class).click(function() {
window[function1Name]();
});
// Function 2
window[function2Name] = function () {
window.open(function2Url, "_blank", "toolbar=no,status=no,scrollbars=yes,resizable=yes,top=500,left=500,width=600,height=745");
}
jQuery(function2Class).click(function() {
window[function2Name]();
});
How would I insert the variables value (2nd line of Function1) there ?

Module pattern in JavaScript

I'm practicing my JS skills (I'm new at it). I'm trying to get the specific element that triggered the event and display it in a span element. But I don't know what I'm doing wrong, when I click the button nothing happens.
This is for a calculator program that I'm doing but using module pattern I think it's called.
var Calculator = {
init: function(){
var button = document.querySelectorAll("[class^='button']");
button.onclick = this.writeEvent;
},
write: function (element){
document.getElementById("display").innerHTML = element;
},
writeEvent: function(event){
write(target.event)
}
}
Calculator.init();
There are several problems with the posted code.
var button = document.querySelectorAll("[class^='button']");
button.onclick = this.writeEvent;
The result of querySelectorAll is a NodeList.
Assigning to its onclick property will not achieve what you want.
You want to assign to the onclick property of each individual node.
But actually that's not so simple, we'll need to come back to this.
writeEvent: function(event){
write(target.event)
}
One problem here is that target is undefined.
Surely you meant event.target.
Another problem is that write is also undefined.
Perhaps you meant this.write,
but that won't actually work well.
The problem is that when writeEvent is called from a click event,
it won't be called on the object,
so this will not be bound to the calculator object,
and the this.write call will raise an exception.
There's a way to overcome this,
by binding the onclick handler function to the object when setting it.
Putting the above together:
var Calculator = {
init: function() {
var nodeList = document.querySelectorAll("[class^='button']");
var callback = this.writeEvent.bind(this);
nodeList.forEach(item => item.onclick = callback);
},
write: function(element) {
document.getElementById("display").innerHTML = element;
},
writeEvent: function(event) {
this.write(event.target);
}
}
Calculator.init();

Javascript - Using a string to prototype functions

So I am a super JS noob, I am not even sure I am asking this question properly, but...
I am trying to dynamically create buttons, then set their onclick event listeners to one of a set of predetermined functions. I want to be able to do this one of two ways, as follows:
var newInput = document.createElement('input');
newInput.parameters = "xyz";
document.getElementById("element").appendChild(newInput);
newInput.onclick = "funcsnip" + array[variable] + "()";
Or, alternatively,
var newInput = document.createElement('input');
newInput.parameters = "xyz";
document.getElementById("element").appendChild(newInput);
newInput.onclick = array[variable];
Where the array is stocked with "myFunction()" primitives.
I have no doubt there are a million things I "should" be doing, but I am happy with the majority of my code, I just want to know basically how to pass a string as a parameter for onclick, if that is possible.
Or, if it is not possible, another way to attach an onclick event to a dynamic input element.
Simpler and more elegant, the better. Thank you!
You can't pass a string to onclick listener. It should be a function. What you can do alternatively is to create a map of functions.
Let's say you have these functions available:
function oneFunc() { console.log('one');
function twoFunc() { console.log('two');
Then you can create a mapping:
var map = {
one : oneFunc,
two : twoFunc
};
So you can access oneFunc by calling map.one or map["one"].
Now solving your problem is straightforward
var newInput = document.createElement('input');
var variable = "one";
// var variable = "two";
newInput.parameters = "xyz";
document.getElementById("element").appendChild(newInput);
// You pass an actual function, but using a string parameter.
newInput.onclick = map[variable];
When you click a button, you will see "one" in the console.
If you have a string for every button that represents a function, you can write
var functionCollection = {
'stringOne': function() {
...
}
}
...
newInput.onclick = functionCollection[myStringValue];
or you could create one handler function and invoke it with the string type through binding, e.g.
function clickHandler(stringValue) {
switch (stringValue) {
case 'stringOne':
return someSpecialFunction();
...
}
}
...
newInput.onclick = clickHandler.bind(this, myStringValue);
Both newInput.setAttribute("onclick", "alert(1)") and newInput.setAttribute("onclick", "function() {alert(1) }" will work. Your code doesn't work because you're trying to set a function string on the onclick property, which expects a true function object.
Having said that, you really should use addEventListener, or an abstraction like jquery's on.

JS method binding with 2 different this

I have this small code:
ScenesController.prototype.viewAction = function() {
this.flash = this.di.HelperFlash.hasSupport();
this.$playerElem = !this.flash? $('#html_player') : $('#flash_player');
// the first click is just a sample, I need the same object in the Quailty Change method
$('.scenes_view_video_quailty').on('click', function() { echo($(this));});
$('.scenes_view_video_quailty').on('click', this.viewVideoQuailtyChange.bind(this));
};
ScenesController.prototype.viewVideoQuailtyChange = function(e) {
e.preventDefault();
if (!this.flash) {
echo(this);
echo($(this));
}
};
When I'm clicking the link, I would need pass 2 this variable to the QualityChange method. One with the object (in the bind) and the other is the click event, because I need the clicked element too.
I was trying with the .on('click', {$this: $(this)}, this.method) solution, but dosen't work, the evend.data.$this looks a different object.
I need the same object as I have in the first click method.
(echo = console.log)
Alias the this that refers to the current instance as something else (traditionally, self) and use this to refer to the clicked element
ScenesController.prototype.viewAction = function() {
var self = this;
this.flash = this.di.HelperFlash.hasSupport();
this.$playerElem = !this.flash? $('#html_player') : $('#flash_player');
$('.scenes_view_video_quailty').on('click', function() { echo(self, $(this));});
};
To call a method setting it's this reference you would use Function.apply, for example:
$('.scenes_view_video_quailty').on('click', function(){
self.viewVideoQuailtyChange.apply(self, [$(this)])
});
You can attach any number of variables with bind
You could have a proper method like:
ScenesController.prototype.viewVideoQuailtyChange = function(secondThis) {
}
then use the bind as:
this.viewVideoQuailtyChange.bind(this, $(this));
With this solution you do lose the event though, so it might need some more thought. I'll look into it and update the answer :)

How to pass parameters to a function declared like left = function()

How can I pass parameters to a function declared like something = function(){};
window.prototype.initInterface = function(){
this.mainPane = document.createElement('div');
this.mainPane.style.border="5px solid grey";
this.mainPane.style.margin="0px";
this.mainPane.style.width="420px";
this.mainPane.style.height="600px";
this.exitButton = document.createElement('input');
this.exitButton.setAttribute("type", "button");
this.exitButton.setAttribute("value", "exit");
this.exitButton.onclick = function(){
document.body.removeChild(this.mainPane);
};
this.mainPane.appendChild(this.exitButton);
document.body.appendChild(this.mainPane);
}
When the user presses the exit button I want to remove the mainPane from the body of the html page.
this.exitButton.onclick = function(this.mainPage){
document.body.removeChild(this.mainPane);
};
Does not work
How can I do this?
For your exitButton.onclick function to have access to variables you create in the enveloping initInterface function you want a to create a closure in the exitButton.onclick function by returning a function that performs the action you want and passing that the variable.
exitButton.onclick = function () {
return (function() {
document.body.removeChild(mainPane);
})(mainPane);
};
Read more on how closures work here and here and see a working example fiddle.
Alternatively, you forget about closures and walk up the DOM from the button which triggers the event to your mainPane
exitButton.onclick = function() {
// in here "this" is the object that triggered the event, exitButton
document.body.removeChild(this.parentNode);
}
As an aside, window.prototype does not exist if you are doing this in a browser; window is the object at the top of prototype chain in browser scripting. You want just window.initInterface = function () {} which is the exact same thing as function initInterface() {} because everything you do in javascript in the browser becomes a property of window.
This function is the function w/o function name. It could only be used once and you may not easy to find out what parameters should be passed.
You can create another function like :
function go(a1){}
And call it like window.prototype.initInterface = go(a1);
Or you can get some DOM parameters in this unnamed function by using functions like getDocumentById("DOM ID") etc.

Categories

Resources