Search code examples
javascriptc#asp.netclientscriptmanager

JS function vs C#


I am quite new to JS and doing web apps and I am facing this problem: I have JS code which creates me 6 gauges and function which updates gauge 1 value:

<!-- Include the Gauge.js library -->
<!-- Raphael must be included before justgage -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.4/raphael-min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/justgage/1.2.9/justgage.min.js"></script>
        <!-- Initialize the gauge on page load -->
    <script>
        var gauge1;
        var gauge2;
        var gauge3;
        var gauge4;
        var gauge5;
        var gauge6;

        function updateGaugeValue(newValue, event) {
            event.preventDefault();
            gauge1.refresh(newValue);
        }

        window.onload = function () {

            gauge1 = new JustGage({
                id: "gauge1",
                value: 0,
                min: 0,
                max: 10,
                title: "My Gauge",
                label: "Value"
            });

            gauge2 = new JustGage({
                id: "gauge2",
                value: 0,
                min: 0,
                max: 10,
                title: "My Gauge",
                label: "Value"
            });

            gauge3 = new JustGage({
                id: "gauge3",
                value: 0,
                min: 0,
                max: 10,
                title: "My Gauge",
                label: "Value"
            });

            gauge4 = new JustGage({
                id: "gauge4",
                value: 0,
                min: 0,
                max: 10,
                title: "My Gauge",
                label: "Value"
            });

            gauge5 = new JustGage({
                id: "gauge5",
                value: 0,
                min: 0,
                max: 10,
                title: "My Gauge",
                label: "Value"
            });

            gauge6 = new JustGage({
                id: "gauge6",
                value: 0,
                min: 0,
                max: 10,
                title: "My Gauge",
                label: "Value"
            });

        };

</script>

When I call update from button like this

<button onclick="updateGaugeValue(5, event)">Click me</button>

function normally works and change value of gauge 1 to 5. But when I try to call this function from C# (using ASP.NET) via ClientScript like:

Page.ClientScript.RegisterStartupScript(this.GetType(), "CallMyFunction", "updateGaugeValue(5, event)", true);

nothing happens. But if I try to test it and alert hello world like

Page.ClientScript.RegisterStartupScript(this.GetType(), "CallMyFunction", "alert('Hello World')", true);

it normally works and alert. Any suggestions? I expect that I am able to call this JS function from C# code.


Solution

  • The issue is much that we use a page onload/onready to setup, create and render the gauge.

    But, we want a plain asp.net button, say maybe a text box, and then some code behind to set the value.

    The issue is the on window load. If we "inject" a call to that routine, we can't (very well) control when our registry start up script runs as opposed to the existing code to setup + create the gauges.

    What we need to do is "force" our startup script to wait. One great way is to use setTimeout, and that will in effect "push" our code to a routine on the JavaScript engine "execution stack" to wait, render page, run that gauge setup code, AND THEN run our desired code.

    Worse yet? Testing this a bit, the event.prevent seems to mess this up.

    Here is a working proof of concept:

    We put the script library code at top, for example:

    <title></title>
    <script src="../Scripts/jquery-1.12.4.js"></script>
    <link href="../Content/bootstrap.css" rel="stylesheet" />
    <script src="../Scripts/bootstrap.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.4/raphael-min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/justgage/1.2.9/justgage.min.js"></script>
    

    but, for OUR code, we want that stuff to be placed at bottom - after the DOM been created, setup and rendered.

    So, now this code:

        <div style="padding:35px">
    
            <div style="border: solid 1px; float: left; padding: 8px">
                <legend>Client side buttons</legend>
                <button style="float: left" onclick="updateGaugeValue(4, event)">Click me</button>
                <button style="float: left; margin-left: 25px" onclick="updateGaugeValue2(6, event)">Click me</button>
    
            </div>
    
            <div style="float: left; margin-left: 30px; padding: 8px; border: solid 1px">
                    <legend>Server side buttons</legend>
    
                <div style="float:left">
                    Enter value 1-10 for gauage1:
                    <br />
                    <asp:TextBox ID="TextBox1" runat="server" Width="50px">
                    </asp:TextBox>
                    <asp:Button ID="cmdGauge1" runat="server"
                        Text="set guage 1"
                        CssClass="btn"
                        OnClick="cmdGauge1_Click" />
                </div>
    
                <div style="float: left; margin-left: 30px">
                    Enter value 1-10 for gauage2:
                    <br />
                    <asp:TextBox ID="TextBox2" runat="server" Width="50px">
                    </asp:TextBox>
                    <asp:Button ID="cmdGauge2" runat="server"
                        Text="set guage 2"
                        CssClass="btn"
                        OnClick="cmdGauge2_Click" />
                </div>
            </div>
    
            <div style="clear: both; height: 50px">
            </div>
    
            <div id="gauge1" style="float:left;width:250px;"></div>
    
            <div id="gauge2" style="width:200px;float:left; margin-left:40px; width: 250px"></div>
    
        </div>
    
    
    <script>
        var gauge1;
        var gauge2;
    
    
        window.onload = function () {
    
            gauge1 = new JustGage({
                id: "gauge1",
                value: 0,
                min: 0,
                max: 10,
                title: "Files Uploaded",
                label: "Zip Files Uploaded",
                showInnerShadow: true,
                shadowOpacity: 2,
                shadowSize: 5,
                textRenderer: function () {
                    return "144 / 400"
                }
            });
    
            gauge2 = new JustGage({
                id: "gauge2",
                value: 0,
                min: 0,
                max: 10,
                title: "My Gauge",
                label: "Pdf Files uploaded",
                showInnerShadow: true,
                shadowOpacity: 2,
                shadowSize: 5,
    
            });
        };
    
        function updateGaugeValue(newValue, event) {
            // event.preventDefault();
            // alert('START')
            gauge1.refresh(newValue);
        }
        function updateGaugeValue2(newValue, event) {
            // event.preventDefault();
            gauge2.refresh(newValue);
        }
    
    
    </script>
    

    So, we wrapped our startup script in a timeout function. Even with a delay of "1", it works, since timeout pushed our code to the Java engine program stack, and thus it runs after everything else on that page.

    code behind:

        protected void cmdGauge1_Click(object sender, EventArgs e)
        {
            string jscode =
                $@"updateGaugeValue({TextBox1.Text},event)";
    
            jscode = "setTimeout(function () {" + jscode + "},1)"; 
            ClientScript.RegisterStartupScript(Page.GetType(), "myfunc", jscode, true);
        }
    
        protected void cmdGauge2_Click(object sender, EventArgs e)
        {
    
        }
    

    and result:

    enter image description here

    However, there really not much need to "call" that existing JS routine you have, since the JS object exists (or we assume it will).

    So, then this code :

        protected void cmdGauge1_Click(object sender, EventArgs e)
        {
            string jscode =
                $@"gauge1.refresh({TextBox1.Text})";
    
            jscode = "setTimeout(function () {" + jscode + "},1)"; 
            ClientScript.RegisterStartupScript(Page.GetType(), "myfunc", jscode, true);
        }
    

    So, now we don't even call that JS routine, but use the refresh method of the graph object.

    So, now, we can put back (un-comment) out the event.preventDefault(), and thus both client side, and server side buttons in above example will now both work.

    I should also point out that I used a delay of 1 (1 millisecond). This delay (amount) is not really required, but the FORCE of the routine to be pushed onto the Java engine execution stack is the important part here.