I need to create a new notification div when an event triggers. Normally, I would do this in jQuery and use something like $("myDiv").append(newDiv), however the item selector to be appended to can't be selected with jQuery. Below is the code to explain more.
function notifMaker() {
var notification = $("<div>").addClass("notification", "id-dark", "overtop");
var notifButton = $("<button>").addClass("delete");
notification.append(notifButton);
notification.text("You've already saved this item. Click the x button to remove it from saved items.");
return notification;
}
and
ondragleave: function (event) {
// console.log("Drag Leave");
var draggableElement = event.relatedTarget;
// console.log(notifMaker());
draggableElement.append(notifMaker());
},
As you can see, the element I need to append to is actually from the event object. And if I try to append the notification from notifMaker into this, I just get [Object object] because jQuery is technically created an object in notifMaker. Is there any way around this? Any other methods I should consider using? Thanks. Here is an image of the object.
Using jQuery you can wrap any DOM element into jQuery object, so that you can use any of library methods on that element. In your case the code would look like this:
ondragleave: function (event) {
var draggableElement = $(event.relatedTarget);
draggableElement.append(notifMaker());
}
Related
Please refer to my previous question: How to get element in template html?.
Firstly, I follow the solution in How to get element in template html? to obtain the element.
var template = templateContent.content;
Then I try to bind a click event for searchBtn:
searchBtn.addEventListener('click', function() {
console.log('click'); // does not work
});
This binding fails, so I use the event delegation to handle event:
document.addEventListener('click',function(e){
if(e.target && e.target.id== 'searchBtn'){
console.log('click');
console.log(template.querySelector('#results'));
template.querySelector('#results').innerText = 'Foo';
}
});
The two logs are expected, but the last command to update the innerText does not work. On the other hand, I can update its content outside the click event. Any solution?
The final version of my code:
var link = document.querySelector('link[rel="import"][href="search.html"]');
var templateContent = link.import.querySelector('template');
var template = templateContent.content;
var searchBtn = template.querySelector('#searchBtn');
console.log(searchBtn);
template.querySelector('#results').innerText = 'Bar'; // ok
document.addEventListener('click',function(e){
if(e.target && e.target.id== 'searchBtn'){
console.log('click'); // ok
console.log(template.querySelector('#results')); // ok
template.querySelector('#results').innerText = 'Foo'; // does not work
}
});
Updates
Now I retrieve the results element outside the function:
var results = template.querySelector('#results');
Then inside the function, results.innerText = 'Foo'; works. However, this only updates the results itself, and the UI is not updated correspondingly.
How to update the UI inside the template?
You got it right, it is the binding issue. template is not available inside click function. You need to bind this. There are many ways to do this e.g.
document.addEventListener('click',onClick.bind(this));
onClick = function(e){
if(e.target && e.target.id== 'searchBtn'){
console.log('click'); // ok
console.log(template.querySelector('#results')); // ok
this.template.querySelector('#results').innerText = 'Foo'; // should work
}
}
There are many ways to get the HTML elements
You can get use
var sbtnElement = document.getElementById('searchBtn');
then add eventlistener to it
sbtnElement.addEventlistener('click', function() {
console.log('click'); // does not work
});
Naturally getElement by id will give you one element, and getElementsByClassName will return you an array of elements with the same classname. Same goes for getElementsByTagName.
hi i don't know what are you try to create for. but have you ever try to use template in script ? like this one
<script id="sampleTemplate" type="text/template">
// do the html here
</script>
So in that case you can bind event using that one. just a normal creating of html and binding javascript function.
You can refer to this blog. https://jonsuh.com/blog/javascript-templating-without-a-library/
I hope, i helped you thru this. :)
Using jQuery I need to:
persists list of all event handlers that are added to element,
remove them all for few seconds and
return things to initial state (reassign the same event handlers)
I found that get list of current listeners with (some jQuery inner mechanisms):
var eventsSubmitBtn = $._data(submitButton[0], "events");
Then I can remove all event listeners with
submitButton.off();
But last stem seems not to be working
setTimeout(function () {
$._data(submitButton[0], "events", eventsSubmitBtn);
}, 5000);
eventsSubmitBtn is an empty array.
Is this the way this should be done with initial setting and I'm need something like deep cloning for those objects or this can't be done with $._data?
N.B. I have possibility to add my cistom code after all other system js code, thus I can't place the code assigning to $.fn.on before anything. Code that I write will run the last on startup and other event listeners are attached before my scripts will run.
As you get a reference to the object returned by $._data(), any change to that object will not go unnoticed, i.e. after you invoke .off(), that object will have changed to reflect that there are no handlers attached any more.
You could solve this by taking a shallow copy of the object, (e.g. with Object.assign).
But this is not really a recommended way to proceed. According to a jQuery blog, "jQuery._data(element, "events") ... is an internal data structure that is undocumented and should not be modified.". As you are modifying it when restoring the handlers, this cannot be regarded best practice. But even only reading it should only be used for debugging, not production code.
It would be more prudent to put a condition in your event handling code:
var ignoreEventsFor = $(); // empty list
$("#button").on('click', function () {
if (ignoreEventsFor.is(this)) return;
// ...
});
Then, at the time it is needed, set ignoreEventsFor to the element(s) you want to ignore events for. And when you want to revert back to normal, set it to $() again.
Now adding this to all your event handlers may become a burden. If you stick to using on() for attaching event handlers, then you could instead extend $.fn.on so it will add this logic to the handlers you pass to it.
The following demo has a button which will respond to a click by changing the background color. With a checkbox you can disable this from happening:
/* Place this part immediately after jQuery is loaded, but before any
other library is included
*/
var ignoreEventsFor = $(), // empty list
originalOn = $.fn.on;
$.fn.on = function (...args) {
var f = args[args.length-1];
if (typeof f === 'function') {
args[args.length-1] = function (...args2) {
if (ignoreEventsFor.is(this)) return;
f.call(this, ...args2);
};
}
originalOn.call(this, ...args);
}
/* This next part belongs to the demo, and can be placed anywhere */
$(function () {
$("#colorButton").on('click', function () {
// Just some handler that changes the background
var random = ('00' + (Math.random() * 16*16*16).toString(16)).substr(-3);
$('body').css({ backgroundColor: "#" + random });
});
$("#toggler").on('change', function () {
// Toggle the further handling of events for the color button:
ignoreEventsFor = $(this).is(':checked') ? $("#colorButton") : $();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="colorButton">Change color</button><br>
<input type="checkbox" id="toggler">Disable events
Notice: the above code uses ES6 spread/rest syntax: if you need support for IE then that would have to be written using the arguments variable, apply, ...etc.
been struggling with this for a while now. Really hope someone can help me out.
Im trying to make divs which are removable when you click onto them.
They have a css-class 'tag-show' which is added and removed (this works), so the selector seems to be fine i guess..?
Why is the $(this).remove() not working?
$(document).ready(function() {
// selectors
var module = $(".divCreate");
var list = module.find(".listTag");
var button = module.find(".divButton");
// the actual issue
button.click(function() {
list.append("<div class='tag'>Tag</div>");
setTimeout(function() {
list.find(".tag").last().addClass("tag-show").on("click", function() {
$(this).removeClass("tag-show");
setTimeout(function() {
$(this).remove();
},190);
});
},40);
})
});
"this" loses it's context in your setTimeout.
add a var containing this and use that instead.
like so
var self = $(this);
setTimeout(function() {
$(self).remove();
},190);
I think that would fix it.
You should use the jQuery .on() function instead of .click(), as it works for dynamically created elements. Then you also don't have to apply it to the element each time it is dynamically added.
Somewhere else in your code within $(document).ready(function() {}); add this event handler:
$('.listTag').on('click', 'div.tag', function() {
$(this).remove();
});
and it should work for any element that is matched by the div.tag selector.
this inside the setTimeout callback is not referring to the div anymore. You could bind the callback to the div or do something like this:
var $this = $(this);
setTimeout(function() {
$this.remove();
},190);
I have made some improvments to your code, adding comments where it was needed. Just check the code below and its comments.
Your problem with remove is that the this in your case is "triggering" the closest parent, which is setTimeout, not clicked element.
For a better understanding just try to call console.log(this); inside timeout function and click function, you will see the difference.
I have made an fiddle which can help you understand better (open developer tools to see the console result)
$(document).ready(function() {
// when you keep DOM elements in variables is better to put $ in the beginning
var $module = $(".divCreate");
// faster than .find()
var $list = $(".listTag", $module);
// can not call 'on' with variable
//var $button = $(".divButton", $module);
// called through document since we need to handle dynamic added elements - check event delegation
$(document).on("click", ".divButton", function() {
$list.append("<div class='tag'>Tag</div>");
setTimeout(function() {
// some improvments
$(".tag", $list).last().addClass("tag-show");
}, 40);
// Just keep this if you have divButton attached to an anchor element
// Useful for preventing default behvaiour - in this case adding "#" to url
return false;
});
// Do not need to create the event inside that event
$(document).on("click", ".tag-show", function() {
// Since we use an element more than once is better to
// add it into a variable to avoid performance issues - js caches it and call the variable
var $el = $(this); // our needed 'this'
$el.removeClass("tag-show");
setTimeout(function() {
// 'this' here returns some properties of window (where setTimeout belongs), we need to call element cached above
//(the 'this' above contains what we need)
$el.remove();
}, 190);
});
});
Note : still do not understand why you need these timeouts but it s up to you, maybe you need them with a bigger interval :D
Not sure what you're trying to accomplish, but perhaps this is a better way to accomplish the same task?
// selectors
var module = $(".divCreate");
var list = module.find(".listTag");
var button = module.find(".divButton");
// the actual issue
button.click(function() {
list.append("<div class='tag'>Tag</div>");
})
$(document).on('click','.tag', function(){
$(this).remove();
});
https://jsfiddle.net/7daffjh8/
I have a function, which at the end of its task assigns a button to a new id.
function altChecker() {
var doc = document,
out = [],
appButton = doc.getElementById('appButton'),
//re = /click-me/gi,
output = doc.createElement('p');
output.setAttribute('id', 'output');
EventUtility.addHandler(appButton, 'click', function(e) {
//I have not included all the function details to concentrate on the question
appButton.id = 'appButtonNextChecker';
var appButtonNextChecker = doc.getElementById('appButtonNextChecker');
nextChecker(appButtonNextChecker);
});
}
function nextChecker(newBtnName) {
EventUtility.addHandler(newBtnName, 'click', function(e) {
$('#output').innerHTML = "";
console.log('next Checker, button!')
});
}
So basically there is one button in the DOM assigned to appButton ID initially, and then I change it doing:
appButton.id = 'appButtonNextChecker';
when the altChecker function fires...
Then I assign the button to a new variable, and pass in the variable to the next function...
var appButtonNextChecker = doc.getElementById('appButtonNextChecker');
nextChecker(appButtonNextChecker);
While I can see the buttons' ID change in the DOM, and I see the console.log fire in the nextChecker function,
$('#output').innerHTML = ""; //doesn't fire
AND the altChecker function fires as well (again)?! Haven't I severed the connection to the click function when I reassigned the new ID?
Any help would be appreciated!
Javascript doesn't remember that you initially attached the event through it's id. The event is attached to the element itself, not the ID. It's not like CSS that way.
In fact your variables are still holding the same element as well, so there's no need to create a new variable after changing the ID, either. Since you're using jQuery you can just type $(appButton).unbind(); to remove the event handler. You may also want to look into .on() and .off()
The problem is that you're trying to use the innerHTML property in a jQuery's object.
That property belongs to Element, and it will not work in the way you're using it.
You can use the document.getElementById method, and it will work fine:
document.getElementById('output').innerHTML = '';
Or you can use jQuery's html method:
$('#output').html('');
And you can even use the first element of the jQuery's array, and use innerHTML again:
$('#output')[0].innerHTML = '';
It's up to you, but the first option will be faster, for sure.
I have a setup theoretically like this [see fiddle -> http://jsfiddle.net/GeZyw/] :
var EventTest = function(element) {
this.element = element;
this.element.addEventListener('click', elementClick);
function elementClick() {
var event = document.createEvent('CustomEvent');
event.initEvent('myevent', false, false);
event['xyz']='abc';
event.customData='test';
console.log(event);
this.dispatchEvent(event);
}
}
var element = document.getElementById('test');
var test = new EventTest(element);
$(document).ready(function() {
$("#test").on('myevent', function(e) {
console.log('myevent', e);
});
});
What I want is to create a CustomEvent in pure Javascript, enrich it with some properties and trigger that event so it can be cached also by a library like jQuery.
As you can see in the fiddle, the CustomEvent is triggered well and it is actually populated with custom properties - but when it reaches jQuery on() the custom properties is gone from the first level. My custom properties is now demoted to e.originalEvent.xyz and so on.
That is not very satisfactory. I want at least my own properties to be at the first level.
Also, in a perfect world, I would like to get rid of most of the standard properties in the dispatched event, so it contained (theoretically optimal) :
e = {
xyz : 'abc',
customData : 'test'
}
Is that possible at all? If so, how should I do it?
I have run into the same issue, couple of months ago, the point is:
When an event is received by jQuery, it normalizes the event properties before it dispatches the event to registered event handlers.
and also:
Event handlers won't be receiving the original event. Instead they are getting a new jQuery.Event object with properties copied from the raw HTML event.
Why jQuery does that:
because it can't set properties on a raw HTML event.
I had decided to do the same, I started to do it with a nasty way, and my code ended up so messy, at the end I decided to use jQuery.trigger solution, and pass my event object as the second param, like:
$("#test").bind("myevent", function(e, myeventobj) {
alert(myeventobj.xyz);
});
var myobj = {"xyz":"abc"};
$("#test").trigger("myevent", myobj);
for more info check this link out: .trigger()