I detect unsaved data within my form in order to warn the user if he leaves the page. This works so far for all elements, except for the primefaces calendar element.
Currently my approach relates to this answer. But this does not work for the calendar element. I found out that the change listener does not work for programmatically set values in general. Probably this is the reason for my problem. So I tried to implement my own very simple "change listener", by registering a click and blur listener to all my calendar elements. In the click listener I temporarily save the current value of the calendar element. In the blur listener I compare the saved value with the current value. But this approach doesn't work, because I'm not able to get the changed value of the calendar element within the blur listener. I tried to get the value in several ways:
$(this).val();
this.value;
$(this).html();
$(this).attr('value');
But in each case I get the old value. So I think the "simple change listener"-approach doesn't work as well.
My primefaces version is 3.4.2.
JSF implementation (probably not relevant) is: Mojarra 2.1.6
I don't know anything about primefaces but it uses the jquery ui calendar. So you could use the onSelect option of it to detect a change.
$('.hasDatepicker').each(function() {
var onSelect = $(this).datepicker('option', 'onSelect');
$(this).datepicker('option', 'onSelect', function() {
// some change happend here, set your flag that the form is dirty e.g.
setConfirmUnload(true);
// we call the original onSelect to not break the primefaces ajax change event
if(onSelect) { return onSelect.apply(this, arguments); }
});
});
Related
I have an APEX application where there are many drop down items. I've bound change event handlers to them using the bind function of jQuery.
Now when I load the content of a drop-down programmatically using $('#ELEMENT').trigger('apexrefresh'), the drop-down reloads but the change event handler fires automatically.
How do I prevent this from happening? I tried avoiding binding the event handler using bind and instead adding the onChange attribute to the element. The incorrect behaviour was still present.
Here is the skeletal code:
$(document).ready(function()
{
$('#P7021_MSG_DEF').bind('change', function(e)
{
console.log('bound function onChange() msg_def');
updateStartWord();
}
);
});
function updateMsgDef()
{
console.log('function updateMsgDef() ');
$('#P7021_MSG_DEF').one('apexafterrefresh', function()
{
if( $x('P7021_RESTORE_CHK').value == 'Y')
{
setdefault('P7021_MSG_DEF', vJson.msg_def);
}
updateStartWord();
}
).trigger('apexrefresh');
}
In the above code, when the updateMsgDef is called from another function the function updateStartWord() gets called twice - once by updateMsgDef() itself and again by the onChange handler that was bound to P7021_MSG_DEF item.
If anyone could help on this?
Calling $('#ELEMENT').trigger('apexrefresh') is going to trigger the change event. Short of going back to the drawing board altogether, the solution is going to be a hack whatever you do. You could poke about in (and quite possibly break) Oracle's javascript. You could write your own AJAX to populate the select list.
The easiest way might be to check in your onChange event which element currently has focus, eg:
onChange = "if($( document.activeElement).attr('id')=='YOUR_PAGE_ELEMENT')
{ $( document.activeElement).trigger('apexrefresh'); };"
If the user has changed the select list, it should still have focus. There's no guarantee that will work in all browsers, but I think it should be ok in current Chrome and IE versions.
I've been in a similar situation to yours, and have come to accept that if the page logic is too complicated to implement using DAs, maintaining it is likely going to be a nightmare whatever happens. Much as I like "proper" programming, Apex is really all about the declarative controls.
There exists a website implemented with ExtJS 3.1.
I want to pre-fill some fields automatically. The problem is, that some fields are not validated by ExtJS when automatically filling them.
I can trigger the validation by firing ExtJS's blur event:
field.fireEvent('blur', field);
However, I don't want to do this. I want that validation to be triggered by a normal event triggered via jQuery:
$field.blur();
What I am asking here is the following:
How to trigger the blur event of a textbox in the same way the browser does it, so that also ExtJS's event handlers run?
BTW: The reason why I don't want to manually fire the ExtJS event is simple: This solution seems to work for ExtJA 3.1 but no longer for 4.2 and I don't want to write special handling code for every version of ExtJS.
If you want to play around a little bit:
Here is the URL: https://www.pantaenius.com/en/service/login/request-a-quote.html?utm_source=http%3A%2F%2Fwww.pantaenius.com%2Fen%2Famerican-yacht-insurance.html&utm_medium=direct&domain_segment=33
Open it in Chrome, open Chrome's developer console and paste the following text:
delete console.log
var $city = jQuery('#ext-comp-1080');
var city = Ext.ComponentMgr.all.filterBy(function(x) { return x.isXType('combo') && x.id==='ext-comp-1080'; }).items[0];
var blurEventFireFn = city.events.blur.listeners[0].fireFn;
city.events.blur.listeners[0].fireFn = function(field) { console.log('ExtJS blur fired!'); blurEventFireFn(field); };
When you click in the City field and then in some other field, you will see the output ExtJS blur fired! in the console. You will see the same output when you execute city.fireEvent('blur', city);. However, you won't see that output when you execute $city.blur();, $city.trigger('blur'); or
var event = document.createEvent('HTMLEvents');
event.initEvent('blur', true, true);
$city.get(0).dispatchEvent(event);
Any ideas how to create this bridge between normal events and ExtJS events would be greatly appreciated.
Simulating the native event with your bit of code does work (in non-IE browsers):
var event = document.createEvent('HTMLEvents');
event.initEvent('blur', true, true);
$city.get(0).dispatchEvent(event);
However you should avoid the problem rather than giving it a weird cure, by using the validator of the field instead of a blur event listener. This way, the setValue method of the field will trigger its validation...
If you're really stuck with it, instead of adding a (probably fragile) layer of complexity by simulating events, I would just call the onBlur method of the fields directly. That's the handler that is added to the DOM by Ext. It is present in 3.x and 4.x, and it doesn't rely on specific browsers...
I am using a jQuery DateTimePicker addon (By: Trent Richardson) and it will only close after you select the date AND the time. However some users don't care about the time and they want the Calendar to close after they choose the date only.
I managed to close the Calendar after picking the Date only but I need to implement a double click and not a single click. How do I do that?
Here is my code:
$(jqCompletedEndID).datetimepicker({
ampm: true,
onSelect: function(){
$(this).datepicker("hide"); $(this).blur();
}
});
I know there is a dblclick event in Javascript but not sure how to apply it in this context.
Thank you!
I have run into the exact same problem / requirement. I tried something very similar to Alex's solution, but it doesn't work because the datetimepicker seems to wipe all styles and event bindings when a day is selected (I assume it's being reconstructed, but haven't checked), making it impossible for the dblclick event to fire.
I've come up with a solution which isn't pretty but does work. You can use the datetimepicker's onSelect event to bind a couple of handlers as follows:
(assuming this._$input is a jQuery reference to the input control being used)
this._$input.datetimepicker({
...
onSelect: function() {
var self = this;
setTimeout(
function () {
$('.ui-datepicker-current-day').bind('click', function () { self._$input.datepicker('hide'); });
$('.ui-datepicker-current-day').bind('dblclick', function () { self._$input.datepicker('hide'); });
},
0
);
}
You're probably wondering why I bind both click and double click, particularly in light of my claim above that double click won't work. It seems that in Chrome, FireFox, Safari, and Opera the event will trigger the "click" event, but in IE it will trigger the "dblclick" event. Also, if you're wondering about the setTimeout, it's required because the popup won't be constructed until after the method is finished, so those selectors won't return anything if executed without it.
You've no doubt noticed that my solution will also close the picker when the currently-selected date is clicked whether or not it's part of a double-click. This is intentional in my case (and I also trigger the same logic in the beforeShow event to wire the handler so clicking on the currently-selected date will always close the picker). In your case, if you want it to work strictly with double clicks, all I can recommend is that you track the time between clicks and make sure they arrive within some threshold.
Try this...
$('#datepicker').datepicker({
//...
});
$('table.ui-datepicker-calendar a').bind('dblclick', function() {
$('#datepicker').val();
});
You can add a doubleclick event handler on the html tag itself. You would be having a emtpy div for the datepicker, so modify it as
<div id="datepicker" ondblclick="close()"></div>
In the close() function write the code to hide the datepicker div.
I have a fairly large javascript class that generates an complete ajax-generated application. In one version of the ajax page there are a number of dropdown menus. These menus can get created and destroyed at various points during the life cycle of the application.
This is the behaviour I see:
User opens page version 1: no dropdowns
User goes to page version 2: dropdowns added with jQuery onchange event. Work as intended.
User returns to version 1 of page, dropdowns removed.
User returns to version 2 of page, dropdowns added again (using same element IDs)
dropdowns will now have 'double' event handling, triggering the event for each onchange.
The behaviour I'm struggling with is as follows.
On the initial page load, I add an onchange event:
function myClass(){
//Initiate once for current and future elements.
jQuery(document).on('change',".mydropdowns",
function(e){
self.submitDescriptionChange(this);
}
);
}
myClass.prototype.submitDescriptionChange = function (el){
doSomeAjaxStuff();
}
This works fine, except that each time the user goes to pages version 1 and returns to page version 2, the event gets multiplied. Very quickly you can end up with the event firing 20 times per change event, which in this case creates 20 ajax calls.
Logically, by using jQuery.off() I should be able to avoid this. But what happens instead is that the event is removed from both past and future elements, which means that when I recreate page version 2, the dropdowns won't work.
Every way I have tried this (and I've tried LOADS), I either end up with no event firing, or multiple events firing. I cannot seem to find a way to add/replace the elements whereby the event is only ever fired once.
Any ideas how I can solve this?
UPDATED
Yeah, so it turns out I misdiagnosed the problem. It actually came from repeatedly rebinding a 'hashchange' event, rather than rebinding the onchange event. Apologies for misdirection. Moving to bind() function to somewhere where it only executed once fixed the issue.
Since you do not want .off() to remove your events from other pages, I would suggest using namespaces for your events. For example, something like this:
function myClass(pageno) {
var pref_ev = 'mypage' + pageno + '.' + 'change';
$(document).off(pref_ev).on(pref_ev, ".mydropdowns", function(e) {
self.submitDescriptionChange(this);
});
}
This way, each page will have its own "change" event such as "mypage1.change". The event is still registered normally as a change event; the prefix namespace "mypage1" is used to only perform the .off() call on the right events.
I am not sure what plugin you are using for your dropdown menus but there should be a "destroy" method on that plugin. If you call that when removing the dropdowns that should work. Also, if you are only hiding the second page and not actually removing it from the DOM you dont have to re-invoke the plugin as the plugin will still be saved on the element.
Here's a jsfiddle to show what the issue is:
http://jsfiddle.net/boblauer/BgvV4/
I'm trying to fire the change event after a text field is updated. Unfortunately, inside the subscribe method, the text box's value hasn't been updated yet, so when I figure the change event, it's fired too soon.
I need to fire the change event because I have 3rd party code that is out of my control that relies on the change event.
Any suggestions?
A simple solution is to wrap your call to $("#text1").change() in a setTimeout with a timeout of 0. That's enough to let knockout do the (synchronous) update to the textbox value before the jquery change handler gets invoked.
I forked your fiddle to demonstrate:
http://jsfiddle.net/SuRYa/1//
If this is something you need to do a lot, a better solution is probably to wrap this behavior in a custom binding where the "update" callback of the binding would fire the jquery change event on the updated element.
bmode is right, a custom binding will do it. Although this answer is a bit late, here is the binding in case it helps anyone subsequently reading this post. It updates the value of the textbox using jQuery - the DOM is now updated in order for Bob's 3rd party code to work - so then it fires the change event.
ko.bindingHandlers.valueAndFireChange = {
update: function(element, valueAccessor) {
var val = ko.unwrap(valueAccessor());
if (val == undefined) return;
$(element).val(val);
$(element).change();
}
};
Here's an updated version of Bob's fiddle showing this in action:
http://jsfiddle.net/BgvV4/17/
I changed the alerts to console.log, so you'll need the console open to see the useful info.