jQuery form on ready/load does not work - javascript

I have this 'template' code (just for example):
$(document).on("<EVENT>", "form", function() {
$(this).find(".input input").each(function() {
var required = $(this).attr("required");
var checkField = $(this).closest("tr").children(".check");
var errorField = $(this).closest("tr").children(".errormessage");
if (required != undefined) {
$(checkField).css("color", "#FFFF00");
$(checkField).html("✘");
$(errorField).css("color", "#FFFF00");
$(errorField).html("(Required)");
}
else {
$(checkField).css("color", "#FFFF00");
$(checkField).html("✔");
$(errorField).css("color", "#000000");
$(errorField).html("");
}
});
});
When <EVENT> is for example click or mouseover, it just works as expected.
However it refuses to work on an ready or load event, any clue why?

From http://api.jquery.com/on/
In all browsers, the load, scroll, and error events (e.g., on an element) do not bubble. In Internet Explorer 8 and lower, the paste and reset events do not bubble. Such events are not supported for use with delegation, but they can be used when the event handler is directly attached to the element generating the event.

Related

Change-Event for div [duplicate]

I want to run a function when a user edits the content of a div with contenteditable attribute. What's the equivalent of an onchange event?
I'm using jQuery so any solutions that uses jQuery is preferred. Thanks!
2022 update
As pointed out in the comments, this doesn't answer the question asked, which wanted the equivalent of the change event rather than the input event. However, I'll leave it here as is.
Original answer
I'd suggest attaching listeners to key events fired by the editable element, though you need to be aware that keydown and keypress events are fired before the content itself is changed. This won't cover every possible means of changing the content: the user can also use cut, copy and paste from the Edit or context browser menus, so you may want to handle the cut copy and paste events too. Also, the user can drop text or other content, so there are more events there (mouseup, for example). You may want to poll the element's contents as a fallback.
UPDATE 29 October 2014
The HTML5 input event is the answer in the long term. At the time of writing, it is supported for contenteditable elements in current Mozilla (from Firefox 14) and WebKit/Blink browsers, but not IE.
Demo:
document.getElementById("editor").addEventListener("input", function() {
console.log("input event fired");
}, false);
<div contenteditable="true" id="editor">Please type something in here</div>
Demo: http://jsfiddle.net/ch6yn/2691/
Here is a more efficient version which uses on for all contenteditables. It's based off the top answers here.
$('body').on('focus', '[contenteditable]', function() {
const $this = $(this);
$this.data('before', $this.html());
}).on('blur keyup paste input', '[contenteditable]', function() {
const $this = $(this);
if ($this.data('before') !== $this.html()) {
$this.data('before', $this.html());
$this.trigger('change');
}
});
The project is here: https://github.com/balupton/html5edit
Consider using MutationObserver. These observers are designed to react to changes in the DOM, and as a performant replacement to Mutation Events.
Pros:
Fires when any change occurs, which is difficult to achieve by listening to key events as suggested by other answers. For example, all of these work well: drag & drop, italicizing, copy/cut/paste through context menu.
Designed with performance in mind.
Simple, straightforward code. It's a lot easier to understand and debug code that listens to one event rather than code that listens to 10 events.
Google has an excellent mutation summary library which makes using MutationObservers very easy.
Cons:
Requires a very recent version of Firefox (14.0+), Chrome (18+), or IE (11+).
New API to understand
Not a lot of information available yet on best practices or case studies
Learn more:
I wrote a little snippet to compare using MutationObserers to handling a variety of events. I used balupton's code since his answer has the most upvotes.
Mozilla has an excellent page on the API
Take a look at the MutationSummary library
non jQuery quick and dirty answer:
function setChangeListener (div, listener) {
div.addEventListener("blur", listener);
div.addEventListener("keyup", listener);
div.addEventListener("paste", listener);
div.addEventListener("copy", listener);
div.addEventListener("cut", listener);
div.addEventListener("delete", listener);
div.addEventListener("mouseup", listener);
}
var div = document.querySelector("someDiv");
setChangeListener(div, function(event){
console.log(event);
});
I have modified lawwantsin 's answer like so and this works for me. I use the keyup event instead of keypress which works great.
$('#editor').on('focus', function() {
before = $(this).html();
}).on('blur keyup paste', function() {
if (before != $(this).html()) { $(this).trigger('change'); }
});
$('#editor').on('change', function() {alert('changed')});
Two options:
1) For modern (evergreen) browsers:
The "input" event would act as an alternative "change" event.
https://developer.mozilla.org/en-US/docs/Web/Events/input
document.querySelector('div').addEventListener('input', (e) => {
// Do something with the "change"-like event
});
or
<div oninput="someFunc(event)"></div>
or (with jQuery)
$('div').on('click', function(e) {
// Do something with the "change"-like event
});
2) To account for IE11 and modern (evergreen) browsers:
This watches for element changes and their contents inside the div.
https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
var div = document.querySelector('div');
var divMO = new window.MutationObserver(function(e) {
// Do something on change
});
divMO.observe(div, { childList: true, subtree: true, characterData: true });
const p = document.querySelector('p')
const result = document.querySelector('div')
const observer = new MutationObserver((mutationRecords) => {
result.textContent = mutationRecords[0].target.data
// result.textContent = p.textContent
})
observer.observe(p, {
characterData: true,
subtree: true,
})
<p contenteditable>abc</p>
<div />
Here's what worked for me:
var clicked = {}
$("[contenteditable='true']").each(function(){
var id = $(this).attr("id");
$(this).bind('focus', function() {
// store the original value of element first time it gets focus
if(!(id in clicked)){
clicked[id] = $(this).html()
}
});
});
// then once the user clicks on save
$("#save").click(function(){
for(var id in clicked){
var original = clicked[id];
var current = $("#"+id).html();
// check if value changed
if(original != current) save(id,current);
}
});
This thread was very helpful while I was investigating the subject.
I've modified some of the code available here into a jQuery plugin so it is in a re-usable form, primarily to satisfy my needs but others may appreciate a simpler interface to jumpstart using contenteditable tags.
https://gist.github.com/3410122
Update:
Due to its increasing popularity the plugin has been adopted by Makesites.org
Development will continue from here:
https://github.com/makesites/jquery-contenteditable
Non JQuery answer...
function makeEditable(elem){
elem.setAttribute('contenteditable', 'true');
elem.addEventListener('blur', function (evt) {
elem.removeAttribute('contenteditable');
elem.removeEventListener('blur', evt.target);
});
elem.focus();
}
To use it, call on (say) a header element with id="myHeader"
makeEditable(document.getElementById('myHeader'))
That element will now be editable by the user until it loses focus.
In Angular 2+
<div contentEditable (input)="type($event)">
Value
</div>
#Component({
...
})
export class ContentEditableComponent {
...
type(event) {
console.log(event.data) // <-- The pressed key
console.log(event.path[0].innerHTML) // <-- The content of the div
}
}
To avoid timers and "save" buttons, you may use blur event wich fires when the element loses focus. but to be sure that the element was actually changed (not just focused and defocused), its content should be compared against its last version. or use keydown event to set some "dirty" flag on this element.
Here is the solution I ended up using and works fabulously. I use $(this).text() instead because I am just using a one line div that is content editable. But you may also use .html() this way you dont have to worry about the scope of a global/non-global variable and the before is actually attached to the editor div.
$('body').delegate('#editor', 'focus', function(){
$(this).data('before', $(this).html());
});
$('#client_tasks').delegate('.task_text', 'blur', function(){
if($(this).data('before') != $(this).html()){
/* do your stuff here - like ajax save */
alert('I promise, I have changed!');
}
});
You need to use input event type
Demo
HTML
<div id="editor" contenteditable="true" >Some text here</div>
JS
const input = document.getElementById('editor');
input.addEventListener('input', updateValue);
function updateValue(e) {
console.log(e.target);
}
know more
The onchange event doesn't fires when an element with the contentEditable attribute is changed, a suggested approach could be to add a button, to "save" the edition.
Check this plugin which handles the issue in that way:
Creating a quick and dirty jQuery contentEditable Plugin
Using DOMCharacterDataModified under MutationEvents will lead to the same. The timeout is setup to prevent sending incorrect values (e.g. in Chrome I had some issues with space key)
var timeoutID;
$('[contenteditable]').bind('DOMCharacterDataModified', function() {
clearTimeout(timeoutID);
$that = $(this);
timeoutID = setTimeout(function() {
$that.trigger('change')
}, 50)
});
$('[contentEditable]').bind('change', function() {
console.log($(this).text());
})
JSFIDDLE example
I built a jQuery plugin to do this.
(function ($) {
$.fn.wysiwygEvt = function () {
return this.each(function () {
var $this = $(this);
var htmlold = $this.html();
$this.bind('blur keyup paste copy cut mouseup', function () {
var htmlnew = $this.html();
if (htmlold !== htmlnew) {
$this.trigger('change')
}
})
})
}
})(jQuery);
You can simply call $('.wysiwyg').wysiwygEvt();
You can also remove / add events if you wish
A simple answer in JQuery, I just created this code and thought it will be helpful for others too
var cont;
$("div [contenteditable=true]").focus(function() {
cont=$(this).html();
});
$("div [contenteditable=true]").blur(function() {
if ($(this).html()!=cont) {
//Here you can write the code to run when the content change
}
});
For me, I want to check the input is valid or not.
If valid, then update, Otherwise show an error message and keep the value as same as before.
Skill: When you edit done, usually, it will trigger the blur event.
Example
<span contenteditable="true">try input somethings.</span>
<script>
const elem = document.querySelector(`span`)
let oldValue = elem.innerText
elem.onkeydown = (keyboardEvent) => {
if (keyboardEvent.key === "Enter") {
elem.blur() // set focusout
}
}
elem.onblur = (e) => {
const curValue = elem.innerText
if (curValue === oldValue) {
return
}
if (curValue.length <= 50) { // 👈 Input your conditions.
// 👇 fail
elem.innerText = oldValue
// (Optional) Add error message
elem.insertAdjacentHTML("beforeend", `<span style="margin-left:5px;color:red">error length=${curValue.length}. Must greater than 50. undo to the previous value.</span>`)
const errMsg = elem.querySelector(`span`)
setTimeout(() => errMsg.remove(), 3500) // wait 3.5 second, and then remove it.
return
}
// 👇 OK, update
oldValue = curValue
}
</script>
Check this idea out.
http://pastie.org/1096892
I think it's close. HTML 5 really needs to add the change event to the spec. The only problem is that the callback function evaluates if (before == $(this).html()) before the content is actually updated in $(this).html(). setTimeout don't work, and it's sad. Let me know what you think.
Based on #balupton's answer:
$(document).on('focus', '[contenteditable]', e => {
const self = $(e.target)
self.data('before', self.html())
})
$(document).on('blur', '[contenteditable]', e => {
const self = $(e.target)
if (self.data('before') !== self.html()) {
self.trigger('change')
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

event.target in not defined in Firefox and minor error in IE

I have read about 15 different stack overflow questions on Firefox having problems with event. Not of them closely pertained to my function but I figured it was a straight forward problem. I have tried everything that seemed to have worked for their problems and they all fail.
My problem is in Firefox, nothing happens and this is caused by the order I have my code. The order is very important or I'll cause unwanted appending of multiple buttons. I at least understand why it isn't adding and removing a class based on a click function. What I don't understand is I added var event = event || window.event; and tried if(!event) event = window.event;. They all seem to do nothing so I even tried just putting window.event anywhere I had just event at and this also did not work.
My problem in IE, This one at least allows me to click and expand the article which is great but it doesn't append my button once clicked. This one isn't major since the close article button isn't life or death.
My jQuery
function newsArticle() { // Articles Functionality
$('.article').on('click', function() {
var self = this;
var button = $('<span />', {
'class': 'close',
text: 'Click to minimize article',
on: {
click: function (e) {
e.stopPropagation();
$(self).stop(true).toggleClass('fullArticle article');
$(this).remove();
}
}
});
if(!event) event = window.event;
if($(event.target).is('.article')) {
$(this).append(button);
}
else if($(event.target).parents().is('.article')) {
$(this).append(button);
}
$(this).removeClass('article').addClass('fullArticle');
});
}
newsArticle();
Answer
function newsArticle() { // Articles Functionality
$('.article').on('click', function(e) {
var self = this;
var button = $('<span />', {
'class': 'close',
text: 'Click to minimize article',
on: {
click: function (e) {
e.stopPropagation();
$(self).stop(true).toggleClass('fullArticle article');
$(this).remove();
}
}
});
if($(e.target).is('.article')) {
$(this).append(button);
}
else if($(e.target).parents().is('.article')) {
$(this).append(button);
}
$(this).removeClass('article').addClass('fullArticle');
});
}
newsArticle();
jsfiddle
If jsfiddle doesn't show problem then view on live site --> site
Just scroll all the way down and above footer there is 4 tabs, click on "In the News".
If you need anything else then let me know and sorry for asking this question but I have not been able to find an answer that works.
When you use jQuery, you don't need to do the cross-browser checks (if(!event) event = window.event; etc) since jQuery does that for you. You should, however, accept the event as a parameter in your event handler:
$('.article').on('click', function(event) {
I like to use e as a convention, to avoid confusion:
$('.article').on('click', function(e) {

Add a JavaScript Event to an Image With JavaScript

Ok so I'm going to try and make this as clear as possible. I want to write a function that when called will add an onmouseout attribute to an image.
Before the image is moused over.
<img src="myfile.jpg" onmouseover="function()" />
After
<img src="myfile.jpg" onmouseover="function()" onmouseout="anotherFunction()" />
I would also like to change the picture with function() and then onmouseout set the picture back to the original. I know how to change the pictures with onmouseover and onmouseout right in the image code but I'm trying to simplify this as I have to do the image changy thing about 100 times and I dont want to write out the code that many times. Gah I hope that was clear.
This is simpler than you may think:
function SetImageSource(ele, url) {
ele.src = url;
}
<img src="myfile.jpg"
onmouseover="SetImageSource(this, 'someURL')"
onmouseout="SetImageSource(this, 'someOtherURL')" />
Note: Inline JavaScript is not ideal. I suggest reading up on event handling in JS. More specifically, read about attaching to an event.
Edit per clarification
<img id="imgMyImage" src="myfile.jpg"
onmouseover="SetImageSource(this, 'someURL')"
onmouseout="SetImageSource(this, 'someOtherURL')" />
function AddEvent(html_element, event_name, event_function)
{
if(html_element.attachEvent) //Internet Explorer
html_element.attachEvent("on" + event_name, function() {event_function.call(html_element);});
else if(html_element.addEventListener) // Everything else
html_element.addEventListener(event_name, event_function, false);
}
AddEvent(document.getElementById('imgMyImage'),
'onmouseover',
// do something
);
Additional Information
See .addEventListener() on MDN
See .attachEvent() on MSDN
Here we go http://jsfiddle.net/5U9w9/2/
I'm going to update the jsFidle with more comments and will update the link here too.
javascript
// grab all the required element on the page
var img_all = document.getElementsByTagName('img');
// for every element do this
for (i=0; i< img_all.length; i++){
var img = img_all[i];
// set the required event on the element
// when the event of the element occurs, the associated function will be called with event object as it's argument.
// https://developer.mozilla.org/en-US/docs/Mozilla_event_reference
//img.addEventListener('mouseover', mouseover_handler, false);
AddEvent(img, 'mouseover', mouseover_handler)
//mouseout_handler will be called, on mouseout event
// img.addEventListener('mouseout', mouseout_handler, false);
AddEvent(img, 'mouseout', mouseout_handler)
}
function mouseover_handler(e){
// el is and event object and has various properties like clientX, clientY, srcElement, etc. you can check them by console.log(el)
console.log(e)
// to get the element i'm hovering, use
var element = e.srcElement;
//element is DOM element and can be manupulated
element.style.width="100px";
}
// similarly handler for an another event.
function mouseout_handler(e){
e.srcElement.style.width="50px";
}
​// cross-browser addEventListner
function AddEvent(html_element, event_name, event_function)
{
if(html_element.attachEvent) //Internet Explorer
html_element.attachEvent("on" + event_name, function() {event_function.call(html_element);});
else if(html_element.addEventListener) // Everything else
html_element.addEventListener(event_name, event_function, false);
}
Update
Use AddEvent in the place of addEventListner() for IE support.​ (CREDIT: #James Hill's answer)

Capture "tap" event with pure JavaScript

How can I capture a user's "tap" event with pure JS? I cannot use any libraries, unfortunately.
The click event is triggered on mouse click as well as on a touch click.
The touchstart event is triggered when the screen is touched.
The touchend event is triggered when the touch ends. If the default action is prevented, a click event will not trigger.
http://www.w3.org/TR/touch-events/
There are touchstart, touchend and other events. You can add event listeners for them in this way:
var el = document.getElementById('test');
el.addEventListener('touchstart', touchHandler);
More information about native DOM events you can find on MDN webstite.
This is not my code but I can't remember where I got it from, used successfully. It uses jQuery but no extra libraries or plugins for the tap handling itself.
$.event.special.tap = {
setup: function(data, namespaces) {
var $elem = $(this);
$elem.bind('touchstart', $.event.special.tap.handler)
.bind('touchmove', $.event.special.tap.handler)
.bind('touchend', $.event.special.tap.handler);
},
teardown: function(namespaces) {
var $elem = $(this);
$elem.unbind('touchstart', $.event.special.tap.handler)
.unbind('touchmove', $.event.special.tap.handler)
.unbind('touchend', $.event.special.tap.handler);
},
handler: function(event) {
event.preventDefault();
var $elem = $(this);
$elem.data(event.type, 1);
if (event.type === 'touchend' && !$elem.data('touchmove')) {
event.type = 'tap';
$.event.handle.apply(this, arguments);
} else if ($elem.data('touchend')) {
$elem.removeData('touchstart touchmove touchend');
}
}
};
$('.thumb img').bind('tap', function() {
//bind tap event to an img tag with the class thumb
}
I used this for a project exclusively for iPad, so might need tweaking to work for desktop and tablet together.
I wrote a little script myself. It's not in pure-JS, but works fine for me.
It prevents executing the script on scrolling, meaning the script only fires on a 'tap'-event.
$(element)
.on('touchstart', function () {
$(this).data('moved', '0');
})
.on('touchmove', function () {
$(this).data('moved', '1');
})
.on('touchend', function () {
if($(this).data('moved') == 0){
// HERE YOUR CODE TO EXECUTE ON TAP-EVENT
}
});

How can I attach event to a tag which is in string form?

I'm creating html on runtime like this:
var myVar = "<div id='abc'>some clickable text</div>"
Now, I want to attach some event, say onclick, to this div. How can I do that on next line? I'll add this to DOM later.
PS: I've to accomplish this without using JQuery.
Instead of building your div as a string, you'll want to use document.createElement('div'). This way you will have a real dom object, and can get and set it's propeties, including onClick
Will this help? Since you dynamically generate it, you know the control id of the DIV.
document.getElementbyId('abc').onClick = foo;
function foo()
{
alert("All your impl to go here");
}
Try building the div as a DOM element first.
var myVar = document.createElement("div"),
parentDiv = document.getElementById("parent_div");
parentDiv.appendChild(myVar);
myVar.innerHTML = "some clickable text";
if(myVar.addEventListener){
myVar.addEventListener("click", clickFn, false);
}
else if(myVar.attachEvent){
myVar.attachEvent("onclick", clickFn);
}
else{
myVar.onclick = clickFn;
}
The addEventListener method is standard, but not every browser plays nice with the standard.
EDIT: As mentioned, an element must be added to the DOM first.
Or you can use this technique: attach event to the document.body. Then if the event target is not the needed div than just do nothing. It is the same techinque jquery uses for its live function:
// crossbrowser event attachment function
function listen(evnt, elem, func) {
if (elem.addEventListener) {
elem.addEventListener(evnt, func, false);
}
else if (elem.attachEvent) {
var r = elem.attachEvent("on" + evnt, func);
return r;
}
else window.alert('I\'m sorry Dave, I\'m afraid I can\'t do that.');
}
// this is an analog of the jquery.live
var assignLiveEvent = function(id, evnt, callback) {
var handler = function(e) {
e = e || window.event;
e.target = e.target || e.srcElement;
if (e.target.id == id) {
//your code here
callback(e);
}
};
listen(evnt, document.body, handler);
};
var myVar = "<div id='abc'>some clickable text</div>";
assignLiveEvent("abc", "click", function(e) {
//your code here
});
// now you can add your div to DOM even after event handler assignation
Here is demo.
Brian Glaz is totally right but, if for some reason, you really need to do it this way, you have two options:
you can only add events to something that is already in the DOM, using pure javascript, so you would have to include it in the html like:
document.body.innerHTML += myVar;
and then, attach the event with
document.getElementById('abc').addEventListener('click', function(e){
//your code
}, 1);
With jQuery, you could use .live() to attach events to elements that are not yet present in the DOM:
$('#abc').live('click', function(e){
//your code here
});
so you could add the div later...

Categories

Resources