When the client open the webapp, how to restore his last state with router-ui? - angular-ui-router

I use router-ui for my angular single page
I hear the $stateChangeSuccess event to store in localStorage the current state and his params :
$scope.$on('$stateChangeSuccess', function(event, toState) {
localStorage.lastState = toState.name;
localStorage.lastStateParams = JSON.stringify($stateParams);
});
My question is :
When the client open the webapp, I want to restore his personnal last state but where can I put this code ?
$state.go(localStorage.lastState, JSON.parse(localStorage.lastStateParams));
// UPDATE
Actually i put this code in $stateChangeSuccess event like this :
$scope.$on('$stateChangeSuccess', function(event, toState) {
if (toState.name !== 'welcome') {
localStorage.lastState = toState.name;
localStorage.lastStateParams = JSON.stringify($stateParams);
}
if (toState.name !== localStorage.lastState) {
$state.go(localStorage.lastState, JSON.parse(localStorage.lastStateParams));
}
});
The problem with this solution is the process is like this at opening app :
localhost (user open the app)
localhost/#/welcome ( because the $urlRouterProvider.otherwise('/welcome') proc before the $stateChangeSuccess event)
and then : localhost/#/articles/423 (on $stateChangeSuccess event)
So i'm sure i do bad, someone know the good method ?
Thanks very much,

As always the solution is always easier than you think !
In my main controller :
$scope.$on('$stateChangeSuccess', function(event, toState) {
// Timeout is required because the document.location.hash is not upadated immediatly
$timeout(function() {
localStorage.hash = document.location.hash.substr(1);
}, 100);
});
At end of my routes :
// Default
$urlRouterProvider.otherwise(localStorage.hash || '/welcome');

Related

In Office.js, How do we use the Office.context.mailbox.item.saveAsync response (overcoming ErrorItemNotFound)?

The DOC says:
Note: If your add-in calls saveAsync on an item in compose mode in order to get an item ID to use with EWS or the REST API, be aware that when Outlook is in cached mode, it may take some time before the item is actually synced to the server. Until the item is synced, using the itemId will return an error.
As best I can tell, that's the cause of my ErrorItemNotFound problems trying to use that ID? (It's a shame Microsoft did not specifically tell us what error to expect).
Since my code is invoked asynchronously - how exactly do I wait for the noted "some time"? Do we set a timer to re-try every second or something? When do we give up?? Is there something else I can do which will give me a call-back to continue when the item sync has completed? [FYI - even waiting 10 seconds after the save does not work for me]
Be aware that I expect my users may be composing mail with large attachments, so while most no-attachment messages should sync in less than 1 second, folks attaching large pdf/zip/etc files could easily cause more than 1 minute delays here...
The best what you could do is to start polling for an item appeared on the server side. For example, you may try an ugly solution when you use sub-sequential EWS query with Id you've got from saveAsync in the loop and wait for success.
For example, I've noticed the following example how developers try to handle such scenarious:
app.makeEwsRequestAsync = function (request, callback, countRepeatIfCrash, callbackIfCrash) {
try {
Office.context.mailbox.makeEwsRequestAsync(request, function (asyncResult) {
try {
if (asyncResult.status !== 'succeeded') {
app.showError(asyncResult.error.message);
return;
} else {
var $result = app.getResponseElementByName(asyncResult.value, 'm:ResponseCode');
if ($result) {
var responseCOde = $result.text();
if (responseCOde !== 'NoError') {
if (countRepeatIfCrash > 0) {
setTimeout(function () {
app.makeEwsRequestAsync(request, callback, countRepeatIfCrash - 1);
}, 500);
} else if (callbackIfCrash) {
setTimeout(function() {
callbackIfCrash();
}, 500);
} else if (responseCOde === 'ErrorItemNotFound') {
app.showError('EWS ' + responseCOde, function () {
app.makeEwsRequestAsync(request, callback, 70);
});
}
else {
app.showError('EWS ' + responseCOde);
}
return;
}
}
}
callback(asyncResult);
} catch (e) {
app.showError(e);
}
});
} catch (e) {
app.showError(e);
}
}
See App for Outlook: EWS request failed with item Id returned by item.saveAsync on compose new message for more information.
You may also can try using the simple GetItem request:
<GetItem xmlns="http://schemas.microsoft.com/exchange/services/2006/messages">
<ItemShape>
<t:BaseShape>IdOnly</t:BaseShape>
</ItemShape>
<ItemIds><t:ItemId Id="' + itemId + '"/></ItemIds>
</GetItem>
The request should return ChangeKey if item was created on exchange.

Spring MVC, Rest Ajax Call and Session Scope Objects

I want to solve following issue. I have a Spring-MVC Application with Thymeleaf, with a post request (sent by a form) I trigger a simulation task, what could take several minutes. The task process big number of data and we would like to have a progress bar via JavaScript. If there are two sessions, the simulation should be triggered independently and each browser shows its progress status.
Currently we have a solution, what is not really working well all the time.
The MVC Controller gets the Post request:
#Autowired SimulatorView view; // SESSION SCOPE
#PostMapping("/view")
public String run(#ModelAttribute(CHECKS) ChecksDto checksWrapper, Model model) throws InterruptedException, ExecutionException {
view.setStatisticDto(simulate(checksWrapper)); // Can take several minutes
return "simulation/result :: simulated";
}
When I trigger the simulation on my WebGUI, a progress bar has been displayed and via JavaScript I am calling Rest Methods frequently to ask for the status of the progress.
RestController
#RequestMapping("simulation/api")
public class SimulatorApi {
#Autowired SimulatorView view; // SESSION SCOPE
#RequestMapping("/progressStream")
public double progressStream() {
return view.getProgress().progressStream();
}
#RequestMapping("/progressInvoice")
public double progressInvoice() {
return view.getProgress().progressInvoice();
}
}
My JavaScript code snippet looks like:
function registerSimulationRunEvent() {
// this is the id of the form
$("#simulatorForm").submit(function(e) {
handleSimulationStarted();
var url = location.protocol + "//" + location.host + "/fdsclient/simulation/view";
$.ajax({
type: "POST",
url: url,
data: $("#simulatorForm").serialize(), // serializes the form's elements.
success: function(data) { handleSimulationFinished(); },
error: function(xhr, error) { handleSimulationError(); }
});
e.preventDefault(); // avoid to execute the actual submit of the form.
});
}
function handleSimulationStarted() {
replaceResultPanelRunning(); // THYMELEAF FRAGMENT EXCHANGE
}
function handleSimulationFinished() {
stopResultPanelAnimation(); // STOP PROGRESS BAR ANIMATION
replaceResultPanelSimulated(); // EXCHANGE THYMELEAF FRAGMENT
}
function handleSimulationError() {
stopResultPanelAnimation();
replaceResultPanelError();
}
function replaceResultPanelRunning() {
var url = // URL;
$("#resultDiv").load(url);
startResultPanelAnimation();
}
// ANIMATION
var animationInterval = null;
function startResultPanelAnimation() {
animationInterval = setInterval(animateResultPanel,4000);
}
function stopResultPanelAnimation() {
clearInterval(animationInterval); // stop the interval
}
function animateResultPanel() {
$("#simulatorProgressLabel").animate({opacity: '0.4'}, "slow");
$("#simulatorProgressLabel").animate({opacity: '1.0'}, "slow");
}
I know using session scope for rest services is a bad thing, but I didn`t know yet what is a good and easy solution. On the other hand currently different browser can simulate independently, but not always the progress bar works (especially when trigger first time mostly doesnt work). The IE11 only works when the Developer Tools are activated. When deactivating the tool while progress, the progress bar stops to grow.
What I would like to know is, how a good solution looks like when using template engine with Spring-MVC and Thymeleaf for triggering the process and displaying the status of progress via Javascript (as JQUery). Thank you in advance.
I have done a similar thing using Jquery AJAX POST submission. You can do something like this. This will submit POST request as a JSON format to the controller and wait for a response. A progress UI component can be shown during this waiting period.
//Start Progress display
function setStatistic(){
var data = JSON.stringify(//build your ChecksDto)
if (data) {
$.ajax({
url : '/view',
headers : {
'Content-Type' : 'application/json'
},
method : 'POST',
dataType : 'json',
data : data,
success : function(data) {
if (data.status == 200) {
// Stop Progress display
// Handle success status
}
},
error : function(xhr, status, error) {
// Stop Progress display
// Handle errors here
}
});
}
}
You also need to change Controller method to retrieve ajax requests as follows,
#ResponseBody
#PostMapping("/view")
public String run(#RequestBody ChecksDto checksWrapper, Model model) throws InterruptedException, ExecutionException
At least I found the solution in another Stackoverflow Page. The magic word is setting ajax cache to false.
$.ajaxSetup ({
// Disable caching of AJAX responses */
cache: false
});

socketio client: How to handle socketio server down

I've got a socketio server/client working well together, however I want to start writing events for when the server is offline on page load or during normal run.
I'm including the remote socket.io code in my header:
<script src="<?=NODE_HOST?>/socket.io/socket.io.js"></script>
<script>
var nodeHost = '<?=NODE_HOST?>';
</script>
And in my client controller I have
if(typeof io != 'undefined')
this.socket = io.connect(this.settings.server);
else
this.handleDisconnect();
The function I have to attempt to re-connect over and over if a) A socket disconnect occurs during normal operation, or b) the server is down on page load
botController.prototype.handleDisconnect = function() {
$.getScript(nodeHost+"/socket.io/socket.io.js").done(function(script, textStatus) {
bot.control.socket = io.connect(bot.control.settings.server);
}).fail(function(jqxhr, settings, exception) {
setTimeout(function() {
bot.control.handleDisconnect();
}, 5000);
});
}
Am I going about this the correct way?
The main issue I have right now (which made me create this question) is my code errors on page load when the server is down because I have functions like:
socket.on(...
When socket doesn't yet exist. I could wrap those in a function and call it when I detect the global socket object exists on successful reconnection? Would it matter if that function that contains socket.on... is called multiple times (if the server goes down more than once during operation)?
OK I managed to come up with this solution that seems to work well using yepnope which I already had using Modernizr (it handles the cross domain issue for me too).
<script src="<?=NODE_HOST?>/socket.io/socket.io.js"></script>
<script>
var nodeHost = '<?=NODE_HOST?>';
</script>
// Attempt to connect to nodejs server
botController.prototype.start = function() {
// Is our nodejs server up yet?
if(typeof io != 'undefined') {
this.socket = io.connect(this.settings.server);
this.startSocketEvents();
} else {
this.handleDisconnect();
}
}
// Our connection to the server has been lost, we need to keep
// trying to get it back until we have it!
botController.prototype.handleDisconnect = function(destroySocketObject) {
if(destroySocketObject === undefined)
destroySocketObject = true;
// Destroy any cached io object before requesting the script again
if(destroySocketObject)
io = undefined;
yepnope.injectJs(nodeHost+"/socket.io/socket.io.js",
function(result) {
// Did it actually download the script OK?
if(typeof io != 'undefined') {
bot.control.socket = io.connect(bot.control.settings.server);
bot.control.startSocketEvents();
} else {
setTimeout(function() {
bot.control.handleDisconnect(false);
}, 5000);
}
}
);
Where startSocketEvents() function contains all of my socket.on events

SignalR hub connection corrupts viewstate after few postbacks

I have written a chat app using signalR. It's a ASCX control containing the markup and the javascript that runs the chat. The page that holds the user control has a updatepanel that renders asynchronous and allows the user to refresh some content specific to a entered code. The problem is, I can click as many times the refresh button and the page behaves without any problem. When I click to connect the chat (which is all build in JavaScript) and I click a couple of times the refresh button it appears to behave fine but suddenly the page brakes and some viewstate errors are logged saying : The state information is invalid for this page and might be corrupted. Invalid view state.. blah blah... it's an ugly error.
This only happens when I connect to the hub. If I don't initiate the connection this never happens.
One thing to mention though, the code behind of the control stores some value in a property that refers to the viewstate (without storing it in the viewstate the page brakes on every postback) that later is written in the markup so the scripts that initiate the chat know who should be part of the conversations.
Please help.
Some code here:
StandAlonePanel.aspx -> contains the updatepanel with the refresh button.
ChatControl.ascx ->
public int userId{
get
{
if (ViewState["UserID"] == null)
ViewState["UserID"] = 0;
return Convert.ToInt32(ViewState["UserID"]);
}
set
{
ViewState["UserID"] = value;
}
}
//--- Same for userName
if (userId == 0 && CurrentUserSession.User != null)
{
this.userId = CurrentUserSession.User.Id;
this.userName = CurrentUserSession.User.Name;
}
in the markup
var userInfo = {
userId : "<%= userId %>",
userName : "<%= userName %>",
IsAnonymized: "<%= IsAnonymized %>",
enableLogging: "<%= enableLogging %>"
}
if (chat != null) {
chat.Disconnect();
}
chat = new Chat(userInfo);
chat.Connect();
//-- The script conn
var hubConn = $.hubConnection(url);
hubConn.logging = self.enableLogging
hubConn.qs = { 'u': userInfo.userId, 'tc': '0', 'oo': userInfo.showOnlineOnly, 'ach': self.IsAnonymized, 'lgch': self.enableLogging }; /* Initiating queryString */
hubConn.error(function (error) {
logMe(error);
});
var hubProxy = new ChatProxy(hubConn);
/* hook up callbacks to hubProxy */
self.Connect = function () {
if (self.longpolling == true) {
hubConn.start({ transport: 'longPolling' }).done(function (result) {
///--
}).fail(function (error) {
///--
alert("error" + error);
});
}
else {
hubConn.start().done(function (result) {
///--
}).fail(function (error) {
///--
alert("error" + error);
});
}
}
I guess I'm closing this question because it only happens in my asp dev env. when I deploy the app to iis it does not present the same problem

Intermittent failure of jQuery ajax using IE8

I am using jQuery ajax to load data into a jQuery tab. It works fine in Chrome and FireFox. In IE8 the data is sometimes not loaded. If I clear cache or reload the page it apparently works fine.
As far as I can tell it fails after shutting down IE and then starting it up again some time later. It has failed within hours, but succeeds if the delay is only minutes. At least that is what I think the failure mode is, I have not rigorously determined a magic time.
ETA: It works if I clear the cache or refresh the page.
I have put a superfluous time parameter in the post data, and set cache:false in the ajax call.
The data is not cached since if I change the expected data it will fill it in properly.
Another update:
A missing piece of data. This is a Facebook app. That turns out to be crucial.
I sniffed both the working and not working sessions with Wireshark. It turns out the difference is that the working session submits the Facebook cookies and the not working one doesn't.
So the question is now how to force the ajax call to include cookies. The descriptions I have found about the ajax call is that it includes cookies. Is the behaviour I am seeing a bug?
ETA:
The javascript:
$.ajaxSetup
(
{
// Disable caching of AJAX responses
cache: false
}
);
$(document).ready
(
function()
{
$('#shopTabs').tabs();
thing.create();
thing.editPicture();
$('#shopTabs').bind
(
'tabsselect',
function(event, ui)
{
thing.setReload(ui.index);
thing.setActive(ui.index);
}
);
}
);
// Must be global for Java to call
function reload()
{
thing.create();
thing.editPicture();
}
var thing =
{
reload : 0,
active : 0,
noOp : function()
{
},
create : function()
{
date = new Date();
$('#shopTabs1').load('create.php', {time : date.getTime()}, thing.linkform);
},
editPicture : function()
{
date = new Date();
$('#shopTabs2').load('editPicture.php', {time : date.getTime()}, thing.noOp);
},
linkform : function()
{
$('#upload').ajaxForm({target : '#shopTabs1'});
},
setReload : function
(
index
)
{
this.reload = this.reloadList[index];
},
setActive : function
(
index
)
{
this.active = this.activeList[index];
},
load : function
(
php,
args,
loadFn
)
{
var settings =
{
type : "POST",
cache : false,
url : php,
data : args,
context : this,
success : function (data)
{
$(this.active).html(data);
loadFn();
}
}
$.ajax(settings);
}
};
thing.activeList = ['#ui-tabs-1', '#shopTabs1', '#shopTabs2'];
thing.reloadList = [thing.noOp, thing.create, thing.editPicture];
In your thing.create function, add a changing query parameter, current date is good, or use a random number.
$('#shopTabs1').load('create.php?r='+escape(new Date().toString()), {time : date.getTime()}, thing.linkform);
or
$('#shopTabs1').load('create.php?r='+new Date().valueOf(), {time : date.getTime()}, thing.linkform);
same with your editPicture.
That will prevent IE from caching, as mentioned by Omu's answer
It turns out the problem was that IE officially expects a P3P header to load an iframe from a third third party site. Facebook implements apps using iframes from the app provider.
IE does not consistently fail if there is no P3P header.

Resources