Is there a CKEditor event that I can hook up to that fires whenever the content changes? Ideally I'm looking for an event that fires when anything at all changes, so for example it could be the user typed something into the editor, or a toolbar item was used (e.g. changed the font color).
Currently I'm just hooking up to the key event which unsurprisingly only fires when a key is pressed, and not when for example the font color is changed via the toolbar.
CKEDITOR.instances['myEditor'].on('key', function () {
console.log("changed");
});
I've also tried using jQuery to delegate a click event on the CKEditor's parent like below. This partly works, for example it fires if you click the Bolt/Italic buttons, but not if you change the font color:
$(document).on('click', '#myEditor_DISPLAY', function(){
console.log("changed");
});
I've looked at the documentation here but haven't found anything. If there's only an event for the toolbar usage then I could make do with that because I can just hookup to both that and the key event.
Related
I have a model, Color, with a foreign key mill that I'd like to autocomplete. Furthermore, I'd like to detect when the mill select box changes and do something with that in Javascript. However, I can't seem to trigger any JS off the select box being changed.
I set up my admin like so:
# admin.py
class MillAdmin(admin.ModelAdmin):
search_fields = ['name']
class ColorAdmin(admin.ModelAdmin):
class Media:
js = ['js/jquery/jquery.min.js', 'js/admin/some-function.js',]
autocomplete_fields = ['mill']
And I write some Javascript:
// some-function.js
console.log('loaded script');
document.addEventListener('change', (function(e) {
console.log('detected change event somewhere')
}))
console.log('event listener added')
In my browser console, when I visit the Color page, I see:
loaded script
event listener added
But when I select a mill, nothing more is logged.
Further notes:
The autocomplete itself is working just fine -- I am able to choose the mill I want, save, etc. Furthermore, if I remove autocomplete_fields = ['mill'] from my admin, I see that the vanilla select box does trigger the change event as expected:
loaded script
event listener added
detected change event somewhere
I dug around in the source code long enough to find that Django is using Select2, which promises to emit the change event just as if it were a normal select box. But if that is happening, something else in the page must be eating it, because I'm not seeing it. What's going on? If there's a conflict between Django and Select2, does anyone know a workaround? Thanks!
Events triggered by jQuery cannot be observed by native event listeners. Select2 uses jQuery's trigger function to handle events, which doesn't fire native DOM events, but you can swap the jQuery trigger for a native DOM one as illustrated here https://github.com/select2/select2/issues/4686
what is the best way to catch and handle a click event on "anything except specific DOM-node(s)" in a React app?
The handler of the click event is the easy part: this can be any method.
The registration of the event, and the trigger to invoke the handler, is the hard part.
There is no clean way to capture a "clicks outside ...." event.
There are however various (HTML/ CSS/ Javascript) tricks you could apply:
If it is a modal page/ popup, you could also render a full page background rectangle (e.g. slightly transparent grey), which is in front of the whole page, but behind the popup. Add a click-event-listener to this background to remove the modal + the grey background.
Another method is to use the focusout javascript event on your top-react component:
the top HTML component rendered by react should be able to get focus (needs to be an <a> or similar HTML, or - somewhat less clean - needs a tabindex=... to work)
give the element focus as soon as it is rendered (inside componentDidMount()`)
add a focusout event listener, which triggers the handler to do something with the click outside.
The focusout event is fired as soon as the component no longer has focus:
- if a child of the component gets focus (e.g. you click something inside the component) focusout is also fired: usually no problem for menu's, but undesired for popups with forms
- the focusout is also fired if the user presses TAB.
There's no React-specific way to do this; all React event handlers are tied to the component they're set on. The best way to accomplish this depends on the details of what you need to get done, but a fairly straightforward way to address this would be to add a delegated click handler to the body element, or the closest ancestor element that includes the area you want to capture clicks from. You'd attach this event handler either on the component's componentDidMount() or whenever it becomes relevant, for example, after toggling the component's state so that it shows a dropdown menu.
Attach the event handler however you normally would – element.addEventListener or jQuery's $().on or what-have-you - and evaluate the event target when it fires to determine whether you need to execute your custom logic.
Simple example, without jQuery:
componentDidMount() {
document.body.addEventListener('click', (e) => {
if (e.target !== [your dom node]) {
// do something
}
}
}
Attaching a single event handler on the body element shouldn't pose any performance issues, but best practice for most cases where you'd use something like this would be to remove the event handler when it's no longer needed.
I am trying to simulate an onclick event on a drop down.
I have an IE object that is going to a page and I need to change a dropdown which has an onchange event:
$('select[name="blah"]').val(3).trigger('change');
$('select[name="blah"]').change(function(){
alert('changed');
});
When I try this, I would expect the alert to fire as it's technically an onchange.
http://jsfiddle.net/3y5hmyf0/
Is there a way to acomplish this?
More Details
My tool is controlling another IE page through an object. It navigates to the page and finds the select drop down on the page. From there, if you did it manually it has an onchange event when making a selection.
I am trying to get jQuery to simulate as if it was being clicked by a person to it triggers that on change event.
I have tried .trigger and .change and couldnt get either of them to work.
The only reason your code does not work is the order you are executing it. You need to connect the handler before triggering it:
JSFiddle: http://jsfiddle.net/3y5hmyf0/1/
// Wire up event handler
$('select[name="blah"]').change(function(){
alert('changed');
});
// Now generate the event
$('select[name="blah"]').val(3).trigger('change');
Note: Your manual change trigger is still required as a change event must normally be triggered by user interaction. Setting the value is not enough.
$('select[name="blah"]').change(function(){
NotifyChanged();
});
function NotifyChanged() {
alert('changed');
}
If you want to test the logic in the changed function, just call it.
I have an <input> element that can either have the focus set via code, or as the result of a mouse click.
If the user clicks on the input, then the click event handler will fire - all well and good. If the element receives the focus via some other way (e.g. via code) then I want to manually trigger the click event so that the handler will also fire.
I could do this:
$elem = $('input');
$elem
.on('focus', function() { $(this).trigger('click') })
.on('click', function() { alert('Clicked!') });
However, this will result in click handler being fired twice; once for the click event and once for the focus event.
Is there any way to selectively trigger the click handler only if the focus was not received as the result of a click event?
UPDATE
This is a very simplified version of my problem, so I can't do things like bind both handlers to the focus event etc. I'm trying to merge two third-party pieces of code.
The .trigger() function adds a property isTrigger in the event object to identify that the event was triggered by its usage. Although, it is not documented the property is still present in jQuery 1.8.3 but it seems to only be used internally.
Anyways, you can make use of the extraParameters parameter to add a custom property to the event object. For instance,
$(this).trigger('click', {
isTrigger: true
});
It will keep the compatibility with isTrigger even if it is gone in a future release.
After doing some more research it appears that there is no way of guaranteeing which event will fire first: click or focus. (There doesn't seem to be a standard that dictates the order of events.)
This means that when the focus event fires there's no way to determine if a click event will or will not be triggered by the browser shortly afterwards.
I managed to solve the issue by using setTimeout() to run a test about 100ms after the focus event fired to check if the click event had fired. The third-party code that I was using (bound to the click event) added an extra class to the <input>, so I was able to check for that.
You can tap into the mousedown event which fires before the focus event. When you click a focusable object the order of events is as follows... mousedown, focus, mouseup, click.
You could set a flag in the mousedown event and then check for it in the focus event to see if the focus came from a mouse click. Obviously make sure to clear the flag in the focus event handler. Every application is different, but tapping into the mousedown event allows you to figure out a solution.
Here is a JSFiddle demonstrating the order of events... http://jsfiddle.net/ek7v7/
$elem = $('input');
$elem
.on('focus', function() { alert("Focused!") })
Focus can be fired by focusing the input by using tab, clicking it, or by using .focus()
Is there a reason for on('click', ...)?
Heres my link:
http://tinyurl.com/6j727e
If you click on the link in test.php, it opens in a modal box which is using the jquery 'facebox' script.
I'm trying to act upon a click event in this box, and if you view source of test.php you'll see where I'm trying to loacte the link within the modal box.
$('#facebox .hero-link').click(alert('click!'));
However, it doesn't detect a click and oddly enough the click event runs when the page loads.
The close button DOES however have a click event built in that closes the box, and I suspect my home-grown click event is being prevented somehow, but I can't figure it out.
Can anyone help? Typically its the very last part of a project and its holding me up, as is always the way ;)
First, the reason you're getting the alert on document load is because the #click method takes a function as an argument. Instead, you passed it the return value of alert, which immediately shows the alert dialog and returns null.
The reason the event binding isn't working is because at the time of document load, #facebox .hero-link does not yet exist. I think you have two options that will help you fix this.
Option 1) Bind the click event only after the facebox is revealed. Something like:
$(document).bind('reveal.facebox', function() {
$('#facebox .hero-link').click(function() { alert('click!'); });
});
Option 2) Look into using the jQuery Live Query Plugin
Live Query utilizes the power of jQuery selectors by binding events or firing callbacks for matched elements auto-magically, even after the page has been loaded and the DOM updated.
jQuery Live Query will automatically bind the click event when it recognizes that Facebox modified the DOM. You should then only need to write this:
$('#facebox .hero-link').click(function() { alert('click!'); });
Alternatively use event delegation
This basically hooks events to containers rather than every element and queries the event.target in the container event.
It has multiple benefits in that you reduce the code noise (no need to rebind) it also is easier on browser memory (less events bound in the dom)
Quick example here
jQuery plugin for easy event delegation
P.S event delegation is pencilled to be in the next release (1.3) coming very soon.