Вопрос

I have a function in my Backbone view(file.js) which is populated with a JSON response that's in the below format:-

Function in Backbone View:-

chart_data: function(){
    var all_stats = this.collection.toJSON();
    $("#page-container").html(this.users_by_loc({
        platform_stats: all_stats,
        graph_data: all_stats.items.slice(0,5) 
        // I want to use the top 5 entries to plot graph
    }));
}

Response present as part of all_stats(from my api call - I'm using Rails on server side):-

{
   "items":
   [
       {
           "loc": "Chennai",
           "users": 11707
       },
       {
           "loc": "Hyderabad",
           "users": 4327
       },
       {
           "loc": "Pune",
           "users": 3625
       },....(many more entries)

   ]
}

Now, I'm trying to pass the json response present in the graph_data parameter(defined in my Backbone view above) to a variable called chartData which is defined in my jst.ejs template(code below) . This variable(chartData) is used by my AM charts JS code to actually plot the graph.

My jst.ejs file which has the code to populate the graph data and plot the graph looks like this:-

<script>
    var chart;  

    chartData = "<%= graph_data %>"    
    console.log("chartData: ", chartData);

            AmCharts.ready(function () {
                // SERIAL CHART
                chart = new AmCharts.AmSerialChart();
                chart.dataProvider = chartData;

                //additional code to help plot the chart  

                chart.write("chartdiv");
            });

</script>

<div id="chartdiv" style="width: 60%; height: 400px;"></div>

My current roadblock is that when I do..

chartData = "<%= graph_data %>"    
console.log("chartData: ", chartData);

.. in my jst.ejs template the chartData variable instead of having the actual data as part of all_stats (shown_above) returns the following in my firebug console:-

chartData: [object Object],[object Object],[object Object],[object Object],[object Object]

How do I correctly assign the actual data present in graph_data variable(as part of my backbone view) to the variable chartData present in my jst.ejs template to plot the graph ?

Это было полезно?

Решение

Mixing "real" JavaScript code in with your templates (i.e. tossing a <script> into a template, not simple bits of JavaScript for putting the template together) generally doesn't work out that well. You'll usually have an easier time if you separate the concerns: HTMLish things go in the template, functionality is hooked up in the view.

I'm not that familiar with amChart but many charting (and mapping) libraries will need to know a few important things about their target element before they can do any work. In particular, they'll usually want to know where it is on the page and how big it is and those won't be know until the <div> has been rendered to the page. In a Backbone app, that generally won't be true until someone has rendered a view and appended its el to the page:

var v = new View;
// We don't know the position or size of anything yet.
v.render();
// We still don't know.
$('body').append(v.el);
// Now the size and position are available but we might have to
// pass control back to the browser first.

You're facing the added difficulty of amChart apparently wanting the id of something in the DOM that it should draw into:

chart.write("chartdiv");

But document.getElementById('chartdiv') won't return anything useful until after render has been called and after someone has done a x.append(v.el) (or equivalent).

If you're expecting someone to immediately your view's el to the page right after calling render then you can queue up some code to run after the browser gets control back (and hence has time to figure out the size and position of things and make document.getElementById('chartdiv') do something useful) by using setTimeout with a timeout of zero:

render: function() {
    var _this = this;
    var chartData = ....

    // Do normal rendering and template stuff.

    setTimeout(function() {
        var chart = new AmCharts.AmSerialChart();
        chart.dataProvider = chartData;
        //...
        chart.write("chartdiv");
    }, 0);
    return this;
}

You can also use _.defer (which is little more than setTimeout(..., 1)) if you want to be a little more explicit about it.

There might be some amChart-specific stuff to deal with but hopefully this will take care of the hard parts.

BTW, that AmCharts.ready call you mentioned in the comments probably doesn't work that well with single-page apps because it is probably equivalent to $(document).ready() and that only fires when a page is loaded (i.e. only once for the duration of a single-page app). There might be other events you can use instead but you should be able to use the existing Backbone view structure instead of relying on document-ready events.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top