I actually have a form with a JQuery focusOut event on some input.
But if the focus is on one of this input and the user want to submit. I need to wait the end of the focusOut event before executing the submit event.
Someone know how to do it?
Shouldn't be too hard using a pair of flags. If you want to hold up the form submission pending the completion of something, just:
Set a flag (inProgress or whatever) when you start the thing you want to wait for
Hook the submit event
If the inProgress flag is set, cancel the submit event and set a flag saying the form needs submitting (submitPending or whatever)
When the other thing completes, clear the inProgress flag, and if submitPending is set, submit the form
It's important that you know that the thing will complete. You don't want to cancel the submission in #3 if you don't know, for sure, that #4 will fire.
So for instance, assuming #theField is the field and #theForm is the form, it would look something like this:
(function() {
var inProgress = false,
submitPending = false;
// #2
$("#theForm").submit(function() {
if (inProgress) {
// #3
submitPending = true;
return false;
}
});
$("#theField").on("focusOut", function() {
inProgress = true;
startThingThatTakesTimeLikeAnimationOrAjax(function() {
// This is the completion callback of the thing that takes time
// #4
// No longer in progress
inProgress = false;
// Submit if one is pending
if (submitPending) {
$("#theForm").submit();
}
});
});
})();
Related
I'm opening my chat window programtically using ToggleChatVisibility which works great, but it does not fire the relevent FlexWebChat.Action
<script>
const operatingHoursCheckMsg = async function () {
Twilio.FlexWebChat.Actions.on("afterToggleChatVisibility", (payload) => {
console.log('Not Working');
});
}
await initateWebChat.init();
}
function Test() {
operatingHoursCheckMsg();
Twilio.FlexWebChat.Actions.invokeAction("ToggleChatVisibility");
}
</script>
<button type="button" onclick="Test()">Click to open and close chat window</button>
the afterToggleChatVisibility event fires if I close and reopen the chat using the chat box ui, but not if I click my button.
How can I trigger this event properly?
I think you have a race condition causing this issue. You defined the operatingHoursCheckMsg function as async even though there isn't an asynchronous call involved (though maybe there is in your full script) but in your Test function you do not wait for the promise to resolve before invoking the action. I think this means that JavaScript placed the promise on a queue to be handled asynchronously by the event loop, and then ran the next synchronous line of code. So you invoke the action before the event listener is registered.
It also looks as though you want to use the button to continue toggling the chat open and closed, so you should probably not be attaching a new listener every time the button is clicked.
I'd recommend you set up the one listener after you have initiated the webchat, like this:
<script>
const operatingHoursCheckMsg = async function () {
// Do operating hours check
}
await initateWebChat.init();
Twilio.FlexWebChat.Actions.on("afterToggleChatVisibility", (payload) => {
console.log('Chat toggled!');
});
}
async function Test() {
await operatingHoursCheckMsg();
Twilio.FlexWebChat.Actions.invokeAction("ToggleChatVisibility");
}
</script>
<button type="button" onclick="Test()">Click to open and close chat window</button>
I'm loading the Zendesk web widget into a page, and this is the event handler for when it's loaded in
scriptElement.onload = function () {
zE(function () {
$zopim(function () {
$zopim.livechat.button.setHideWhenOffline(true);
$zopim.livechat.setOnStatus(function (status) {
console.log('status',status);
status === 'online' ? $zopim.livechat.button.show() : $zopim.livechat.button.hide();
});
$zopim.livechat.setStatus('offline');
});
});
};
It has the setOnStatus event handler which should trigger anytime the status changes. It seems to be triggered once when the page initially loads in. You'd expect it to be triggered as well everytime I call the setStatus method, but that's not the case. Where I log the status, it's always just 'online', and it only happens once.
What I'm trying to do is force the button to disappear when the status is offline. Yet setting the status to 'offline' doesn't hide the button, just displays the offline version (i.e. a button which lets me send an offline message, rather than a live chat).
I thought the setHideWhenOffline method might have helped, but that doesn't seem to make any difference in this case.
Any ideas?
Actually I found the solution I needed here, this prevents the offline button appearing.
window.zESettings = {
webWidget: {
contactForm: {
suppress: true
}
}
};
https://developer.zendesk.com/embeddables/docs/widget/settings#suppress
I call bindElement of the view to execute the webservice and get data.
The call is executed correctelly if the key of tha path is different.
The event "dataReceived" didn't trigger in the second time of the same path.
Example:
First Time:
I call bindElement with the path 'ABCD', it's working, dataReceived is trigerred.
The second time:
If I call the same path 'ABCD', noting is happend, the event dataReceived didn't trigger.
If I call another path 'EFGH', it's working and dataReceived is trigerred.
So what can I do to trigger the event with bindElement even if the path is the same ?
Thanks.
cb = this.getView().byId("cb").getValue();
vpath = "/ZDECL_INSet('"+ cb +"')";
this.getView().bindElement({
path: vpath,
mode: sap.ui.model.BindingMode.TwoWay,
events: {
dataReceived: function(rData) {
var data = vthis.getView().getModel().getProperty(rData.oSource.sPath);
msg = "";
if(data.TMSG1 == 'E'){
msg = data.Msg1;
sap.m.MessageBox.show(msg, {
icon: sap.m.MessageBox.Icon.ERROR,
title: vtitle,
actions: [sap.m.MessageBox.Action.YES],
onClose: function(oAction) {
oCB.focus();
oCB.setValue(null);
}
}
);
}
else{
sap.m.MessageToast.show("Good", {
duration: 2000,
width: "200px"
});
oCB.focus();
oCB.setValue(null);
}
}
}
});
DataReceived will be fired only if data is received. So second time data will not be requested, so dataReceived won't be fired.
Use "change" event for this.
As example of the three events involved here, in the order they are fired.
events: {
dataRequested: function(){
//Here the code to be executed when a request to server was fired. For example, set a "waitingForData" flag to true
},
change: function(){
//Here your magic to be executed everytime you do ElementBinding. For example, check if your "waitingForData" flag is false, if so, do whatever you want with the data you already have.
},
dataReceived: function(rData){
//Here your logic to be executed when data from server is received. For example, set your "waitingForData" flag to false, and do whatever you want with the data have reveived.
}
}
If you call bindElement with the same path twice, the second time won't actually trigger a new call to get new data, since the path didn't change. Since there won't be a second call, there won't be a second dataReceived event.
You can fire it manually if you want to trigger it again.
this.getView().getElementBinding().fireDataReceived()
Based on your code, it looks like you're trying to execute code from your server when you get the response. I would use the attachEventOnce method from the EventProvider class.
oModel.attachEventOnce("requestCompleted", function(oEvent) {
//execute your code here
}, this);
this.getView().bindElement(sPath);
The requestCompleted event will fire after data comes back once, and then clear the event from happening again, that way you don't always run every response from every request through the same callback function.
I have a page that is created completely using Knockout. In one of the templates, clicking on a link will display a JQuery Datepicker control to select a date. Upon selecting the date, a function executes using the selected date and the Datepicker closes. That much works just fine.
It can take several seconds from when someone selects a date until the Datepicker closes. This is due to a function that is called (LoadAppointmentTimeSlots) which needs to run synchronously and can take a while to do what it does. To address this, I would like a DIV to appear that provides feedback to the user that the system is working ("#loading").
THE PROBLEM is that the DIV does not appear until after the LoadAppointmentTimeSlots function executes (by which time the DIV gets hidden again). I have experimented with setTimeout in several ways, but nothing has worked.
Below is the "offending" code:
var SchedulingViewModel = function () {
var self = this;
...
self.Date_OnClick = function () {
var selectedDate;
$("#calendarPopup").append('<div id="datepicker" />');
$("#datepicker").datepicker({
dateformat: 'mm-dd-yy',
changeMonth: true,
changeYear: true,
setDate: new Date(),
minDate: 0,
maxDate: self.SelectedRFVInterval() - 1,
onSelect: function (datetext, inst) {
selectedDate = datetext;
$("#loading").show();
self.LoadAppointmentTimeSlots(datetext); // function within view model that uses $AJAX in sync mode to return time slot data
$("#loading").hide();
$('#calendarPopup').dialog('close');
}
});
};
...
}
The difficulty you are running into is because show() is executed asynchronously, and since javascript is executed in a single thread, that means they have to wait until all synchronous code (such as LoadAppointmentTimeSlots) is done.
To get your desired behaviour, put everything after the show() call into the callback for the show command. That way LoadAppointmentTimeSlots won't execute until the show() call is done. Here is how:
// ... other code
$("#loading").show(function() {
self.LoadAppointmentTimeSlots(datetext);
$("#loading").hide();
$('#calendarPopup').dialog('close');
});
However, it might be better to change your ajax call in LoadAppointmentTimeSlots to be asynchronous and move the hide() and dialog('close') calls to the callback of the ajax call. This allows javascript to keep doing other things while you are waiting for LoadAppointmentTimeSlots to finish. That might look more like this:
// ... other code
$("#loading").show()
self.LoadAppointmentTimeSlots(datetext, function() {
$("#loading").hide();
$('#calendarPopup').dialog('close');
});
// ... more code
function LoadAppointmentTimeSlots(datetext, alwaysCallback) {
// Prepare request details
$.ajax( "/myendpoint?param=foo" )
.done(function(data) { alert("success"); }) // do something with data
.fail(function() { alert("error"); })
.always(alwaysCallback); // called on both success and failure of ajax call
}
I'm using a jQuery modal dialog to display a 'Please Wait' type message to a user when a ajax call is made back to the server.
I'm doing this by making the dialog visible using the jQuery ajaxSend method. And I close the dialog using the jQuery ajaxComplete method.
All fairly routine stuff I'm sure.
However if the call takes a very short about of time (say 10 milliseconds) then I want wait until a second has passed since making the dialog visible before I then close the dialog. The reason is to provide user feedback ... and to stop the horrible flicker of the dialog quickly opening and then closing.
How can I achieve this using jQuery and / or ajax?
Many thanks for any pointers.
Would a better paradigm be to actually wait for a period of time before showing the dialog? If you have a responsive app then it would make sense to only show the modal if the response does not come back within say 100ms. This would avoid delaying the UI just to avoid flicker which is what you are proposing.
Note I am using beforesend and success here to dummy up the code
var timerid;
beforeSend: function(){
//open the dialog in 100 milliseconds
timerid = window.setTimeout( function(){
$('#dialog').dialog('close');
}, 100)
},
success: function(){
//cancel the showing of the dialog if not already called
window.clearTimeout( timerid );
//close the dialog regardless
$('#dialog').dialog('close');
}
If you dont like this idea then simplay put the dialog close function inside a setTimeout within the ajax complete callback e.g
complete : function(){
//close the dialog in 1 second
window.setTimeout( function(){
$('#dialog').dialog('close');
}, 1000)
}
I've pulled together a solution for this myself - based on the great response from 'redsquare' and some further reading.
I have used the code from redsqure to open the modal dialog only after a given duration has passed - thus hopefully not having to open the modal at all.
For when the modal has opened I've added code to ensure it remains open for a minimum of 800 milliseconds ... just to avoid the possibility of it quickly flashing up on the screen. To achieve this I start a javascript timer in the 'ajaxSend' method and then I use the 'ajaxComplete' method to determine whether the modal is open. If so I use the timer to calculate how long it has been open for and make up the difference to 800 milliseconds. I adapted a script I found on line for my timer. Script below.
var timer_ms = 0;
var timer_state = 0;
/// <summary>
/// Responsible for starting / stopping the timer. Also calculates time.
/// </summary>
function timerStartStop() {
if (timer_state == 0) {
timer_ms = 0;
timer_state = 1;
then = new Date();
then.setTime(then.getTime() - timer_ms);
}
else {
timer_state = 0;
now = new Date();
timer_ms = now.getTime() - then.getTime();
}
}
/// <summary>
/// Resets the timer.
/// </summary>
function timerReset() {
timer_state = 0;
timer_ms = 0;
}
Thanks.
Thanks.