Strange javascript array push behaviour - javascript
I wrote a simple code to manipulate a query result to a bidimensional array (matrix) for a google chart datatable.
I'm getting nut on this strange array.push behaviour: when I push a new row in the matrix this method add the row, but also change the value of all the previus rows!
this is the code:
<script src="https://www.gstatic.com/charts/loader.js" type="text/javascript"></script>
<script type="text/javascript">
query is the matrix from the query
var qry = [[{label:'Montly', type: 'string'}, {label:'Model', type: 'string'}, {label:'total', type: 'number'}], ['12-2017','California T',parseFloat(13+13)], ['12-2017','458 Speciale',parseFloat(3+2)], ['12-2017','GTC4Lusso',parseFloat(2+6)], ['12-2017','458 Spider',parseFloat(0+1)], ['12-2017','GTC4Lusso T',parseFloat(2+0)], ['12-2017','California',parseFloat(0+2)], ['12-2017','488 Spider',parseFloat(16+7)], ['12-2017','FF',parseFloat(1+3)], ['12-2017','488 GTB',parseFloat(17+10)], ['12-2017','F12berlinetta',parseFloat(3+4)], ['12-2017','458 Italia',parseFloat(0+3)], ['12-2017','F12tdf',parseFloat(1+21)], ['12-2017','LaFerrari Aperta',parseFloat(0+1)], ['12-2017','812 Superfast',parseFloat(2+3)], ['12-2017','Portofino',parseFloat(1+1)], ['11-2017','458 Spider',parseFloat(2+4)], ['11-2017','GTC4Lusso',parseFloat(4+34)], ['11-2017','California T',parseFloat(8+15)], ['11-2017','488 GTB',parseFloat(9+12)], ['11-2017','LaFerrari',parseFloat(0+1)], ['11-2017','458 Speciale',parseFloat(2+2)], ['11-2017','GTC4Lusso T',parseFloat(0+1)], ['11-2017','FF',parseFloat(1+4)], ['11-2017','812 Superfast',parseFloat(3+1)], ['11-2017','California',parseFloat(0+3)], ['11-2017','488 Spider',parseFloat(11+8)], ['11-2017','458 Italia',parseFloat(1+5)], ['11-2017','F12tdf',parseFloat(0+1)], ['11-2017','Portofino',parseFloat(0+1)], ['11-2017','F12berlinetta',parseFloat(3+4)], ['10-2017','458 Italia',parseFloat(0+4)], ['10-2017','California T',parseFloat(9+18)], ['10-2017','California',parseFloat(0+8)], ['10-2017','812 Superfast',parseFloat(1+2)], ['10-2017','F12tdf',parseFloat(1+2)], ['10-2017','Portofino',parseFloat(2+0)], ['10-2017','488 GTB',parseFloat(8+14)], ['10-2017','FF',parseFloat(0+3)], ['10-2017','458 Spider',parseFloat(1+3)], ['10-2017','LaFerrari Aperta',parseFloat(0+1)], ['10-2017','F12berlinetta',parseFloat(5+8)], ['10-2017','458 Speciale',parseFloat(3+2)], ['10-2017','488 Spider',parseFloat(9+7)], ['10-2017','GTC4Lusso',parseFloat(2+4)], ['9-2017','California',parseFloat(0+4)], ['9-2017','458 Speciale Aperta',parseFloat(1+0)], ['9-2017','FF',parseFloat(3+6)], ['9-2017','812 Superfast',parseFloat(2+1)], ['9-2017','458 Italia',parseFloat(1+3)], ['9-2017','GTC4Lusso',parseFloat(2+6)], ['9-2017','F12tdf',parseFloat(1+0)], ['9-2017','LaFerrari',parseFloat(0+1)], ['9-2017','488 GTB',parseFloat(18+13)], ['9-2017','458 Spider',parseFloat(3+2)], ['9-2017','F12berlinetta',parseFloat(4+10)], ['9-2017','458 Speciale',parseFloat(5+1)], ['9-2017','California T',parseFloat(23+37)], ['9-2017','488 Spider',parseFloat(11+14)], ['8-2017','FF',parseFloat(0+1)], ['8-2017','458 Spider',parseFloat(0+1)], ['8-2017','F12berlinetta',parseFloat(0+3)], ['8-2017','GTC4Lusso',parseFloat(0+6)], ['8-2017','488 GTB',parseFloat(0+1)], ['8-2017','California T',parseFloat(0+2)], ['8-2017','458 Italia',parseFloat(0+2)], ['8-2017','California',parseFloat(0+2)], ['7-2017','488 GTB',parseFloat(9+14)], ['7-2017','458 Speciale',parseFloat(1+4)], ['7-2017','California T',parseFloat(14+20)], ['7-2017','GTC4Lusso',parseFloat(1+7)], ['7-2017','California',parseFloat(1+6)], ['7-2017','458 Italia',parseFloat(1+4)], ['7-2017','458 Speciale Aperta',parseFloat(1+0)], ['7-2017','F12berlinetta',parseFloat(3+7)], ['7-2017','FF',parseFloat(2+3)], ['7-2017','458 Spider',parseFloat(1+3)], ['7-2017','488 Spider',parseFloat(10+10)], ['7-2017','F12tdf',parseFloat(0+1)], ['6-2017','488 GTB',parseFloat(7+23)], ['6-2017','458 Italia',parseFloat(2+2)], ['6-2017','812 Superfast',parseFloat(1+0)], ['6-2017','FF',parseFloat(0+3)], ['6-2017','GTC4Lusso',parseFloat(2+16)], ['6-2017','458 Spider',parseFloat(3+6)], ['6-2017','F12tdf',parseFloat(0+2)], ['6-2017','LaFerrari',parseFloat(0+1)], ['6-2017','F12berlinetta',parseFloat(4+9)], ['6-2017','458 Speciale',parseFloat(2+3)], ['6-2017','California T',parseFloat(16+18)], ['6-2017','488 Spider',parseFloat(11+14)], ['5-2017','458 Speciale',parseFloat(4+4)], ['5-2017','458 Italia',parseFloat(0+2)], ['5-2017','F12berlinetta',parseFloat(2+5)], ['5-2017','F12tdf',parseFloat(0+3)], ['5-2017','FF',parseFloat(0+1)], ['5-2017','488 GTB',parseFloat(8+13)], ['5-2017','458 Spider',parseFloat(0+2)], ['5-2017','GTC4Lusso',parseFloat(0+6)], ['5-2017','488 Spider',parseFloat(6+12)], ['5-2017','California T',parseFloat(12+19)], ];
I want to extract the unique models from the column and create the series for the line chart
function extractColumn(arr, column) {
function reduction(previousValue, currentValue) {
previousValue.push(currentValue[column]);
return previousValue;
}
return arr.reduce(reduction, []);
}
var prima = extractColumn(qry,1);
var models = [...new Set(prima)];
with extract column I get all the values of the column 1,and with the spread operator I get the models array, without duplicate.
var testa = []; // the header of the matrix
var tabella = []; // the array for the DataTable
for (i=1; i<models.length; i++) {
riga[i]=0;
}
testa.push([{label:'Montly', type: 'string'}]);
for (i=1; i<models.length; i++) {
testa.push([{label:models[i], type:'number'}]);
} // this code create the header objects
tabella.push(testa); //push the header into the tabella array
console.log(tabella[0]); //this push is ok!
var mese=qry[1][0]; // first date value
var riga = []; // array to add as row of the matrix
riga[0]=mese; // start populating the firs row
the following code should create a new row and append it to the chart table.
It checks the date of every row of the query matrix (qry): if it's a new date append the created row to the chart table and start a new row, if not it goes on creating the new row.
for (i=1; i<qry.length; i++){ // iterate qry array
if (mese!=qry[i][0]) { // check if the date is new
console.log(riga); // all the created row are ok!
tabella.push(riga); // append the row to the array
console.table(tabella); // WEIRD PROBLEM: ALL THE ARRAY ROW ARE CHANGED
mese=qry[i][0]; // EVERY CICLE!
for (x=1; x<models.length; x++) {
riga[x]=0;
}
riga[0]=mese; //reset the new row array and set the date
} else {
for (t=0;t<models.length;t++){
pos = models.indexOf(qry[i][1]);
if (pos != -1) {
riga[pos]=qry[i][2]
}
} // this code populates the new row.
}
}
The following code create the chart
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable(tabella);
var options = {
title: 'Montly Trend Focus on Complaint Type',
colors: ['#D9D904','#2A55FF','#000000'],
backgroundColor: {fill:'#FAFAFA',strokeWidth:1},
chartArea: {width:1800,height:380,left:70},
curveType: 'none',
legend: { position: 'bottom' },
hAxis: {direction:-1},
annotations: {
alwaysOutside: true,
textStyle: {
fontSize: 12,
bold: true,
color: '#000000',
}
}
};
var chart = new google.visualization.LineChart(document.getElementById('line_chart'));
chart.draw(data, options);
}
this is an image from my console:
I solved my problem redeclareing the new row in the loop:
for (i=1; i<qry.length; i++){
if (mese!=qry[i][0]) {
tabella.push(riga);
var riga=[]; // NEW DECLARATION
mese=qry[i][0];
for (x=1; x<models.length; x++) {
riga[x]=0;
}
riga[0]=mese;
}
else {
for (t=0;t<models.length;t++){
pos = models.indexOf(qry[i][1]);
if (pos != -1){riga[pos]=qry[i][2]}
}
}
}
Hope this will be usefull for others.
Related
JavaScript: Fullcalendar - Insert Break / Empty Row Between Months
I'm using Fullcalendar to render a calendar. Everything is working fine, but I have a specific request that I've been trying to solve, which is: show two months, but have some kind of visual separation (i.e. empty row) between them. I have my custom view set-up, but have no idea where to even begin on inserting a row between months. (My initial thoughts are: it's probably easier to insert a 'row' into the calendar after it renders, as opposed to getting too deep). I was thinking about looping through the calendar's HTML on the fc-day-top CSS class and use Moment.js to match the date and then break the row by inserting html into the DOM; but I'm not sure if that's the right approach. (please see the code below and fiddle) I am able to select the last day of the respective month, but am now trying to figure out the best way to insert HTML into the table with correct offsets before and after the split. Any help would be much appreciated! var calendarEl = document.getElementById('my-calendar'); var calendar = new FullCalendar.Calendar(calendarEl, { plugins: [ 'interaction', 'dayGrid','timeGrid', 'list' ], header: { left: 'prev,next today', center: 'title', right: 'listDay,dayGridMonth,monthView2' }, views: { monthView2: { type: 'dayGrid', duration: { months: 2 }, buttonText: '2-Month View', showNonCurrentDates: false, }, dayGridMonth: { buttonText: 'Month View', showNonCurrentDates: false, }, listDay: { buttonText: 'Day List' }, }, defaultView: 'monthView2', // With the code below: my initial though is: find the last day of the month, and insert <td>s and a row to split it datesRender: function( info ){ $('.fc-row.fc-week').each(function() { var thisWeek = $(this); var $d_i = 0; var htmlCellStringBefore = htmlCellStringAfter = ''; $(thisWeek).find('.fc-day-top').each(function() { $d_i++; var thisDay = $(this).data('date'); var thisDateYear = moment(thisDay).year(); var thisDateMonth = moment(thisDay).month(); var lastDay = new Date(thisDateYear, thisDateMonth + 1, 0); var lastDayMoment = moment(lastDay).format('YYYY-MM-DD'); // Match the last day, if matches, cut the table and insert HTML if(thisDay == lastDayMoment){ var cellIteratorBefore = 7 - $d_i; var cellIteratorAfter = 7 - cellIteratorBefore; // Looping to create number of offset cells before break for insertion for (i = 0; i < cellIteratorBefore; i++) { htmlCellStringBefore += '<td class="cellBefore"></td>'; } // Looping to create number of offset cells after break for insertion for (i = 0; i < cellIteratorAfter; i++) { htmlCellStringAfter+= '<td class="cellAfter"></td>'; } var returnHtmlHead = htmlCellStringBefore + '</tr></thead>'; // inserting empty cells after date to break into head var returnHtmlBody = htmlCellStringBefore + '</tr></tbody></table>'; // inserting empty cells after date to break into table body var thisTableFcBG = $(thisWeek).find('.fc-bg tbody td'); var thisTableFcSkeleton = $(thisWeek).find('.fc-content-skeleton tbody td'); var thisTableFcBGNthTableCell = $(thisTableFcBG)[cellIteratorBefore]; var thisTableFcSkeletonNthTableCell = $(thisTableFcSkeleton)[cellIteratorBefore]; var MonthName = moment(lastDayMoment).add(1, 'days').format("MMMM"); $('<div class="break-month-title">'+ MonthName+ '</div>').insertAfter(thisWeek); // This part is messy and i'm trying figure out the best way to split up the tables $(returnHtmlHead).insertAfter(thisDay); $(returnHtmlBody + '<div class="fc-row fc-week fc-widget-content"><div class="break-month">BREAK MONTH</div><div class="fc-bg"><table><thead><tr>'+ htmlCellStringAfter).insertAfter(thisTableFcBGNthTableCell); $(returnHtmlBody + '<div class="fc-content-skeleton"><table><thead><tr>' + htmlCellStringAfter).insertAfter(thisTableFcSkeletonNthTableCell); } }); }); } }); calendar.render(); .break-month { background:#f10000; } .break-month-title { text-align:center; padding:3rem; font-size:2rem; } <link href="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/4.2.0/core/main.min.css" rel="stylesheet"/> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://momentjs.com/downloads/moment.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/4.2.0/core/main.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/4.2.0/interaction/main.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/4.2.0/daygrid/main.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/4.2.0/timegrid/main.min.js"></script> <div id="my-calendar"></div> I also have a fiddle: https://jsfiddle.net/zjr73m41/
jexcel table SUM column after change
I want to sum a column in jexcel after entering a value This code is not working I don't know why: var change = function(instance, cell, value) { var cellName = $(instance).jexcel('getColumnNameFromId',$(cell).prop('id')); $('#log').append('New change on cell'+ cellName+'to:'+ value + '<br>'); var thisid = $(cell).prop('id'); var splitted = thisid.split("-"); var nextcellid = ++splitted[1]; var nextcell = '0-'+nextcellid; console.log(nextcell,'nextcell'); $("td#"+nextcell).html('<span>total</span>'); }
using onafterchange event: $('#my').jexcel({ data:data, colHeaders: ['Model'], colWidths: [ 300 ], onafterchange:function(instance){ console.log(instance) }, columns: [ { type: 'text' }, ] }); full handing events ready this url https://bossanova.uk/jexcel/docs/events or using this example https://bossanova.uk/jexcel/examples/including-formulas-on-your-spreadsheet
To be honest, you can just use =SUM(A1:A10) in the column you would like to have the total. Pretty much like excel.
Refreshing gridx cell value using DateTextBox
Working with gridx. I've added a Diji/form/DateTextBox to one of the columns. I am able to save back to the grid's JSON, but I am not managing to update what is displayed in the cell. function deadlineDecorator(value) { return '<div data-dojo-type="dijit/form/DateTextBox" data-dojo-props="constraints:{datePattern: \'dd/MM/yyyy\'}" data-dojo-attach-point="deadlineCal" required="true" />'; } function <portlet:namespace/>deadlineCellValueSet(gridData, storeData, cellWidget) { cellWidget.deadlineCal.set('value', newDate(gridData)); cellWidget.deadlineCal.constraints.min = new Date(); } var locale = dojo.require("dojo.date.locale"); function getDate(d){ res = locale.format(d, { selector: 'date', datePattern: 'dd/MM/yyyy' }); return res; } function deadlineChange(cellWidget, cell) { return [ [cellWidget.deadlineCal, 'onChange', function(e){ cell.setRawData(getDate(cellWidget.deadlineCal.value)); }] ]; } I am creating the grid using this: data = [{"id": 1, "dead": 18/12/2014}]; function creategrid() { var gridData = {data: data}; var dataStore = new dojo.store.Memory(gridData); grid.setStore(datastore); }; How can I save the chosen date back to the JSON AND show that change in the cell. I guess I could refresh the whole grid, but that doesn't seem like a very elegant solution?
Ember.js: rendering google chart in template (AKA target DOM element only when present)
I am trying to integrate a working google chart example into my ember.js app. The problem is that I'm not sure where to put the drawChart() function so that it is only run when it's target DOM element is on the page. Ember app example: http://jsbin.com/oqeSabI/4/edit Working google chart example: http://jsfiddle.net/doub1ejack/h7mSQ/96/ I'm thinking that the proper location for the load function is in a view (I don't see any reason to put it in a model/controller/route). But I need to be sure that drawChart() is not called until after the template has finished rendering and the <div id='chart'> element exists. Apparently View.init() is too early. Where should I call my build function? Does it even belong in a view (maybe I should use a control or handlebars helper?) App.DashboardView = Ember.View.extend({ name: "", init: function(){ // this breaks the app... //google.load("visualization", "1", {packages:["corechart"]}); //google.setOnLoadCallback(drawBarGraph); this.set('name', 'ted'); return this._super(); } });
It is best to place logic related to ui and layout in views. So for this task i would suggest to use a view or a component . As you already realised the didInsertElement event is the appropriate place to call this kind of logic, since you need to make sure that the view has been inserted into the DOM and all required elements such as div#chart are available. I'm providing a solution which is a bit rough but gives a starting point. The idea is to create, a reusable view GoogleChartView with an associated template google-chart that can be included in any other view. I assumed that dashboard view will eventually include other charts as well that will be using its model to present data in charts, tables etc. This chart related view has been included with the assistance of view helper {{view "googleChart"}} . Another important point is that google.load needs to be called in head. http://jsbin.com/oCIcexOB/1/edit JS App = Ember.Application.create(); /******** VIEWS ********/ App.DashboardView = Ember.View.extend({ name: "", init: function(){ //google.load("visualization", "1", {packages:["corechart"]}); //google.setOnLoadCallback(drawBarGraph); this.set('name', 'ted'); return this._super(); } }); App.GoogleChartView = Ember.View.extend({ templateName:"google-chart", drawChart:function(){ drawChart(); }.on("didInsertElement") }); /******** ROUTES ********/ App.Router.map(function() { this.resource('items'); this.resource('dashboard'); }); App.IndexRoute = Ember.Route.extend({ redirect: function() { this.transitionTo('items'); } }); App.ItemsRoute = Ember.Route.extend({ model: function() { var a = Em.A(); a.pushObject( App.Item.create({title: 'A', cost: '100', options: buildMockOptions('A')})); a.pushObject( App.Item.create({title: 'B', cost: '200', options: buildMockOptions('B')})); a.pushObject( App.Item.create({title: 'C', cost: '300', options: buildMockOptions('C')})); return a; } }); buildMockOptions = function(someVar){ var arr = []; for(var i = 0;i<3;i++){ var opt = App.Option.create({someOption: 'Option for ' + someVar + ': ' + i}); opt.cost = 5; arr.pushObject(opt); } return arr; }; /******** MODELS ********/ App.Item = Ember.Object.extend({ title: '', cost: '', quantity: '', options: null, totalOptionsCost: function(){ var j = this.get('options').reduce( function(prevValue, currentValue, index, array){ return prevValue + parseInt(currentValue.get('cost'), 10); }, 0); return j; }.property('options.#each.cost') }); App.Option = Ember.Object.extend({ someOption: '', cost: '' }); /******** CONTROLLERS ********/ App.ItemsController = Ember.ArrayController.extend({ len: function(){ return this.get('length'); }.property('length'), totalCost: function() { return this.reduce( function(prevCost, cost){ return parseInt(cost.get('cost'),10) + prevCost; }, 0); }.property('#each.cost'), totalOptions: function(){ var opts = this.mapBy('options'); return [].concat.apply([], opts).length; }.property(), totalOptionCost: function(){ var sum = this.reduce(function(prev, curr){ return prev + curr.get('totalOptionsCost');},0); return sum; }.property('#each.totalOptionsCost') }); App.DashboardController = Em.Controller.extend({ needs: ['items'], itemsLength: Ember.computed.alias('controllers.items.len'), itemsTotalCost: Ember.computed.alias('controllers.items.totalCost'), optionsTotal: Ember.computed.alias('controllers.items.totalOptions'), optionsCost: Ember.computed.alias('controllers.items.totalOptionCost') }); // GOOGLE CHART FUNCTION function drawChart() { // Create and populate the data table. var options = { title:"Yearly Coffee Consumption", width:600, height:400, animation: {duration: 1000, easing: 'out'}, vAxis: {title: "Cups", minValue:0, maxValue:500}, hAxis: {title: "Year"} }; var data = new google.visualization.DataTable(); data.addColumn('string', 'N'); data.addColumn('number', 'Value'); data.addRow(['2003', 0]); data.addRow(['2004', 0]); data.addRow(['2005', 0]); // Create and draw the visualization. var chart = new google.visualization.ColumnChart(document.getElementById('chart')); chart.draw(data, options); data.setValue(0, 1, 400); data.setValue(1, 1, 300); data.setValue(2, 1, 400); chart.draw(data, options); var button = document.getElementById('b1'); button.onclick = function() { if (data.getNumberOfRows() > 5) { data.removeRow(Math.floor(Math.random() * data.getNumberOfRows())); } // Generating a random x, y pair and inserting it so rows are sorted. var x = Math.floor(Math.random() * 10000); var y = Math.floor(Math.random() * 1000); var row = 0; while (row < data.getNumberOfRows() && parseInt(data.getValue(row, 0),10) < x) { row++; } data.insertRows(row, [[x.toString(), y]]); chart.draw(data, options); }; } function drawChart() { // Create and populate the data table. var options = { title:"Yearly Coffee Consumption", width:600, height:400, animation: {duration: 1000, easing: 'out'}, vAxis: {title: "Cups", minValue:0, maxValue:500}, hAxis: {title: "Year"} }; var data = new google.visualization.DataTable(); data.addColumn('string', 'N'); data.addColumn('number', 'Value'); data.addRow(['2003', 0]); data.addRow(['2004', 0]); data.addRow(['2005', 0]); // Create and draw the visualization. var chart = new google.visualization.ColumnChart(document.getElementById('chart')); chart.draw(data, options); data.setValue(0, 1, 400); data.setValue(1, 1, 300); data.setValue(2, 1, 400); chart.draw(data, options); var button = document.getElementById('b1'); button.onclick = function() { if (data.getNumberOfRows() > 5) { data.removeRow(Math.floor(Math.random() * data.getNumberOfRows())); } // Generating a random x, y pair and inserting it so rows are sorted. var x = Math.floor(Math.random() * 10000); var y = Math.floor(Math.random() * 1000); var row = 0; while (row < data.getNumberOfRows() && parseInt(data.getValue(row, 0),10) < x) { row++; } data.insertRows(row, [[x.toString(), y]]); chart.draw(data, options); }; } HTML <!DOCTYPE html> <html> <head> <meta name="description" content="Ember.js example: Trying to display a google chart in a template." /> <meta charset=utf-8 /> <title>JS Bin</title> <script src="http://www.google.com/jsapi?ext.js"></script> <script src="http://code.jquery.com/jquery-2.0.2.js"></script> <script src="http://builds.emberjs.com/handlebars-1.0.0.js"></script> <script src="http://builds.emberjs.com/ember-latest.js"></script> <script src="http://www.google.com/jsapi?ext.js"></script> <script>google.load("visualization", "1", {packages:["corechart"]});</script> </head> <body> <script type="text/x-handlebars" data-template-name="application"> <p><strong>Ember.js example:</strong><br> Trying to display a google chart in a template.</p> <p>This jsbin represents a dashboard that analyzes a hierarchy of items and child 'options' and visualizes that info in a 'dashboard' section'. Currently, I am trying to integrate a google chart into the dashboard right above the 'Change Value' button.</p> <p>Google chart example: <a href='http://jsfiddle.net/doub1ejack/h7mSQ/96/'>http://jsfiddle.net/doub1ejack/h7mSQ/96/</a><br> Stackoverflow post: <a href='http://stackoverflow.com/questions/20198317/ember-js-rendering-google-chart-in-template-aka-target-dom-element-only-when-p'>http://stackoverflow.com/questions/20198317/...</a></p> {{render dashboard}} {{outlet}} </script> <script type="text/x-handlebars" data-template-name="items"> <h2>Items:</h2> <dl> {{#each}} <dt>Item: {{title}}</dt> <dd>Cost: {{cost}}</dd> <dd class='options'>{{render 'options' options}}</dd> {{/each}} </dl> </script> <script type="text/x-handlebars" data-template-name="options"> {{log controller}} <dl> {{#each option in controller }} <dt>{{option.someOption}}</dt> <dd>Option cost: {{option.cost}}</dd> {{/each}} </dl> </script> <script type="text/x-handlebars" data-template-name="dashboard"> <h2>Dashboard:</h2> {{view "googleChart"}} <div id="chart"></div> {{! ITEM/OPTION ANALYSIS }} {{#if controllers.items}} <h3>Item Overview:</h3> Total number of items (expect 3): {{itemsLength}}<br> Total cost of items (expect 600): {{itemsTotalCost}} <h3>Option Overview:</h3> Total number of options (expect 30): {{optionsTotal}}<br> Total cost of options (expect 45): {{optionsCost}} {{/if}} </script> <script type="text/x-handlebars" data-template-name="google-chart"> <div id="chart"></div> <form><input id="b1" type="button" value="Change Value"/></form> </script> </body> </html> EDIT This is another example where the code with the properties and data related to drawing the chart are accomodated in the GoogleChartView class, allowing for binding of properties, execution of actions etc. This is also a draft example just to demonstrate the idea. The change value action executes the old code but it could certainly do modifications to the data property of GoogleChartView. The data property of GoogleChartView could certainly take better advantage of the model. Interesting points are the retrieval of the view's DOM via this.$().find, the access to the controller (DashboardController) of the context where this view in included, since at this point any data could be retrieved,parsed and drawn. http://jsbin.com/UHajoX/1/edit App.GoogleChartView = Ember.View.extend({ templateName:"google-chart", chart:null, options:{ title:"Yearly Coffee Consumption", width:600, height:400, animation: {duration: 1000, easing: 'out'}, vAxis: {title: "Cups", minValue:0, maxValue:500}, hAxis: {title: "Year"} }, data:function(){ var items = this.get("controller").get("items"); var chartData = new google.visualization.DataTable(); chartData.addColumn('string', 'N'); chartData.addColumn('number', 'Value'); chartData.addRow(['2003', 0]); chartData.addRow(['2004', 0]); chartData.addRow(['2005', 0]); items.forEach(function(item,index){ chartData.setValue(index,1,parseInt(item.get("cost"),10)); }); /*chartData.setValue(0, 1, 400); chartData.setValue(1, 1, 300); chartData.setValue(2, 1, 400);*/ return chartData; }.property(), drawChart:function(){ this.drawChart2(); }.on("didInsertElement"), drawChart2:function(){ var data = this.get("data"); // Create and draw the visualization. this.set("chart", new google.visualization.ColumnChart(this.$().find('#chart').get(0))); this.get("chart").draw(data, this.get("options")); }, actions:{ changeValue:function(){ var data = this.get("data"); if (data.getNumberOfRows() > 5) { data.removeRow(Math.floor(Math.random() * data.getNumberOfRows())); } // Generating a random x, y pair and inserting it so rows are sorted. var x = Math.floor(Math.random() * 10000); var y = Math.floor(Math.random() * 1000); var row = 0; while (row < data.getNumberOfRows() && parseInt(data.getValue(row, 0),10) < x) { row++; } data.insertRows(row, [[x.toString(), y]]); this.set("data",data); this.get("chart").draw(data, this.get("options")); } } }); caveat: I guess in the future the data may originate from the ember app itself, but now when calling google load there might be a possibility where the view tries to call drawChart and the data is not been available yet. To overcome this you may need to check that the data have been loaded before calling drawChart.
returning the table head value in google visualization tables with JavaScript
I'm writing a JavaScript application using Google Visualization API. /* Define a table */ var table = new google.visualization.ChartWrapper({ 'chartType': 'Table', 'containerId': 'chart2', 'options': { 'sortColumn': '-1', 'allowHtml' : 'true', }, 'style' : { 'white-space' : 'nowrap' } }); google.visualization.events.addListener(table, 'select', function (){ var tablewrapper = table.getChart(); var tabledata = table.getDataTable(); var value = $('.google-visualization-table-tr-head td').html(); console.log(value); //var columnId = tablewrapper.getColumnDescriptions(); //console.log(tablewrapper); /*var columnIndex = tablewrapper.getViewColumnIndex(); var selection = tablewrapper.getSelection(); for(var i = 0; i < selection.length; i++){ var item = selection[i]; console.log('{row:' + item.row + ',column:' + item.column + '}'); var properties = tabledata.getRowProperties(parseInt(item.row)); console.log(properties); } */ } ); Above is the definition of my listener. My goal is either to get the columnIndex or return the table head name, or the entire column. If I can get the columnIndex returned, then it's straight forward. However, if I have the column header name, I can map it to a hashtable, and retrieve the columnIndex. If I have the entire column, I want to return the first element of the array, which is the id. However, I don't know how to accomplish neither of those tasks. Could someone please help me with that? Either using the Google's Visualization API or JQuery