Javascript variable using jquery to find variable - javascript

i made a fiddle with buttons. Now in the javascript, I'm trying to learn jquery and by doing so I'm converting old fiddles into jquery from javascript however I know how.
My problem is that in my function called init, I can't figure out how to convert the javascript way of get an html element with an id stored in a variable.
Old code in javascript:
var but = document.getElementById("but");
New code in jQuery:
var but = $('#but');
I think the problem is that I start with a javascript statement but then use jQuery. I don't know what to do in terms of variables in jQuery.

You need to add in [0] to your jquery code to get the document element, but that is rather pointless with the jquery method of adding event listeners. I would suggest either $('#but').mouseout(etc) or $('#but').on('mouseout', etc).
I've updated your jsfiddle to work as expected, though I'll attempt to give a short tut here:
There are two methods of adding event listeners you should familiarize yourself with per the jquery documentation; the .on() method, and the .(event)() method. The latter you can add to jquery ojects in lieu of object.(eventName)() as an example, adding the click handler to an object: object.click(function() { console.log('executed'); });
This method however is not 'live' it will not update itself if the elements are added dynamically, and the events are only attached when the document is ready($(document).ready(function() { do stuff });). In order to attach events to dynamically added elements, we need the .on() method.
Take for example the following html:
<div class="wrapper">
<span class="dynamically_added">stuff</span>
</div>
In order to attach an event listener to the dynamically added span, in your jquery, add the following:
$(".wrapper").on('click', '.dynamically_added', function() {
console.log('executed');
});
The first parameter of .on() is(are) the event(s). You can attach multiple events by delimiting them with spaces: .on('click hover'). The second parameter is either the function to execute, or the targeted element. In the case of the above example it is the span. The last parameter is of course the function to execute. As far as I am aware, you need to have an anonymous function to refer to the function to execute, instead of simply writing it there.
I hope this has helped.

$('#but') returns a jQuery object, not a DOM object. You can either call jQuery methods on that or you can get the DOM object out of it, but you can't use DOM methods directly on it. If you want the DOM object out of it, you can get it with:
$('#but')[0]
And, your method would be this:
function init() {
var but = $('#but')[0];
but.addEventListener("mouseover", butResult, false);
but.addEventListener("mouseout", reverse, false);
var button = $('#button')[0];
button.addEventListener("mouseover", buttonResult, false);
button.addEventListener("mouseout", reverse, false);
}
Or, instead of using native DOM methods, you can use jQuery methods on the jQuery object.
function init() {
$('#but').on("mouseover", butResult).on("mouseout", reverse);
$('#button').on("mouseover", buttonResult).on("mouseout", reverse);
}

Not sure if I understand you ? completely, but, is this what you're roughly looking for:
var b1 = document.getElementById('button');
var b2 = $(b1);
b2.click( function(){
alert('hi');
})

Related

TypeError: elem.addEventListener is not a function

At some place I have a code elem.addEventListener(event, listener, false);
The above code works for
this.buttonBar = doc.getElementsByClassName("wmd-button-bar" + postfix)[0]
But when I change to
this.buttonBar = $('.wmd-button-bar').first();
It does not work. In whole html code I have only one wmd-button-bar class.
The reason why it's not working is because $('.wmd-button-bar').first(); (which equals to $('.wmd-button-bar').eq(0)) returns the first jQuery wrapped instance.
Therefore you should use jQuery's own API for adding the listener.
However, if you want to receive a first DOM element from collection, you should use
$('.wmd-button-bar').get(0);
This will return first element from the jQuery wrapped collection as a DOM element.

How to copy a DOM node with event listeners?

I tried
node.cloneNode(true); // deep copy
It doesn't seem to copy the event listeners that I added using node.addEventListener("click", someFunc);.
We use the Dojo library.
cloneNode() does not copy event listeners. In fact, there's no way of getting hold of event listeners via the DOM once they've been attached, so your options are:
Add all the event listeners manually to your cloned node
Refactor your code to use event delegation so that all event handlers are attached to a node that contains both the original and the clone
Use a wrapper function around Node.addEventListener() to keep track of listeners added to each node. This is how jQuery's clone() method is able to copy a node with its event listeners, for example.
This does not answer the question exactly, but if the use case allows for moving the element rather than copying it, you can use removeChild together with appendChild which will preserve the event listeners. For example:
function relocateElementBySelector(elementSelector, destSelector) {
let element = document.querySelector(elementSelector);
let elementParent = element.parentElement;
let destElement = document.querySelector(destSelector);
elementParent.removeChild(element);
destElement.appendChild(element);
}
Event Delegation example.
After reading Tim Down's answer, I found delegated events are very easy to implement, solving a similar problem I had. I thought I would add a concrete example, although it's in JQuery not Dojo.
I am re-skining an application in Semantic UI, which requires a small piece of JS to make the message close buttons work. However the messages are cloned from an HTML template tag using document.importNode in a library. This meant even if I did attach the event handlers to the template in the new HTML, they are lost during the cloning.
I cannot do Tim's option 1, to simply re-attach them during cloning as the messaging library is front-end framework agnostic. (Interestingly my previous front-end was in Zurb Foundation which uses a "data-closable" attribute, the functionality of which does survive the cloning process).
The normal event handling suggested was like this:
$('.message .close').on('click', function() {
$(this)
.closest('.message')
.transition('fade');
});
The problem being ".message" at app-load only matches the single template, not the actual messages which arrive later over web-sockets.
Making this delegated, meant attaching the event to the container into which the messages get cloned <div id="user-messages">
So it becomes:
$('#user-messages').on('click', '.message .close', function() {
$(this)
.closest('.message')
.transition('fade');
});
This worked immediately, saving any complex work like the third option of wrapping the event subs.
The Dojo equivalent looks pretty similar in concept.
This is what #JeromeJ was describing in a comment. Create the initial element using this HTML code.
<DIV ONCLICK="doSomething(this)">touch me</DIV>
When you clone this element the result will have the same handler, and "this" will point to the cloned element.
It would be great if the ONCLICK handler could easily be added in JavaScript. This approach means that you have to write some of your code in HTML.
I know I'm late to the party but this a solution that worked for me:
const originalButtons = original.querySelectorAll<HTMLElement>('button');
const cloneButtons = clone.querySelectorAll<HTMLElement>('button');
originalButtons.forEach((originalButton: HTMLElement, index: number) => {
cloneButtons[index].after(originalButton);
cloneButtons[index].remove();
});
Only inline attributes would work here which are heavily, heavily discouraged because of how misused they are. That said, you can have elements bind to the same event listener.
The proper way with Web Components (and shadow root) would look like and what we would want to replicate:
static onButtonClick(event) {
const { host } = this.getRootNode();
console.log('onButtonClick', { event, host, this: this });
}
/* Or constructor */
connectedCallback() {
this.myShadowRoot.getElementById('button')
.addEventListener(MyElement.onButtonClick);
}
It's efficient because you don't create function per element like you would with .addEventListener(() => this.onButtonClick). 1000 buttons would attach to the same function instead of creating a new function per button.
To convert that to inline would look like this:
<button onclick="this.getRootNode().host.constructor.onButtonClick.call(this, event)">
Is it ugly? Yes. But does it work? Also, yes. In this case there's no need for JS to have find the element and instruct the browser to create an event handler. The inline onclick does that for you. I will note that are creating a new function for each and every element, instead of them all sharing one.
Cloning a node copies all of its attributes and their values, including intrinsic (inline) listeners. It does not copy event listeners added using addEventListener() or those assigned to element properties (e.g., node.onclick = someFunction). Additionally, for a element, the painted image is not copied.
source: MDN (https://developer.mozilla.org/en-US/docs/Web/API/Node/cloneNode).

How can I dynamically change css for html that is generated by javascript at runtime?

I have some html that is generated programmatically using javascript at runtime.
I want to be able to dynamically change the css properties of this html
e.g.
$(".pointsbox").css("background-color","green");
but it appears to not work as those html elements are not available at the time that the css change is called.
I am pretty sure I have managed to do this before but I've forgotten what the function is called.
Any help much appreciated!
You haven't posted code on how exactly you create your HTML elements, but it can be something as simple as this:
You can create an HTML element by passing HTML into the jQuery function right?
var new_element = $('<div>');
Well, you can treat that like any other jQuery object, and just manipulate its CSS right then and there.
var new_element = $('<div>').css('background-color', 'green');
Heck, you can even chain the create, the css change and the DOM insert in one call.
var new_element = $('<div>')
.css('background-color', 'green')
.appendTo('#container')
;
There are the Mutation events - specifically the DOMNodeInserted event - that you could bind an event handler to. However, as the page I linked states, it's recommended that you don't because it has a serious negative effect on the performance of your page and the cross-browser support isn't particularly good.
An alternative is to simulate your own DOMNodeInserted event using a custom event. Essentially you bind a handler for a custom event (say nodeinserted) on the document, then trigger that event whenever you have code that dynamically modifies the structure of your page. Code might look something like the following:
$(document).on('nodeinserted', function() {
$('.pointsbox').css('background-color', 'green');
});
function modifyPage() {
// code to modify your page here
$(document).trigger('nodeinserted');
}
Note that, with this approach, you'll need to modify all functions that add elements to the page to trigger that nodeinserted custom event.
I use this. It ensures the DOM has loaded.
$(document).ready(function(){
//code here
$(".pointsbox").css("background-color","green");
});

jquery onclick is not working

I am dynamically creating a link, and I am trying to add a click function to it. The links are being added, but the click function is not working. I dont see anything in the console, nor do I get an alert.
var section = $('<section></section>').append('<a class="link" href="#"></a>');
section.find('a.link').attr('title', post.data.permalink)
.text(post.data.title)
.click(function()
{
console.log("function");
alert("hi");
getThread(post.data.permalink);
});
items.push(section[0].outerHTML);
$('#posts').empty().append(items.join(''));
One of the most common mistakes with jQuery. When dynamically adding elements, normal jQuery event handlers don't work, so you need to use .live() to be able to bind events to dynamic elements. This should work:
var section = $('<section></section>').append('<a class="link" href="#"></a>');
section.find('a.link').attr('title', post.data.permalink)
.text(post.data.title)
.live("click", function()
{
console.log("function");
alert("hi");
getThread(post.data.permalink);
});
items.push(section[0].outerHTML);
$('#posts').empty().append(items.join(''));
Notice the use of .live("click", function() { ... }); there? That should solve your problem.
That looks okay. You may try using each() to iterate over that collection. I'm not sure if you can bind even handlers to a jQuery collection like that.
section.find('a.link').each(function(){
$(this).attr('title', post.data.permalink)
.text(post.data.title)
.click(function()
{
console.log("function");
alert("hi");
getThread(post.data.permalink);
});
});
If running this in IE be sure that developer-tools (F12 )are present , otherwise console will be undefined and the call of console.log() will force an error and stops the function from executing.
What else: outerHTML is IE-only, you'll better forget it and never use it.
You don't need to manually join the HTML.
You're binding the event to an element, then taking the HTML of that element and just concatenting it into a string, which is then in turn inserted into the DOM as new elements when you append to #posts.
items is not defined here, but I'm going to go out on a limb and assume it's an array of generated <section>s and etc?
If that's the case, I might be missing something you're trying to do here, but it seems you could just eliminate the whole concatention of HTML and simply append the items array, which would preserve the bound click event.
// Push the element, don't stringify it.
items.push(section);
// Then simply append the "items" elements.
$('#posts').empty().append(items);
Sure, live would probably solve the problem as well, but you certainly can bind events to generated elements then insert them into the DOM. What you cannot do is bind an event to an element then print out it's HTML and insert that into the DOM. Any binding you made with the original element is lost.

Using JQuery to get string value of an onclick() event

Wondered if there was good way to do this, thought I would post to the SO community...
There is a 3rd party web page that I have no control over how it renders, but they allow me to add JQuery.
Using the JQuery, I am creating a nav menu on the side of the page, it will be a list of links. The onclick event of these links I get from existing onclick events already on the page, but when I do a:
var linkLoc = $('#theLink').attr("onclick");
linkLoc returns:
function onclick(event) {
handleJumpTo("com.webridge.entity.Entity[OID[E471CB74A9857542804C7AC56B1F41FB]]", "smartform");
}
instead of what I would expect:
handleJumpTo("com.webridge.entity.Entity[OID[E471CB74A9857542804C7AC56B1F41FB]]", smartform");
I think JQuery is trying to get the event for binding, but I need the actual Javascript markup since I'm creating the HTML dynamically. I guess I could substring the "function onclick(event) {" out, but seems kind of hacky.
Any ideas of an elegant way I could get the onclick markup?
$("#theLink") would return a jQuery object whereas $("#theLink")[0] would give a DOM object. This is a resson that $("#thelink")[0].getAttributeNode('onclick').value would work.
The type of $('#theLink').attr("onclick") is a function, so you can just use that when you bind events to the links.
var linkLoc = $('#theLink').attr("onclick");
$('a#link1').live('click', linkLoc);
Example: http://jsfiddle.net/BdU6f/
You can also run other code in the click handler too, if you need:
var linkLoc = $('#theLink').attr("onclick");
$('a#link1').live('click', function(e){
// Code...
linkLoc(e);
});
Example: http://jsfiddle.net/BdU6f/1/
The "onfoo" attributes have values that are functions, not strings. The semantics of:
<whatever onclick='code code code'>
are that the browser constructs a function object as if you had code that did this:
document.getElementById('whatever').onclick = new Function("event", "code code code");
Thus you don't really need the raw string, since you've got something better: the function itself, ready to be called. You can then bind it as a handler to other elements via JavaScript code, not HTML (which is really a better way to do things anyway). You're using jQuery, you say, so you can use the jQuery ".bind()" API to bind those functions to whatever elements you need.
You should also be aware that there are other ways of binding event handlers to elements, ways that will leave the "onfoo" attributes completely unset.
If I understand where you're going with this, you should be able to assign the returned onclick function straight through to the onclick of your new nav element...
$('#NewNavElement').click($('#theLink').attr('onclick'));
If you need to add additional code to the handler, you can just bind another click handler.
try this;
$('#theLink').getAttributeNode('onclick').value
Revised as per comment:
$('#theLink').get().getAttributeNode('onclick').value

Categories