Filling array on event and access it outside the event function handler - javascript

I'm trying to fill an array on an event (onclick) with the button's value (there will be different buttons with different values, that's why I'm using an array), and I want to be able to access that array outside the event handler function.
This is what I tried so far, but I just can't figure how to access the array outside the event handler function.
Here's the HTML:
<button value="5"> button </button>
<div> The value is: <span id="res"></span></div>
And here the script:
var n = [];
var val;
var ret;
function add(arr,val) {
arr.push(val);
return val;
}
document.body.addEventListener("click", function(event) {
if (event.target.nodeName == "BUTTON") {
val = event.target.value;
ret = add(n, val);
console.log(n); //these console.log are tests
console.log(ret);
}
console.log(ret); //also this
});
//need to access the array here
console.log(n); //obv doesn't work
console.log(ret); //same
document.getElementById("res").innerHTML = ret; //it remains undefined, obv
I know why this doesn't work (it's because I do all the thing inside the event handler function), but I can't figure it out how to do what I want to do.
Any suggestions?

You need to perform the action you want to perform in the callback, not before. The reason is that none of the code in the event handler runs before the event occurs. Just declaring the variable doesn't change the order of execution.
So you need to put
document.getElementById("res").innerHTML = ret;
inside your event handler function.
Updated (and simplified) code:
var n = [];
document.body.addEventListener("click", function(event) {
if (event.target.nodeName == "BUTTON") {
var val = event.target.value;
n.push(val);
console.log(n); //these console.log are tests
console.log(ret);
document.getElementById("res").innerHTML = val;
}
});

Related

Is there a way to switch between 2 functions onclick so that the first one adds together and a second one subtracts variables?

So basicly I want to make a program that would have 2 inputs and a button in HTML. The first input would be the starter value (stvalue) and the second would be the value added/subtracted (value) and output a sum (sum) that would constantly change.
So when I enter the 2 values (stvalue) and (value) and click the button it would first add them together (sum), and then I would write in a different value (value) to be subtracted on the second click from the added together sum (sum).
And then if I write in another value (value) and click the button the third time, it would add the subtracted sum (sum) and the value I wrote (value) together.
And it would continuosly add/subtract the values I write in to/from the "sum" value on clicks.
I dont know if even there is a way to do this, I tried some versions but they didnt really worked out the way I wanted them.
I managed to make functions switch on click and add the values together but then I wasnt able to use that added together value in the second function where it would be subtraced.
var stValue;
var value;
var sum;
function buttonClick() {
var stValue = parseFloat(document.getElementById("stvalue").value);
var value = parseFloat(document.getElementById("value").value);
var sum = stValue + value;
console.log(sum);
this.onclick = notButtonClick; //function reference to nBC
}
function notButtonClick() {
var value = parseFloat(document.getElementById("value").value);
var sum = sum - value;
console.log(sum);
this.onclick = buttonClick; //function reference to original function
}
var el = document.getElementById("button"); //let for ES6 aficionados
el.onclick = buttonClick; //again, function reference, no ()
<input id="stvalue" type="number" placeholder="kezdo" />
<input id="value" type="number" placeholder="ertek" />
<button id="button" onclick="buttonClick()">Start</button>
I hope I managed to explain it pretty well and its not too confusing.
Thank you for your time, I really appriciate it.
To assign an event handler to an event, and pass parameters along at the time of assignment, execute a function that returns a function, which is then provided as an event handler to the next event assignment. This uses function encapsulation to make the parameters available to the next event execution.
let stValue, value, sum;
function buttonClick (sum, val) {
return function () {
let stValue = (undefined === sum)
? parseFloat(document.getElementById("stvalue").value)
: sum;
let value = (undefined === val)
? parseFloat(document.getElementById("value").value)
: val;
let ret = stValue + value;
console.log(ret);
this.onclick = notButtonClick(sum, val);
}
}
function notButtonClick (sum, val) {
return function () {
let stValue = (undefined === sum)
? parseFloat(document.getElementById("stvalue").value)
: sum;
let value = (undefined === val)
? parseFloat(document.getElementById("value").value)
: val;
let ret = stValue - value;
console.log(ret);
this.onclick = buttonClick(sum, val);
}
}
var el = document.getElementById("button").onclick = buttonClick();
<input id="stvalue" type="number" placeholder="kezdo" />
<input id="value" type="number" placeholder="ertek" />
<button id="button" onclick="buttonClick()">Start</button>

Javascript onclick event not working with variable reference

I am reading some code and trying to replicate the same at my end step by step.
I am attaching an event to a particular button and onclick it should log a statement.
Following is the code that does not work :-
(function(){
var el = function(element){
if(element.charAt['0'] === '#'){
return document.querySelector(element);
}
return document.querySelectorAll(element);
}
var viewer = el('#viewer');
var clear = el('#clear');
console.log(clear);
var clearAll = function(){
console.log('Clearing');
};
//click event
clear.onclick = clearAll;
})();
Above a function is used to get elements.
The below code works
document.getElementById('clear').onclick = clearAll;
or
document.querySelector('#clear').onclick = clearAll;
I do not understand why the above code does not work. Please Help.
"foo".charAt['0'] is undefined because charAt is a function and doesn't have a 0 property.
You need () (to call the function), not [] (to access properties of the object).
You are using charAt as an array while it is a function.
var el = function(element){
if(element.charAt('0') === '#'){
return document.querySelector(element);
}
return document.querySelectorAll(element);
}
See it working https://jsfiddle.net/
Regards,

Validate input on blur [duplicate]

I am using the following code jsFiddle:
function Field(args) {
this.id = args.id;
this.name = args.name ? args.name : null;
this.reqType = args.reqType ? args.reqType : null;
this.reqUrl = args.reqUrl ? args.reqUrl : null;
this.required = args.required ? true : false;
this.error = args.error ? args.error : null;
this.elem = document.getElementById(this.id);
this.value = this.elem.value;
this.elem.addEventListener('blur', this, false);
this.elem.addEventListener('focus', this, false);
}
// FormTitle is the specific field like a text field. There could be many of them.
function FormTitle(args) {
Field.call(this, args);
}
Field.prototype.getValue = function() { return Helpers.trim( this.value ) };
Field.prototype.blur = function (value) {
alert("blur");
};
Field.prototype.focus = function (value) {
alert("focus");
};
Field.prototype.handleEvent = function(event) {
var prop = event.type;
if ((prop in this) && typeof this[prop] == "function")
this[prop](this.value);
};
inheritPrototype(FormTitle, Field);
var title = new FormTitle({name: "sa", id: "title"});
function inheritPrototype(e, t) {
var n = Object.create(t.prototype);
n.constructor = e;
e.prototype = n
}
if (!Object.create) {
Object.create = function (e) {
function t() {}
if (arguments.length > 1) {
throw new Error("Object.create implementation only accepts the first parameter.")
}
t.prototype = e;
return new t
}
}
The problem is that the 'blur' event is fired every time the field is brought to focus, which is opposite of what you'd expect. This is despite the fact that the focus event isn't even mentioned in the code. The problem is that I cannot replicate this problem in jsFiddle but the problem is happening in IE.
Also, on jsFiddle, there is another problem. The focus event is triggered multiple times...
Is there a possible explanation for this and/or a solution?
Updated:
Bonus question (and last on this, promise).
I added a function addEvent to dynamically add events to form fields instead of adding them all directly in the parent constructor. This is the jsFiddle for it. I am trying to call the function but it doesn't seem to work. What might I be doing wrong?
The alert in your focus handler immediately removes focus away from the field as soon as it gains focus. The loss of focus triggers the blur. It is odd that the blur comes first.
If you change the alerts to console.log (or something that does not steal focus), you will see that the events fire correctly.
http://jsfiddle.net/rsKQq/4/

Can I name a JavaScript function and execute it immediately?

I have quite a few of these:
function addEventsAndStuff() {
// bla bla
}
addEventsAndStuff();
function sendStuffToServer() {
// send stuff
// get HTML in response
// replace DOM
// add events:
addEventsAndStuff();
}
Re-adding the events is necessary because the DOM has changed, so previously attached events are gone. Since they have to be attached initially as well (duh), they're in a nice function to be DRY.
There's nothing wrong with this set up (or is there?), but can I smooth it a little bit? I'd like to create the addEventsAndStuff() function and immediately call it, so it doesn't look so amateuristic.
Both following respond with a syntax error:
function addEventsAndStuff() {
alert('oele');
}();
(function addEventsAndStuff() {
alert('oele');
})();
Any takers?
There's nothing wrong with the example you posted in your question.. The other way of doing it may look odd, but:
var addEventsAndStuff;
(addEventsAndStuff = function(){
// add events, and ... stuff
})();
There are two ways to define a function in JavaScript. A function declaration:
function foo(){ ... }
and a function expression, which is any way of defining a function other than the above:
var foo = function(){};
(function(){})();
var foo = {bar : function(){}};
...etc
function expressions can be named, but their name is not propagated to the containing scope. Meaning this code is valid:
(function foo(){
foo(); // recursion for some reason
}());
but this isn't:
(function foo(){
...
}());
foo(); // foo does not exist
So in order to name your function and immediately call it, you need to define a local variable, assign your function to it as an expression, then call it.
There is a good shorthand to this (not needing to declare any variables bar the assignment of the function):
var func = (function f(a) { console.log(a); return f; })('Blammo')
There's nothing wrong with this set up (or is there?), but can I smooth it a little bit?
Look at using event delegation instead. That's where you actually watch for the event on a container that doesn't go away, and then use event.target (or event.srcElement on IE) to figure out where the event actually occurred and handle it correctly.
That way, you only attach the handler(s) once, and they just keep working even when you swap out content.
Here's an example of event delegation without using any helper libs:
(function() {
var handlers = {};
if (document.body.addEventListener) {
document.body.addEventListener('click', handleBodyClick, false);
}
else if (document.body.attachEvent) {
document.body.attachEvent('onclick', handleBodyClick);
}
else {
document.body.onclick = handleBodyClick;
}
handlers.button1 = function() {
display("Button One clicked");
return false;
};
handlers.button2 = function() {
display("Button Two clicked");
return false;
};
handlers.outerDiv = function() {
display("Outer div clicked");
return false;
};
handlers.innerDiv1 = function() {
display("Inner div 1 clicked, not cancelling event");
};
handlers.innerDiv2 = function() {
display("Inner div 2 clicked, cancelling event");
return false;
};
function handleBodyClick(event) {
var target, handler;
event = event || window.event;
target = event.target || event.srcElement;
while (target && target !== this) {
if (target.id) {
handler = handlers[target.id];
if (handler) {
if (handler.call(this, event) === false) {
if (event.preventDefault) {
event.preventDefault();
}
return false;
}
}
}
else if (target.tagName === "P") {
display("You clicked the message '" + target.innerHTML + "'");
}
target = target.parentNode;
}
}
function display(msg) {
var p = document.createElement('p');
p.innerHTML = msg;
document.body.appendChild(p);
}
})();
Live example
Note how if you click the messages that get dynamically added to the page, your click gets registered and handled even though there's no code to hook events on the new paragraphs being added. Also note how your handlers are just entries in a map, and you have one handler on the document.body that does all the dispatching. Now, you probably root this in something more targeted than document.body, but you get the idea. Also, in the above we're basically dispatching by id, but you can do matching as complex or simple as you like.
Modern JavaScript libraries like jQuery, Prototype, YUI, Closure, or any of several others should offer event delegation features to smooth over browser differences and handle edge cases cleanly. jQuery certainly does, with both its live and delegate functions, which allow you to specify handlers using a full range of CSS3 selectors (and then some).
For example, here's the equivalent code using jQuery (except I'm sure jQuery handles edge cases the off-the-cuff raw version above doesn't):
(function($) {
$("#button1").live('click', function() {
display("Button One clicked");
return false;
});
$("#button2").live('click', function() {
display("Button Two clicked");
return false;
});
$("#outerDiv").live('click', function() {
display("Outer div clicked");
return false;
});
$("#innerDiv1").live('click', function() {
display("Inner div 1 clicked, not cancelling event");
});
$("#innerDiv2").live('click', function() {
display("Inner div 2 clicked, cancelling event");
return false;
});
$("p").live('click', function() {
display("You clicked the message '" + this.innerHTML + "'");
});
function display(msg) {
$("<p>").html(msg).appendTo(document.body);
}
})(jQuery);
Live copy
Your code contains a typo:
(function addEventsAndStuff() {
alert('oele');
)/*typo here, should be }*/)();
so
(function addEventsAndStuff() {
alert('oele');
})();
works. Cheers!
[edit] based on comment: and this should run and return the function in one go:
var addEventsAndStuff = (
function(){
var addeventsandstuff = function(){
alert('oele');
};
addeventsandstuff();
return addeventsandstuff;
}()
);
You might want to create a helper function like this:
function defineAndRun(name, func) {
window[name] = func;
func();
}
defineAndRun('addEventsAndStuff', function() {
alert('oele');
});
Even simpler with ES6:
var result = ((a, b) => `${a} ${b}`)('Hello','World')
// result = "Hello World"
var result2 = (a => a*2)(5)
// result2 = 10
var result3 = (concat_two = (a, b) => `${a} ${b}`)('Hello','World')
// result3 = "Hello World"
concat_two("My name", "is Foo")
// "My name is Foo"
If you want to create a function and execute immediately -
// this will create as well as execute the function a()
(a=function a() {alert("test");})();
// this will execute the function a() i.e. alert("test")
a();
Try to do like that:
var addEventsAndStuff = (function(){
var func = function(){
alert('ole!');
};
func();
return func;
})();
For my application I went for the easiest way. I just need to fire a function immediately when the page load and use it again also in several other code sections.
function doMyFunctionNow(){
//for example change the color of a div
}
var flag = true;
if(flag){
doMyFunctionNow();
}

Onclick event handler is executed several times when I click on a link

I have an event handler that is called six times when I click on a link.
var elems = elem.getElementsByTagName('a');
var cntr = 0;
for(var a in elems) {
AttachEvent(elems[cntr], 'click', function(e) {
this.reporturl = this.href;
document.getElementById('reportpopup').style.visibility = "visible";
return false;
});
}
I am using Firefox 3.5 currently so this is used for AttachEvent:
function AttachEvent(obj,evt,fnc,useCapture){
if (!useCapture) useCapture=false;
if (undefined == obj || null == obj)
return;
if (obj.addEventListener){
obj.addEventListener(evt,fnc,useCapture);
return true;
} else if (obj.attachEvent) return obj.attachEvent("on"+evt,fnc);
else{
MyAttachEvent(obj,evt,fnc);
obj['on'+evt]=function(){ MyFireEvent(obj,evt); };
}
}
The this.href value is the same each time, and there are only three links that match my getElementsByTagName.
So, I have attached an event to my link, and when I click on one of the three, it is called six times with the exact same link information.
Any idea why this may be happening?
It looks like you're attaching the same event handler to the 0th item for as many times as there are links.
var cntr = 0;
for(var a in elems) {
AttachEvent(elems[cntr], 'click', function(e) {
^never changes?
Secondly, in JavaScript object members, properties, array elements, etc. are all in the same collection. for(var item in obj) will run once for every available member of obj. If it is an array with 3 elements, it will run once for each element, once for the length property, and once each for... whatever the other two built-in properties are. That's six times total, which is probably not what you want. Use for(var i=0;i<elems.length;i++) for reliability.

Categories

Resources