JoeFromAccounting
JoeFromAccounting

Reputation: 145

Dynamic variable names javascript MVC

I'm running a bit of javascript code in a loop, creating a chart (using google visualization). After all this code is run, I need to access these objects somewhere else. My problem is that I can't just call "chart" again, since it now has been over-written.

I've managed to figure out a really hacky solution which involves using the MVC @ thing to dynamically generate something at run-time, which I then force as a variable name. It works, but I don't think it's the right way to approach this problem. Is there a way for me to dynamically change the name of the variable each time it's run?

The following code is run multiple times.

@{
var myChart = "cData" + Model.ChartId.ToString();
}
...
function () {
    @myChart = new google visualization.ChartWrapper({ ... }); 
    dashboard.bind(slider, @myChart);
    dashboard.draw(data); 
}

myChart changes every single time the code is run, giving me a really hacky string. By putting it without the ' marks, it becomes a variable at runtime. After all that is run, I have a resize function which run the following:

@myChart .setOption('width', width);
@myChart .setOption('height', height);
@myChart .draw();

This is also super hacky. I took advantage of how javascript ignores spaces, so that I can treat @myChart like an object.

The result is riddled with syntax errors, but it still runs, and it runs with intended results. So my question is if there is a "proper" solution for this, instead of making separate javascript functions for each individual chart I need to make.

Thanks.

Upvotes: 3

Views: 1319

Answers (1)

Tim M.
Tim M.

Reputation: 54359

There's nothing wrong with what you've done, but it could be better.

First, you don't have to rely on a space to mix JavaScript and Razor.

@(myChart).setOption('width', width);

But that's still ugly.

Approach 1

<script>

    // global (usual caveats about globals apply)
    var charts = {};

</script>

@for( int i = 0; i < 10; i++ )
{
    string chartId = "chart-" + i;

    <script>

        charts['@chartId'] = new Chart();
        charts['@chartId'].setOption('width', width);
        charts['@chartId'].setOption('height', height);
        charts['@chartId'].draw();

    </script>
}

Approach 2

<script>

    function doResize(chart) {
        chart.setOption('width', width);
        chart.setOption('height', height);
        chart.draw();
    }

</script>

@for( int i = 0; i < 10; i++ )
{
    <script>

        (function () {

            // limit the scope of the "chart" variable
            var chart = new Chart();

            // perform other init

            // listen for resize in some manner

            $(window).on("resize", function() {
                doResize(chart);
            });

        })();

    </script>
}

Approach #2 is my preferred method as it manages scope and is clear to read.

Upvotes: 3

Related Questions