I have a html page with 2 buttons on it and a big javascript function that is executed every 10 ms. Each click on each button executes a javascript function that changes some variables used by the big javascript function and change its behaviour. In time the code got very complex and time consuming and I would like to move the entire calculation of variables over to the server side. Or, better yet I would like to generate the entire function on the server.
How can I dynamically change the big javascript function when any of the 2 buttons is being pressed?
What you could do is once the button is pressed you make an Ajax request to the server side. There you generate the javascript code based on the button pressed and send it back. You can then eval the response and execute the appropriate function.
Grabbing a large script and executing it every 10 ms is bound to be slow.
Modifying a large script isn't that bad and then you only care about the execution plan of the script. (It doesn't matter how fast the server can generate the script the client will execute if you're sending it every 10 ms and it's super complicated. Client execution is going to cause the client to creep if not properly made.)
However have you considered just "fixing" your script so that it's a bit more compartmentalized. Surely the entirety of the function does not change every 10 ms? (On your site does it change from being a game of Pong to a looping weather radar graphic every 10 ms?)
compartimentalized javascript example (using jquery): Assumes you have two tags one with the class buttonA and one with the class buttonB. Clicking buttonA or buttonB changes internal values and then the script is executed.
var complicatedFunction = function(){
//private variables and methods
var a = 2, b = 3;
//public variables and methods
return {
exec: function(el){
//which button was pushed?
if($(el).is('.buttonA')){
a = 4;
b = 8;
} else {
a = 10;
b = 2;
}
alert('The result of a*b is ' +(a*b));
}
}
}();
$('.buttonA, .buttonB').click(function(){complicatedFunction.exec(this)});
Wish I could help more, if you post a code example maybe we can!
Related
I have report view where a bunch of controls located, there is an example code:
#Html.DevExpress().DropDownEdit(
settings =>{
settings.Name = "SomeList";
settings.Width = 100;
settings.SetDropDownWindowTemplateContent(c =>{
#Html.DevExpress().ListBox(
...
).BindList(ViewData["SomeList"]).Render();
some code...
).GetHtml()
When it render first time it works fine, but in business logic there is another drop down let's call it dropdown #2. When user select some values in dropdown#2 JS handle this action send request to the server to get actual value for first dropdown, then clear all rendered values from dropdown #1 and insert new items.
And problem in performance lies in how devexpress create new items on client side. From backend there is now 8000 new items can be added to dropdown #1 and it keep growing. And user must wait 5-10 seconds when browser render it. I tried to research what is happening when new item is creating but there are a lot of devexpress function which call another functions.
JS code look's like:
SomeList.BeginUpdate();
l = data.SomeList.length;
while (x < l) {
SomeList.AddItem(data.SomeList[x].Name, data.SomeList[x].Id);
x++;
}
SomeList.EndUpdate();
BeginUpdate and EndUpdate is devexpress functions that prohibbit browser render control while adding new items. Without this function it takes eternity to finish adding new items.
I know start point of problem it is - item creating code SomeList.AddItem(...).
So my question: is there way to do something like console.trace(SomeList.AddItem(...)) and see full trace which will be executed on first code pass?
Also is there way to determine which function call take alot of time to execute?
In a Google Spreadsheet, I have a long script that permorms many actions in steps, like:
function MyLongScript()
{
var Results1 = Action1();
//send feedback 1
var Results2 = Action2(Results1);
//send feedback 2
var Results3 = Action3(Results2);
//send feedback 3
//end code
}
And I want to show the users a dialog box that tells them that script is running and updates each step of the scritp, like "Action1 complete", ..., "Action2 complete" and so on.
So, I have the HTML interface which contains some table rows with these steps. The question is: how do I make the dialog see that the code performed a certain step?
Right now I'm trying to start the code from the dialog after it loads:
$(function() {
google.script.run
.withSuccessHandler(MainCodeSuccess)
.withFailureHandler(MainCodeFailure)
.MyLongScript();
}
And the dialog is called with the UI and HtmlService:
function CallDialog()
{
var ui = HtmlService.createTemplateFromFile('FeedbackWindow')
.evaluate()
.setWidth(300)
.setHeight(500);
SpreadsheetApp.getUi().showModalDialog(ui, "Dialog Title");
}
What I need is either a getStatus() in the dialog scritp or a sendStatus() in the server script.
What is the best way of achieving this?
You can run multiple google.script.run calls to the server simultaneously. You can't have one server call send multiple success calls back. You could have your MyLongScript() run, save progress status somewhere, and just keep that running, then have a second google.script.run executing on a loop every certain time period. You can use a JavaScript setInterval(): window.setInterval("javascript function", milliseconds); I don't think that there is a jQuery equivalent.
So it might (roughly) look like this:
$(function() {
google.script.run
.withSuccessHandler(MainCodeSuccess)
.withFailureHandler(MainCodeFailure)
.MyLongScript();
window.setInterval("statusChecker()", milliseconds);
}
window.statusChecker = function() {
google.script.run
.withSuccessHandler(statusCheckSuccess)
.withFailureHandler(onFailure)
.StatuChecker();
};
window.statusCheckSuccess = function(returnStatus) {
if (returnStatus !== false) {
//To Do - show msg to user
document.getElementById('idMsgToUser').textContent = returnStatus;
};
};
Your MyLongScript() might need to be saving the state of the current status to a file. I'm not sure if the subsequent, and simultaneous google.script.run calls wipes out the data in a global variable. If a global variable would hold the data even with all the simultaneous server scripts running, you could save the current status to a global variable. You'd need to experiment with that, or maybe someone knows the answer to that question.
I ended up using the following script in order to auto-submit forms to my server after 60 seconds. However, for some reason the forms are reporting an error.
</style>
<script>
var counter{{num}} = {{seconds}};
var interval = setInterval(function() {
counter{{num}}--;
// Display 'counter' wherever you want to display it.
document.getElementById("counter{{num}}").innerHTML = "Timer:"+counter{{num}}
if (counter{{num}} == 0) {
// Submit form
test.submit('timeout');
}
}, 1000);
</script>
<p id="counter{{num}}" style="text-align: right;">COUNTER</p>
The script looks a little funny because there is this `{{num}}' value. This is basically replaced by a different number using server side scripting each time the form is called so that multiple functions are not generated simultaneously which force the timer to zero twice or three times faster than before.
Sorry if this is unclear. I tried every solution to auto-submit this form but I think there were server side conflicts with my javascript. This is all pretty new to me.
Thanks for any help you can provide!
I will put this post into paragraphs to make it easier reffering to specific content.
I have made a simple button in html that plusses a number with 1 everytime the button is pressed. This function is made in Javascript. This number has to be put into the database every 20 seconds.
Since Javascript is running on the client side, every visiter will be able to change the current number of times the button is pressed, and that "fake" number will then be sent to the database after 20 seconds.
The user should not be able to change this number, because it's considered cheating.
I could use other languages to complete this like java, flash etc. but I need to make it working with Javascript/Jquery that runs on the client side. The reason for this is that it will take too hard on the server if there is sent a request to the server everytime to button is pressed.
I hope you understand all 4 steps, if not please let me know which step I shall deepen.
Question: How can I make a secure way of processing a number from the client-side to the database without the user being able to change that number on their computer? If I can't, any other suggestions?
Thanks in advance.
First of all, your counter should be on your server. Don't let the client side tell you how many times the button has been pressed - store this yourself on the server (where no one can reach).
This will mean that you'll have to notify the server every time the user clicks the button. Furthermore, you'll need to make sure that each "click" is valid. You could do this by attaching a unique key to each of the buttons clicks. As soon as the user clicks the button, this key will be sent to the sever and validated. If it is valid, the server will return a new key to be sent when the button is next clicked.
You should be aware that it is very VERY easy to write a short jQuery script to manipulate clicks on DOM elements though. A command as simple as
setInterval(function(){
$('button').trigger('click');
},500);
Would trigger a click event on the button every 500 milliseconds (0.5 seconds).
Code that runs in JavaScript can't practically be protected against "cheating". Your best bet might be data hiding:
var myobj = (function() {
var i = 0;
return {
function setI(newvalue) {
// do checks here
if (true) {
i = newvalue;
}
},
function sendI() {
// send value of i
}
}
}());
myobj.setI(123);
myobj.sendI();
myobj.i // undefined
Moving the logic that prevents data tampering to the server is better though.
I need to do a simple pdf with some 3D objects for an oral presentation. I made several views, each one with a camera viewpoint, an object and a display mode.
To avoid the need to manually switch between the different viewpoints with the context menu, I would like the viewpoints to switch automatically with a Timer (each viewpoint staying for a few seconds). And I would like to not have to touch the mouse at all (nor the keyboard), so I would like to have the playback started as soon as the page appears.
I found the javascript command runtime.setView(N,x) to switch to the x'th view among N, but I don't know where to put it (I don't want to define a function which will be called when I press a button, since I want everything to be automated). Also, I don't know how to pause for a few seconds.
Any help ? Thanks !
I believe you're looking for setInterval(fn, time) which will call a function periodically at a time interval that you set. I'm not familiar with the setView() method you mentioned, but here's some pseudo code that you would put in tags at the end of the document body.
function startSwitcher()
var viewNum = 0;
var maxViews = 5; // you set this to how many views there are
setInterval(function() {
++viewNum;
if (viewNum >= maxViews) {
viewNum = 0;
}
runtime.setView(N, viewNum); // you will have to figure out this line
}, 2000);
}
startSwitcher();
The 2000 is 2000 milliseconds and is the time interval between executing the function. You can put any number of milliseconds there.
The runtime.setView(N, viewNum) line is something you will have to figure out as I am not familiar with whatever library you're trying to use there. The operative part of this code is the viewNum variable which configures which view in rotation should be next.
I think the runtime.SetView(..) Methods works with the name of the view as a string instead of the viewnumber. I have this function in a Dokument-level script and it works for me:
// view is the name of the view for example "TopView"
function setView(view){
console.println("Navigating to view: "+view);
var pageIndex = this.pageNum;
var annotIndex = 0;
var c3d = this.getAnnots3D( pageIndex )[ annotIndex ].context3D;
c3d.runtime.setView(view, true);
}
Combine this with the setInterval(..) from jfriend00´s answer und you should get what you need.
Best regards