I have this function check(e) that I'd like to be able to pass parameters from test() when I add it to the eventListener. Is this possible? Like say to get the mainlink variable to pass through the parameters. Is this even good to do?
I put the javascript below, I also have it on jsbin: http://jsbin.com/ujahe3/9/edit
function test() {
if (!document.getElementById('myid')) {
var mainlink = document.getElementById('mainlink');
var newElem = document.createElement('span');
mainlink.appendChild(newElem);
var linkElemAttrib = document.createAttribute('id');
linkElemAttrib.value = "myid";
newElem.setAttributeNode(linkElemAttrib);
var linkElem = document.createElement('a');
newElem.appendChild(linkElem);
var linkElemAttrib = document.createAttribute('href');
linkElemAttrib.value = "jsbin.com";
linkElem.setAttributeNode(linkElemAttrib);
var linkElemText = document.createTextNode('new click me');
linkElem.appendChild(linkElemText);
if (document.addEventListener) {
document.addEventListener('click', check/*(WOULD LIKE TO PASS PARAMETERS HERE)*/, false);
};
};
};
function check(e) {
if (document.getElementById('myid')) {
if (document.getElementById('myid').parentNode === document.getElementById('mainlink')) {
var target = (e && e.target) || (event && event.srcElement);
var obj = document.getElementById('mainlink');
if (target!= obj) {
obj.removeChild(obj.lastChild);
};
};
};
};
Wrap your event listener into a function:
document.addEventListener(
'click',
function(e,[params]){
check(e,[params]);
}
);
One solution would be to move the "check" function up inside your test() function. As an inner function, it would automatically be able to refer to variables in its outer scope. Like this:
function test() {
if (!document.getElementById('myid')) {
var mainlink = document.getElementById('mainlink');
var newElem = document.createElement('span');
mainlink.appendChild(newElem);
var linkElemAttrib = document.createAttribute('id');
linkElemAttrib.value = "myid";
newElem.setAttributeNode(linkElemAttrib);
var linkElem = document.createElement('a');
newElem.appendChild(linkElem);
var linkElemAttrib = document.createAttribute('href');
linkElemAttrib.value = "jsbin.com";
linkElem.setAttributeNode(linkElemAttrib);
var linkElemText = document.createTextNode('new click me');
linkElem.appendChild(linkElemText);
if (document.addEventListener) {
document.addEventListener('click', function(e) {
if (document.getElementById('myid')) {
if (document.getElementById('myid').parentNode === mainlink) {
var target = (e && e.target) || (event && event.srcElement);
if (target!= mainlink) {
mainlink.removeChild(mainlink.lastChild);
};
};
};
});
};
What I typically do in this situation is save arguments to the object (whenever it's convenient), and then retrieve them in the function, like this:
// Listener function receives e (the event object) by default.
function eventReceiver(e) {
var obj;
// Find object which triggered the event
e.srcElement ? obj = e.srcElement : obj = e.target;
// obj.someProperty has been set elsewhere, replacing a function parameter
alert(obj.someProperty);
}
This is cross browser, and allows you to pass objects and values through the properties of the event target.
I initially started with the this keyword, but that behaves differently cross-browser. In FF, it's the object that the event was triggered on. In IE, it's the event itself. Thus, the srcElement / target solution was born. I'm interested to see the other solutions though - have a +1.
Related
In Javascript, when I use addEventListener, I would like to call an external method and pass it an event arg:
var secondParam= "titi";
element.addEventListener("keydown", handleEventFunc(event, secondParam));
...
handleEventFunc: function (eventArg, secondParam) {
var key = event.keyCode;
var toto = secondParam;
//do things
}
It would be working equivalent if I were using closure:
var secondParam= "titi";
element.addEventListener("keydown", function (event) {
var key = event.keyCode;
var toto = secondParam;
//do things
}
Do you know how to do this?
This happens automagically if you just reference the function instead of calling it, as any arguments will be passed by the calling context, in this case the event handler
element.addEventListener("keydown", obj.handleEventFunc);
var obj = {
handleEventFunc: function (event) { // tada, now works
var key = event.keyCode; // keep the names the same
//do things
}
}
I want to be able to set a function onbroadcast in SpeechRecognition after I create a new SpeechRecognition object so that I can call this function internally if certain conditions are met.
I would like to be able to set it in the same way that you would set something like onerror in webkitSpeechRecognition. When I look at onerror in the Developer Tools it looks like it might be done via some sort of getter/setter like what is described here but I can't be certain.
Is this possible?
recognition.js:
var SpeechRecognition = function () {
var recognitionObject = new webkitSpeechRecognition();
recognitionObject.onresult = function (event) {
if(event.results.length > 0) {
if (onbroadcast !== null && onbroadcast === 'function') {
onbroadcast('there are results');
}
}
}
recognitionObject.onerror = function (event) {
console.log(event);
}
recognitionObject.onend = function (event) {
console.log(event);
}
recognitionObject.start();
}
SpeechRecognition.prototype.onbroadcast = null;
main.js:
var sr = new SpeechRecognition();
sr.onbroadcast = function(msg) {
document.getElementById('id') = msg;
}
You need to refer to onbroadcast as a property of your instance (this.onbroadcast). It doesn't magically become available as a variable inside the constructor scope.
function SpeechRecognition() {
var self = this; // a reference to the instance
var recognitionObject = new webkitSpeechRecognition();
recognitionObject.onresult = function (event) {
if (event.results.length > 0 && typeof self.onbroadcast === 'function') {
self.onbroadcast('there are results');
// ^ a property access
}
};
recognitionObject.onerror = recognitionObject.onend = function (event) {
console.log(event);
};
recognitionObject.start();
}
I would like to trigger an events without duplicating code. So I decided to create a constructor function (class) and then a new object with a variable that connects to an event handler. Im just testing it but I cant get the if statement to trigger the alert() using this.link it works like this: if(el) but not like this: if(el === this.link)
var faqOne = document.getElementById("faqOne");
var hiddenOne = document.querySelector("p.faqOneHidden");
faqOne.addEventListener("click", function (e) {
showFaqOne.showClickedFaq(e);
}, false);
function DisplayQFaqs(link, faq) {
this.link = link;
this.faq = faq;
}
DisplayQFaqs.prototype.showClickedFaq = function (e) {
var el = e.target;
if (el === this.link) {
alert('hi');
}
};
var showFaqOne = new DisplayQFaqs(faqOne, hiddenOne);
I am facing a cross browser issue while trying to pass an event object from an onclick event.
Currently, I am doing the following
for (var i = 0; i < list.length; i++)
{
var link= list[i];
link.onclick = function(el) { return function () {LinkManager.HandleOnClick(window.event, el); }}(link);
}
Firefox doesn't respect window.event. However, how else can I pass it?
I resorted to a "not" clean solution:
for (var i = 0; i < list.length; i++)
{
var link= list[i];
link.onclick = SomeClickHandler;
}
function SomeClickHandler(e)
{
e = e || window.event;
if (typeof (e) !== 'undefined')
{
var element = e.target || e.srcElement;
LinkManager.HandleOnClick(e, element);
}
}
Can anyone recommend a better way of solving it? I really didn't like the workaround that I did.
If I understand correctly, you want your handler to have access to the el variable and the event object when it's called. That's possible and not that hard, but you might want to read up on closures:
link.onclick = (function(el)
{
return function (e)//this function will receive the event object
{
e = e || window.event;//for ie
LinkManager.HandleOnClick(e, el);
}
})(link);
but, to be honest, this is overkill, try this (pun intended):
link.onclick = function(e)
{//this refers to `link`, the clicked element
e = e || window.event;//for ie
LinkManager.HandleOnClick(e, this);
};
or even less code:
link.onclick = function(e)
{//this refers to `link`, the clicked element
e = e || window.event;//for ie
LinkManager.HandleOnClick.apply(this,[e]);
//LinkManager.HandleOnClick will receive 1 argument, the event object, and 'this' will point to 'link'
};
and even less:
link.onclick = LinkManager.HandleOnClick;//this === link, 1 argument: the event object
That said, you're iterating a list, and attaching an event listener to each individual child element. I'd strongly advise you to use delegaion:
if (list.addEventListener)
{
list.addEventListener('click',LinkManager.HandleOnClick,false);
}
else if (list.attachEvent)
{
list.attachEvent('onclick',LinkManager.HandleOnClick);
}
else
{
//use the loop you have now as a last resort
}
//LinkManager.HandleOnClick should start like so:
LinkManager.HandleOnClick = function(e)
{
e = e || window.event;//<- you have the event object here
var target = e.target || e.srcElement;//=== list item: your link variables, your element
console.log(this);//<-should reference the list element (<ul> || <ol>)
};
Anyway, that's how I'd tackle this
var handler = function (evt) {
// do something here
}
if(window.addEventListener) {
link.addEventListener("click", handler);
} else if(document.attachEvent) {
link.attachEvent("onclick", handler)
}
When users click "search" input element, the search text inside the input will disappear and since I have several controls like that, I thought I could make the code reusable. Here is my code formerly done and working with jQuery but now in YUI I cannot make it work.
var subscriptionBoxTarget = "div.main div.main-content div.side-right div.subscription-box input";
var ssbNode = YAHOO.util.Selector.query(subscriptionBoxTarget);
var ssbValue = YAHOO.util.DOM.getAttribute(ssbNode,"value");
var subscriptionBox = new RemovableText(ssbNode,ssbValue,null);
subscriptionBox.bind();
////////////////////////////////
//target : the target of the element which dispatches the event
// defaultText : the default for input[type=text] elements
// callBack : is a function which is run after everthing is completed
function RemovableText(target,defaultText,callBack)
{
var target = target; //private members
var defaultText = defaultText;
var callBack = callBack;
//instance method
this.bind = function()
{
mouseClick(target,defaultText);
mouseOff(target,defaultText);
if(callBack != null)
callBack();
}
//private methods
var mouseClick = function(eventTarget,defaultValue)
{
var _eventTarget = eventTarget;
var _defaultValue = defaultValue;
/*$(eventTarget).bind("click",function(){
var currentValue = $(this).val();
if(currentValue == defaultValue)
$(this).val("");
});*/
YAHOO.util.Event.addListener(_eventTarget,"click",function(e){
alert(e);
});
}
var mouseOff = function(eventTarget,defaultValue)
{
var _eventTarget = eventTarget;
var _defaultValue = defaultValue;
/*$(eventTarget).bind("blur",function(){
var currentValue = $(this).val();
if(currentValue == "")
$(this).val(_defaultValue);
});*/
YAHOO.util.Event.addListener(_eventTarget,"blur",function(e){
alert(e);
});
}
}
You have a lot of unnecessary code here.
The input parameters passed to the RemovableText constructor are available by closure to all the methods defined inside. You don't need to, and shouldn't redefine named params as vars.
function RemovableText(target, defaultText, callback) {
this.bind = function () {
YAHOO.util.Event.on(target, 'click', function (e) {
/* You can reference target, defaultText, and callback in here as well */
});
YAHOO.util.Event.on(target, 'blur', function (e) { /* and here */ });
if (callback) {
callback();
}
};
}
The definition of an instance method from within the constructor seems dubious, as is the requirement that the values passed to the constructor must be kept private. Just assign them to instance properties (this._target = target; etc) and add instance methods to the prototype. If the functionality you're after is just this simple, then why bother with methods at all?
Using the click event does not support keyboard navigation. You should use the focus event.
I'm not sure why you would have a callback passed at construction that fires immediately after attaching the event subscribers.