SAPUI5 - bindElement doesn't work the second time - path

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.

Related

Zendesk web widget status not correctly updating and button not hiding

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

Preventing every push notification being executed iOS titanium

If I get multiple push notifications whilst app is in foreground. The callback method will execute every push notification one by one.
callback : function(e) {
if (e.inBackground == 1) {
//came from background - do something.
} else {
// Titanium.UI.iPhone.setAppBadge(null);
//check type, if it is chat.
if (type == 'chat') {
//check if window is already opened or not, if so fire event handler
if (currentWindow == '_chatWindow') {
//update view directly after entering app from the background. Fire event handler
Ti.App.fireEvent('_updateChat', {});
} else if (currentWindow == '_messages') {
//refresh messages screen if on messages screen and chat message arrives
//update view directly after entering app from the background. Fire event handler
Ti.App.fireEvent('_updateMessages', {});
} else {
//display local notification
}
}
If the push notification has come from the background it is easy to deal with, as the push notification that is activated is the one the user chooses to swipe. However, if multiple push notifications come into the foreground and say it's chat, it will execute them multiple times.
How can I handle push notifications in the foreground better? Thanks
Update:
tried this code without much luck
Ti.App.addEventListener('_displayNotification', function(e) {
//store all push notifications in array
var pushArray = [];
var countPushNotifications;
//currentTime to cross reference
var currentTime = new Date();
if (currentTime - Alloy.Globals.pushTime < 3000) {
//do something
pushArray.add(e.PushNotificationData);
} else {
//after 3 seconds remove event handler
//fire event to filter array and process notification, reset time for next event
Alloy.Globals.pushTime = null;
Ti.App.removeEventListener('_displayNotification', {});
}
//first push notification, will be the current time
if(Alloy.Globals.pushTime==null){
Alloy.Globals.pushTime = currentTime;
}
});
Trying to get all the push notifications inside the array, for further filtering.
Update 2:
if (Alloy.Globals.countPushNotificationsFlag == 1) {
Alloy.Globals.countPushNotificationsFlag = null;
setTimeout(function() {
Ti.App.fireEvent('_displayNotification', {
PushMessage : message
});
}, 6000);
} else {
Alloy.Globals.countPushNotificationsFlag = 1;
Ti.App.fireEvent('_displayNotification', {
PushMessage : message
});
}
I have tried to execute push notifications alternatively.
1st notification - fires instantly.
2nd notification - fires after 6 seconds.
3rd notification - instantly.
4th notification - fires after 6 seconds.
and so on...
however the code only works for
notification 1 and 2.
Fails when it hits the 3rd notification.
you can check if Push is received in foreground or background using inBackground Property of push here is the documentation
Hope it helps.
I haven't got the Titanium experience to give you actual code, but this is the approach you need to take:
When you receive a notification, check to see if a (global) boolean receivedNotification is false
If it is false, set it to true, store the event into a global and schedule a setTimeout function for, say, 3 seconds, to process the event and reset receivedNotification to false
If receivedNotification is true, update the global event to the newer notification
In the process event method that is triggered via the timer your will do what you currently do in the first section of code.
This will ensure that the event is processed no longer than 3 seconds after it is received and that events will be processed, at most, once every three seconds.
Your code looks pretty close, except you are trying to fire the first event immediately and then subsequent events after a delay. Unfortunately I don't believe that this is possible, because you have no way of seeing if there are events queued immediately. I think that you are always going to have to incur the delay, but you can tune the delay to find a balance between responsiveness and reduced API calls -
if (Alloy.Globals.countPushNotificationsFlag == null) {
Alloy.Globals.countPushNotificationsFlag = 1;
Alloy.Globals.messageToPush=message;
setTimeout(function() {
Alloy.Globals.countPushNotificationsFlag = null;
Ti.App.fireEvent('_displayNotification', {
PushMessage : Alloy.Globals.messageToPush
});
}, 3000);
}
else {
Alloy.Globals.messageToPush=message;
}

Telerik Grid Double Click Display Twice the Number of Clicks

I have a telerik grid that I am using to do a post to the server when the user double click on a row. It appears to work fine until I place an alert in the code and notice some odd behaviors. When I double click on a row for the first time, the alert comes up twice and continues to display twice the number of times that I click. I mean - it comes up twice the first time, 4 times the second time, 6 times the third times, and it continues on. Below is the scripts that I am using to call the grid.
function DisplayStudent(e) {
if (IsStudentGradeAvailable == "True") {
$('tr', this).live('dblclick', function () {
var row = e.row;
var StudentId= row.cells[0].innerHTML;
var StudentGrade= row.cells[1].innerHTML;
var data = { "StudentId= ": StudentId= , "StudentGrade": StudentGrade };
var url = '#Url.Action("Student", "StudentGrade")';
$.ajax({
url: url,
type: 'post',
dataType: 'text',
data: data,
success: function (data) {
alert("Success");
},
error: function (error) {
alert("Error");
}
});
});
}
}
Live attaches an event handler. You want one event handler, so you should call the live() method only once. Given your code, this implies that DisplayStudent() should only be called once.
If DisplayStudent() is called n times, you will have attached n event handlers, each of which alerts you when you click.

Knockout View Instantiating JQuery Datepicker Control onSelect Not Updating DOM Until JS Finishes Executing

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
}

Wait the end of a JQuery event to execute an other

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();
}
});
});
})();

Resources