How to access data object in a HTMLElement without jQuery - javascript

In my web-application, I have binded jQuery keyboard to a textbox. And I want to call keyboard.close() function explicitly on the keyboard since I'm removing all the eventListeners to the textfield at the start.
I can call this function using jQuery, like below.
$('#chat-form').data('keyboard').close();
But I'm not allowed to use jQuery because of some memory issues. Is there anyway that I can access data object in a HTMLElement, without jQuery?
Unfortunately, elem.dataset.keyboard and elem.getAttribute('data-keyboard') is not working as well. but $(elem).data('keyboard') is working fine.

You can use as below;
var elem = document.getElementById('elId');
console.log(elem.dataset.<your-data-attribute-without-data-prefix>)

Related

Is attaching an onchange object a closure?

I have searched prior SO posts here, here and here, and couldn't an answer that made sense to me. This should be a basic question, but I'm not understanding the posts I find. They don't seem to address using a this parameter.
I want to programatically add an input with an onchange event, such that the final result is this:
<input type="button" onchange="handleButtonOnChange(this)">ClickMe</input>
I am working on a project that is using an embedded IE6 browser inside a old Delphi application, so I have to have a solution that is IE6 compatible (yes, IE6 is horrible, but there are reasons I am stuck with it for now).
My initial attempt was this:
var DaySelect = document.createElement("select");
DaySelect.id = ParentID+"-day";
DaySelect.disabled = true;
MonthSelect.onchange="handleDayChange(this);" //<--- not correct
Parent.appendChild(DaySelect);
I then read that the .onchange should be assigned an object, not a string, and one should use this instead:
MonthSelect.onchange=handleDayChange; //<--- '(this)' removed
But it seem to me that this will result in this element (notice the missing this parameter)
<input type="button" onchange="handleButtonOnChange">ClickMe</input>
If I use the line below, instead, won't this make a closure, and the 'this' will refer to the event at the time the object is assigned to the .onchange property, instead of being the event at the time of the change event?
//Does the line below make a closure?
MonthSelect.onchange=handleDayChange(this); //<-- What does 'this' refer to?
I'm a relatively new web programmer, but long time Delphi programmer. Closures still make my head hurt. I appreciate any help in this.
Also, I read here about using addEventListener and the problems with older versions of IE, and the last post on the page provides a work around. But I don't understand how it works.
EDIT -- And what about passing other parameters? It seems that many event handlers will need to have parameters specific for the attached element. It seems that it is just not possible to add a listener with any parameters.
A simple closure if you are creating the elements in JS as you show:
var DaySelect = document.createElement("select");
DaySelect.id = ParentID+"-day";
DaySelect.disabled = true;
MonthSelect.onchange=function(){handleDayChange(DaySelect);};
Parent.appendChild(DaySelect);
Since the function is created inside the scope that you create the element in, the same variables will be available to it.
EDIT:
Additional parameters can be passed with this method, for example, the anonymous function we create and attach as the handler will still have the event object sent to it:
function(e){handleDayChange(DaySelect, e);};
In the event object you will have access to the event target, but in your example the event target and "this" are not the same element, so there would be no way for the handler to know about the DaySelect element.
jQuery makes a lot of event handling much simpler which is one of the reasons many people use it, it also normalizes it's methods between various browsers so you don't have to write multiple versions of the same code (in most cases)

About saving DOM elements in object properties

I want to make an UI object that saves references to DOM objects and also some UI strings, so I can use it all over my code and can handle name changes easily. Kind of like this:
var UI = {
DOMelem0: document.getElementById('imUnique'),
DOMelem1: document.getElementById('imSpecial')
};
However, I think that everytime I would access DOMelem0 (by calling UI.DOMelem0), for instance, I'd be calling the getElementById() function, is that what happens?
Or is it no different than storing the elem in a scoped variable? (Like so: var elem = document.getElementById('cow');)
I'm worried about any performance issues this might cause if I were to have lots of UI elements, although I guess they'd be minimal. Either way, I wouldn't want to be calling the DOM method all the time.
Thanks.
Calling UI.DOMelem0; will not call document.getElementById('imUnique').
document.getElementById('imUnique') is only called when you first create the UI object.

Accept text string instead of element in jQuery plugin

When making a jQuery plugin, is it possible to accept a text string instead of an element?
For example, instead of
$("#someelement").myPlugin();:
$('Some text string').myPlugin();
Also, is it possible to allow multiple parameters?
For example, $('Text here', 'Another text').myPlugin();
I have been researching, and $() seems to be used only for selecting DOM elements. However, it's not possible to not use it. When I tried my test function using just $.myPlugin(); it didn't work.
Therefore, for this kind of thing should I just use a function? Are jQuery plugins only used when targeting a DOM element (ie. the $("p").greenify(); example). Or is it acceptable to use them like a regular function with params?
jQuery "plugins" are just prototypes on the jQuery object. So when calling the constructor like $('text') it actually "does" something with the argument text (jQuery will treat this as a selector).
If you just want to create a "plugin" for manipulating text, here a simple one for you:
myPlugin('Text here', 'Another text');
Or you can extend the String prototype if you fancy:
String.prototype.myPlugin = function(suffix) {
return this+suffix
};
'mytext'.myPlugin('.com') // -> mytext.com
you can design your plugin to accept a string as parameter...
and then use it on a jquery selection
$('#myid').myPlugin('some text');
or even just as a regular function
myPlugin('some text');
I don't understand your question - what do you want to do exactly?
If you want to call just the plugin without selecting a DOM node, most jquery extensions register themselves to $.fn:
$.fn.my_pluginname
some possibilities to call it on an element:
$('#my-css-id').myPlugin();
$('<div class="justCreatedNow">content</div>').appendTo('body').myPlugin();

CKEditor how do I get a UIElement

I need to have two select menus in a CKEditor dialog, with the second select menu changing its options according to the selected option of the first menu. Simple enough you would think! But in CKEditor it seems really difficult to obtain the DOM equivalent of the CKEditor object. I can access the CKEditor Object but not its DOM equivalent(s).
The instance of the CKEditor select (UIElement) object has some useful DOM interactions i.e. getElement() but I can only access this object with the special this keyword within an event method within a CKEditor select "class" definition.
How can I access the instance of the CKEditor UIElement object (in this case the select)? I only have the id of the CKEditor object, CKEditor for some frustrating reason decides to apply random ids to its DOM object equivalents.
The instance object I am trying to access is documented here: (No mention of how to obtain this instance though!)
http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.ui.dialog.select.html
In fact the CKEDITOR.dialog.getCurrent() method will allow you to access the Dialog instance from any function, and from there you can access the UIElement instance of any CKEditor object you're after.
Can you cache what you need in the setup callbacks during your dialog's initialization?
You can pass the setup functions an object and they could put what they need in there. So you'd pass an object into your setup stuff:
onShow: function() {
//...
this.cachedDomIds = { };
this.setupContent(this.cachedDomIds);
//...
}
And then in your setup:
setup: function(cache) {
//...
cache.some_dom_id = this.domId;
//...
}
Then at least you'd have access to all the real DOM id attributes and you could getElementById() as needed.
Thanks for the suggestion mu is too short,
I found I could access the other select menus by using this method:
this.getDialog().getContentElement([insert_dialog_name_here], this.getValue()).getElement()
this.getValue will have the same id of the CKEditor UI element I'm after

Save and restore "onclick" action on jQuery objects

I want to disable a whole bunch of objects on the page, and then re-enable them later. Since some of them are tags rather than buttons, I disable them by removing their onclick attr. I've tried to store the old handler in a .data(), but unfortunately when I attempt to restore them with $(obj).attr('onclick',$(obj).data('onclick')), it calls the function rather than restoring it to the attribute. And if I try to store it in a different attribute instead of a data, it doesn't store the function, it stores the return value for the function.
Is there any way to accomplish this without re-writing every tag and every onclick handler on my page?
if( doEnable) {
$(obj).attr('href', $(obj).data('href'));
$(obj).attr('onclick', $(obj).data('onclick'));
$(obj).removeClass(EIS.config.classes.disabled);
$(obj).show();
}
else {
// Save the things you're going to remove
$(obj).data('onclick', $(obj).attr('onclick'));
$(obj).data('href', $(obj).attr('href'));
$(obj).prop("href", null);
$(obj).prop("onclick", null);
$(obj).addClass(EIS.config.classes.disabled);
$(obj).show();
}
By the way, this code seems to work fine in Chrome and Firefox, but only sometimes in IE8 and never in IE6. Unfortunately the client tests first in IE6.
$(obj).attr('onclick', ...
is ambiguous, has results that differ in different versions of jQuery and different browsers. It probably doesn't do what you want. You should avoid using attr on event handlers.
The problem is the disconnect between the onclick attribute and the onclick property. jQuery has tried to brush the difference between an attribute and a property under the carpet in the past, using attr to access both, but they're quite different. This was changed in jQuery 1.6, and partially reverted in 1.6.1, to widespread controversy, confusion and incompatibility.
For many properties, the values of an attribute and the corresponding DOM property are the same; for others, including all properties that aren't strings, they aren't. Event handlers certainly aren't: the property is a Function object, whereas the string attribute might be (a) the original string of the onclick="..." attribute in the HTML, (b) nothing (if the onclick was assigned from script to be a Function object) or (c) unavailable (in older IE).
To access the event handler Function property, use prop() in jQuery 1.6:
$(obj).data('onclick', $(obj).prop('onclick'));
...
$(obj).prop('onclick', $(obj).data('onclick'));
or just use plain old JavaScript which is actually simpler and more readable; jQuery wins you nothing here.
obj._onclick= obj.onclick;
...
obj.onclick= obj._onclick;
Either way this is not going to reliably ‘disable’ elements since they can (and very likely will, if you're using jQuery) have other event listeners registered on them, using addEventListener/attachEvent rather than the old-school event handler interfaces.
It looks like saving a function via .data() works just fine:
var f1 = function() { console.log('invoked'); };
$('a').data('func', f1)
var f2 = $('a').data('func'); // 'invoked' is not printed
f1 === f2 // true
so how are you storing the function via .data? if you're doing something like
a = $('a');
a.data('onclick', a.click()); // click handler is invoked here
then you're actually invoking the click handler(s) prematurely, and storing the return value with .data().
--edit--
it appears that .attr(function) invokes the passed function. This is a feature of jQuery. I'd suggest using jQuery's .click() method to attach the function as a click handler.
a = $('a');
a.each(function() {
this.data('onclick', handler_fn);
this.bind('click', handler_fn);
});
// later
a.each(function() {
this.unbind('click');
});
// even later
a.each(function() {
this.bind('click', this.data('onclick'));
});
What about binding the event in jQuery instead of setting the onclick attribute?
$(obj).click($(obj).data('onclick'));
Can we see the code that you use to set the data attribute?

Categories