MVC call Javascript from razor #Helper at unpredictable times - javascript

In my MVC view I need to get razor c# code to execute a javascript function at unpredictable times, way after the page has loaded.
I have used a thread to simulate unpredictableness but ultimately instead of the thread it will be a WCF callback method that raises an event which runs the helper, but to eliminate session issues I have used the thread.
Javascript to execute:
<script type="text/javascript">
function DisplayNews(news) {
alert(news);
}
</script>
Helper that runs the javascript (because sticking this directly in the below thread didn't work)
#helper UpdateNews(string news)
{
<script>
DisplayNews(news);
</script>
}
Thread that simulates unpredictableness/post page loading or non user invoked events
#{
System.Threading.Thread T = new System.Threading.Thread(new System.Threading.ThreadStart(delegate
{
while (true)
{
System.Threading.Thread.Sleep(5000);
UpdateNews("Some cool news");
}
}));
T.Start();
}
If I stick a break point at UpdateNews("Some cool news"); I can see that it gets hit every 5 seconds as it should, but thats as far as it gets, nothing else happens. I can't stick a break point in the helper or the Javascript so I can't see where it stops working after that.
Is this going to work at all or is there another way I should be approaching this?
Any help would be greatly appreciated.

In server side code you can call an client function...
Razor executed in server side and javascript is in client side.that mean when you get server response it's created by razor code in server side and now you can just use javascript in client side

I may be misunderstanding what you are trying to do but you can have javascript that will run on page load that will be wrapped in a set timeout with a random millisecond period.
Something like this:
<script>
window.onload = function() {
setTimeout(function() {}, 1000); // this will run 1 second after page load
}
</script>
simply randomize the number being passed as the second parameter to setTimeout and your javascript will run at a random time after the page loads.

Related

Javascript call java method doesn't work immediately after the page was loaded in webview?

Here is my problem, I want to call Java method like window.jsBridge which is defined in java via:
CustomChromeClient client = new CustomChromeClient(
"jsBridge", WebCallJsFunction.class);
mWebView.setWebChromeClient(client);
mWebView.loadUrl("file:///android_asset/test.html");
and in my html:
<body>
</script>
document.write(window.jsBridge.getSomething())
</script>
</body>
The page will show nothing, because window.jsBridge is undefined, but if I chage it to this:
setTimeout(() => {
document.write(window.jsBridge.getSomething())
}, 500)
the page will write the correct thing. I guess the reason is that the java method: mWebView.setWebChromeClient(client) is executing with the js in text.html at the same time, and when the js run: document.write(window.jsBridge.getSomething()) then java code has not executed completed, am I right? So how to solve this problem?

Updating content in a Google Apps Script sidebar without reloading the sidebar

I am using the following Google Apps Script code to display content in a custom sidebar of my spreadsheet while the script runs:
function test() {
var sidebarContent = '1<br>';
updateSidebar(sidebarContent);
sidebarContent += '2<br>';
updateSidebar(sidebarContent);
sidebarContent += '3';
updateSidebar(sidebarContent);
}
function updateSidebar(content) {
var html = HtmlService.createHtmlOutput(content)
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setTitle('Sidebar')
.setWidth(250);
SpreadsheetApp.getUi().showSidebar(html);
}
It works, but each time the updateSidebar() function runs, the sidebar blinks when loading in the new content.
How can I program this to update the content of the sidebar more efficiently, thus removing the blink?
I'm assuming that SpreadsheetApp.getUi().showSidebar(html); should really only be run once, at the beginning, and the subsequent updates to the content should be handled by Javascript in a .js file.
But I don't know how to get the sidebarContent variable from Javascript code running client-side in the user's browser.
Also, I know this must be possible, because I just saw this post on the Google Apps Developer Blog today about an app that uses a custom sidebar, and the .gif towards the end of the article shows a nicely-animated sidebar that's being updated in real-time.
I believe the solution for this situation is to actually handle the flow of the server-side script from the client-side. That is the only way I can think of right now to pass data to the client side from the server without re-generating the HTML.
What I mean by this is that you would want to make the calls to the server-side functions from the client, and have them return a response as a success handler to the client. This means that each action that needs to be logged will need to be made into its own function.
Ill show you a quick example of what I mean.
Lets say your server-side GAS code looked like this:
function actionOne(){
...insert code here...
return true;
}
function actionTwo(){
...insert code here...
return true;
}
And so on for as many actions need to be executed.
Now, for your .html file, at the bottom you would have javascript looking something like this:
<script>
callActionOne();
function callActionOne(){
google.script.run.withSuccessHandler(callActionTwo).actionOne();
}
function callActionTwo(){
...update html as necessary to indicate that the first action has completed...
google.script.run.withSuccessHandler(actionsComplete).actionTwo();
}
function actionsComplete(){
..update html to indicate script is complete...
}
</script>
It is a bit more complex than is ideal, and you might need to use the CacheService to store some data in between actions, but it should help you with your problem.
Let me know if you have any questions or if this doesn't fit your needs.

Run Javascript in iFrame context

I am attempting to run a script in a webpage, that should be executed in an <iframe>. Right now I can call a function that is set within the <iframe>.. I'm just having issues running a script to the <iframe>'s context.
Here's how I run a function set in the <iframe>
$('#iframe').get(0).contentWindow.performSearch();
Now instead of calling the preformSearch function, I wish to run a script - for this example, this is the script...
console.log('worked!');
My actual script is a big one, so I won't put it here - for the sake of this question.
So, is there any way to run that script through the <iframe>'s context? For example, my first guess would be/was..
$('#iframe').get(0).contentWindow.function(){
console.log('worked!');
}
I've never messed with running functions through something like an <iframe> before though, so I'm stumped.
Thanks for any help in advance!
NOTE I am using NW.js (Node-Webkit) to remove all <iframe> restrictions.
NOTE v2 The preformSearch() function was just a reforence on how I call functions in the frame.
You could try and use the messaging mechanizm
which means that on the parent frame you could send the message with
var win =$("#iframe").contentWindow;
win.postMessage({ messageType: "predefinedMessage", features: data }, '*');
and than in the iframe you could get the message
function FrameCommunicator(attachManager) {
var mfilesFrame;
function _actOnMessage(data) {
if (data.messageType === "predefinedMessage") {
//perform here what you need
}
}
window.addEventListener("message", function (e) {
var data = e.data;
mfilesFrame = e.source;
_actOnMessage(data);
}, false);
}
now the thing is that the iframe and the parent fram can have the same code if they reference to the remotely.
Another way would be just to send the content of the message as JS and run it with eval , but that is risky , bad practice and lotsa other things :)

How PhoneGap keep Javascript executing after changing window.location/document.location

According to this question, when we set the window.location, javascript will "stop" executing or turn into a race condition.
Sometimes we need to fire window.location = SOMESCH://xxx multiple times inside a WebView to send "Notifications" back to our app. For example setting window.location = myapp://loginButtonEnabled?e=1 to tell the app that the user had filled in some nessasary info and can start login. It seems to be impossible to do something like this:
function(){
window.location = myapp://loginButtonEnable?e=1;
window.location = myapp://hideHintView;
.....
window.location = myapp://theLastThing;
}
Only the last window.location = myapp://theLastThing will be fired and then the execution of Javascript will stop(though we stopped the redirecting in our app by returning NO in webView:shouldStartLoadWithRequest:navigationType:).
I found it interesting that PhoneGap made this possible by using a dispatching queue, but I still haven't figure out why it works, anybody knows the trick??
BTW, is there a simple way to "resume" the execution after setting location? It will be much better than using an operation queue.
You need to give the event loop a chance to respond to the location change each time. The typical way of doing this is using a setTimeout with a small/zero delay, which has the effect of moving execution to the next event loop tick. Try something like this:
var q=[];
function dequeue() {
window.location='myapp://'+q.shift();
if (q.length>0) setTimeout(dequeue,0);
}
function notifyApp(cmd) {
q.push(cmd);
if (q.length==1) setTimeout(dequeue,0);
}
notifyApp('loginButtonEnable?e=1');
notifyApp('hideHintView');
notifyApp('theLastThing');
As for javascript execution stopping, setting window.location shouldn't have this effect unless it actually results in a page change - perhaps try using the technique above and see if your javascript continues after the last notifyApp() call.
EDIT: Another approach to this issue is to create temporary iframes instead of changing the location of the current page - see for example
Triggering shouldStartLoadWithRequest with multiple window.location.href calls

Any way to gracefully enforce a timeout limit when loading a slow external file via javascript?

I'm using javascript to include some content served up from a php file on another server. However, this other service can sometimes get flaky and either take a long time to load or will not load at all.
Is there a way in JS to try to get the external data for x number of seconds before failing and displaying a "please try again" message?
<script type="text/javascript" src="htp://otherserver.com/myscript.php"></script>
Couple issues: you can use timeout thresholds with XMLHttpRequest (aka ajax), but then since it's on an otherserver.com you cannot use XMLHttpRequest (and support all A-grade browsers) due to the Same Origin Policy restriction.
If the script introduces any kind of global name (eg any variable name, function name, etc) You can try setTimeout to keep checking for it:
var TIMELIMIT = 5; // seconds until timeout
var start = new Date;
setTimeout(function() {
// check for something introduced by your external script.
// A variable, namespace or function name here is adequate:
var scriptIncluded = 'otherServerVariable' in window;
if(!scriptIncluded) {
if ((new Date - start) / 1000 >= TIMELIMIT) {
// timed out
alert("Please try again")
}
else {
// keep waiting...
setTimeout(arguments.callee, 100)
}
}
}, 100)
The problem as I see it is you cannot cancel the request for the script. Please someone correct me if I'm wrong but removing the <script> from the DOM will still leave the browser's request for the resource active. So although you can detect that the script is taking longer than x seconds to load, you can't cancel the request.
I think you may be out of luck.
The only way I can think of doing this is to create a proxy on another (PHP-enabled) server which will fetch the data for you, but will stop when a certain timeout limit has been reached (and it can just return an empty result).
This is purely, purely theoretical:
<script> tags can be dynamically inserted into the DOM, at which point the script will be fetched and processed. This dynamic script tag injection is how some achieve cross-domain "AJAX."
I would imagine you could declare a global variable var hasLoaded = false;. At the end of the script you are attempting to load you could set that variable to true hadLoaded=true;. After injecting the script tag into the DOM you could then kickoff a setTimeout() whose callback function checks to see if "hasLoaded" is set to true. If it isn't, you can assume the script has not yet loaded fully into the browser. If it has, you can assume it has loaded completely.
Again, this is theoretical, but if you test it be sure to report back, I'm very curious.
I think that the only way to do this is take the content of the file via ajax and then set a timer. If the request finishes before the timer you can evaluate the respons with eval(that's not the better solution anyway), otherwise you can stop the ajax request and write the error message.

Categories

Resources