why is google chart column not generating in angular app? - javascript

I am adding the Google column chart I Pasted some code from AGC to my page but why is it not generating the chart?
Bar.cshtml
<div google-chart chart="myChartObject" width:100%;"></div>
#section scripts{
<script src="~/Scripts/Charts/BarCharts.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-google-chart/0.1.0/ng-google-chart.js" type="text/javascript"></script>}
MyApp.cshtml
var app = angular.module('MyApp', [])
app.filter('ctime', function(){
return function(jsonDate){
var date = new Date(parseInt(jsonDate.substr(6)));
return date;
}
})
Javfile.Js
var app = angular.module("MyApp", ['googlechart']);
app.controller("GenericChartCtrl", function ($scope) {
$scope.myChartObject = {};
$scope.myChartObject.type = "ColumnChart";
$scope.onions = [
{ v: "Onions" },
{ v: 3 },
];
$scope.myChartObject.data = {
"cols": [
{ id: "t", label: "Topping", type: "string" },
{ id: "s", label: "Slices", type: "number" }
], "rows": [ {
c: [ { v: "Mushrooms" }, { v: 3 },]},{ c: $scope.onions },{c: [{ v: "Olives" }, { v: 31 }]}

<div google-chart chart="myChartObject" style="width:100%;" ng-controller="GenericChartCtrl">
</div>
Try this i hope it will work

Related

Svelte on:change runs too late

I have a Svelte app with:
A dropdown that lets you choose a chart to view (pie chart / bar chart / calendar)
A panel of checkboxes with variables to include in the chart. (Different charts have different variables available)
A function that filters my data just for the selected variables, then passes that data to a chart.
Full code that you can run here:
<script>
let rawData = {
LevelTracker: [{ text: "headache" }, { text: "pain" }],
EventType: [{ text: "coffee" }, { text: "aspirin" }],
Event: [
{ time: 1500000000, text: "coffee" },
{ time: 1500030000, text: "aspirin" },
{ time: 1500230000, text: "coffee" },
// etc....
],
LevelChange: [
{ time: 1500000000, text: "headache", level: 2 },
{ time: 1500030000, text: "headache", level: 3 },
{ time: 1500230000, text: "pain", level: 2 },
// etc....
],
};
$: availableLTs = rawData.LevelTracker.map((e) => e.text);
$: availableETs = rawData.EventType.map((e) => e.text);
let schemas = [
{
name: "byTimeOfDay",
vars: [{ name: "X", et: true, lt: true }],
},
{
name: "lagBarChart",
vars: [
{ name: "X", min: 1, et: true, lt: false },
{ name: "Y", min: 1, max: 1, lt: true, et: true },
],
},
{
name: "calendar",
vars: [{ name: "X", et: true, lt: true }],
},
];
let chartsMap = {};
for (let schema of schemas) {
chartsMap[schema.name] = schema;
}
//let selectedChart = "lagBarChart";
//let selectedChart = "byTimeOfDay";
let selectedChart = "calendar";
function getInitSelectedVars(schemaVars) {
let selection = {};
for (let varSchema of schemaVars) {
selection[varSchema.name] = { ets: [], lts: [] };
}
return selection;
}
function initSelectedVars() {
console.log("in initSelectedVars");
selectedVars = getInitSelectedVars(schemaVars);
}
function makeChartData({ selectedVars, rawData }) {
console.log("in makeChartData");
for (let [key, value] of Object.entries(selectedVars)) {
// TODO: we filter rawData for just the selected vars, and return that data...
}
}
// this will be passed to the chart component
$: chartData = makeChartData({
selectedVars,
rawData,
});
$: schemaVars = chartsMap[selectedChart].vars;
$: selectedVars = selectedVars || getInitSelectedVars(schemaVars);
</script>
<main>
<h2>Select chart type</h2>
<select bind:value={selectedChart} on:change={initSelectedVars}>
{#each schemas as chart}
<option value={chart.name}>
{chart.name}
</option>
{/each}
</select>
<h2>Select your vars</h2>
{#each schemaVars as schemaVar}
<h3>
{schemaVar.name}
</h3>
{#if schemaVar.lt}
{#each availableLTs as ele}
<div class="form-check">
<label>
<input
type="checkbox"
class="form-check-input"
bind:group={selectedVars[schemaVar.name].lts}
value={ele}
/>
{ele}
</label>
</div>
{/each}
{/if}
{#if schemaVar.et}
{#each availableETs as ele}
<div class="form-check">
<label>
<input
type="checkbox"
class="form-check-input"
bind:group={selectedVars[schemaVar.name].ets}
value={ele}
/>
{ele}
</label>
</div>
{/each}
{/if}
{/each}
<!-- then we display the selected chart, like:
<calendar {chartData} />
-->
</main>
<style>
</style>
Each time the user changes the dropdown, we need to re-initialize selectedVars to a value that matches the current chart's schema.
For example, if calendar is selected we need to do:
selectedVars = {X: {ets: [], lts: []}}
But if barchart is selected, we need:
selectedVars = {X: {ets: [], lts: []}, Y: {ets: [], lts: []}}
I defined a function that does this, and put on:change={initSelectedVars} in the chart dropdown. However, each time I change the chart type from 'calendar' to 'bar chart', I still get an error in my makeChartData:
Uncaught (in promise) TypeError: Cannot read property 'lts' of undefined
at Object.mount [as m] (Debug.svelte:101)
at Object.mount [as m] (Debug.svelte:95)
at Object.mount [as m] (Debug.svelte:109)
at Object.update [as p] (Debug.svelte:90)
at update (index.mjs:764)
at flush (index.mjs:732)
I think that on:change function would only get run after selectedVars is changed, so it's too late.
Any suggestions? My code is below.
Are you sure, the error occurs in the makeChartData function?
It might be this line: bind:group={selectedVars[schemaVar.name].lts}
I have not fully understand your code yet, but it should be possible to change the value of selectedVars to the desired value with reactive statements. So, I don't think you need a on:change handler.
Edit:
I think you want something like that: https://svelte.dev/repl/57d760278e0e4acfad536c1269bceba3?version=3.37.0

want to pass one extra column value to the $scope.seriesSelected

I am working on Timeline charts in angularjs google chart API.
From Timeline chart API i understood that only 4 columns are allowed and the other column would be a tooltip column.
I have a requirement where i am attaching the ID of that row along with the description and i want to pass that ID when the row is clicked but dont want to show on the label.
js code:
angular.module('myApp', ['googlechart'])
.controller('myController', function($scope,$timeout) {
var chart1 = {};
chart1.type = "Timeline";
chart1.displayed = false;
var container = document.getElementById('timeline')
chart1.data = {
"cols": [{
id: "month",
label: "Month",
type: "string"
}, {
id: "description",
label: "Description",
type: "string"
}, {
id: "start",
label: "start",
type: "date"
}, {
id: "end",
label: "end",
type: "date"
}],
"rows": [{
c: [{
v: "January"
}, {
v: "Jan text here -$# 1001".trim().split(' -$#')[0]
}, {
v: new Date(2018, 3, 1)
}, {
v:new Date(2018, 4, 12)
} ]
}, {
c: [{
v: "February"
}, {
v: "feb text here -$# 1002".trim().split(' -$#')[0]
}, {
v: new Date(2018,4, 1)
}, {
v: new Date(2018, 4, 15)
} ]
} , {
c: [{
v: "april"
}, {
v: "april text here -$# 1003".trim().split(' -$#')[0]
}, {
v: new Date(2018,5, 1)
}, {
v: new Date(2018, 7, 15)
} ]
} ]
};
chart1.options = {
timeline: {
showRowLabels: false,
},
};
$scope.seriesSelected = function(selectedItem) {
var rowValue = chart1.data.rows[selectedItem.row].c[1].v;
alert(rowValue);
}
$scope.myChart = chart1;
});
In the above js code, i am attaching the rowID like 1001,1002,.. to the description column (Jan text here -$# 1001".trim().split(' -$#')[0]), but using trim() because i should not show the ID on the screen. When clicked on the row
var rowValue = chart1.data.rows[selectedItem.row].c[1].v; i wanted to get the entire value as Jan text here -$# 1001 but it is not showing the ID values as shown in the demo link. Any inputs on how to pass the ID values (1001,1002..) appended in the description to the $scope.seriesSelected .
PS: Is it possible to include another column where i can assign the ID values(1001,1002..), but it should not be shown on the webpage/tooltip.
you can assign properties to each cell, row, or column...
c: [{
v: "January"
}, {
v: "Jan text here", p: {id: 1001}
},
...
and use data table methods to get / set...
dataTable.getProperty(rowIndex, columnIndex, name);
dataTable.setProperty(rowIndex, columnIndex, name, value);
or access the property directly from the json used as the data table...
chart1.data.rows[selectedItem.row].c[1].p.id

Rendering a table in Angular 1 without ng-repeat

I'm trying to find a better way for rendering a large table in Angular than using ngRepeat.
I tried using one-time {{::binding}}s, but found the initial render time remained unchanged, which wasn't satisfactory.
Back to the drawing board, I'm trying to find a much more performant method for assembling data into a HTML table in the DOM. I've been trying to use angular.element() to assemble all the parts into a whole, but with no luck. Any insights?
var app = angular.module('app', []);
app.directive('myTable', function() {
return {
restrict: 'E',
scope: {
ngModel: "=",
},
require: 'ngModel',
link: function(scope, element, attrs) {
scope.$watch('ngModel', function() {
if (typeof scope.ngModel == 'undefined') {
console.log("ngModel not defined yet");
return;
}
element.html('');
var table = angular.element('<table/>');
var tbody = angular.element('<tbody/>');
scope.ngModel.forEach(function(m) {
var tr = angular.element('<tr/>');
m.fields.forEach(function(f) {
var td = angular.element('<td/>')
td.text(f.value);
td.append(tr);
});
tr.append(tbody);
})
tbody.append(table);
table.append(element);
})
}
}
});
app.controller('AppController', function($scope) {
$scope.data = [{
fields: [{
value: 1,
metadata: ""
}, {
value: 2,
metadata: ""
}, {
value: 3,
metadata: ""
}, {
value: 4,
metadata: ""
}, {
value: 5,
metadata: ""
}, ]
},
{
fields: [{
value: 6,
metadata: ""
}, {
value: 7,
metadata: ""
}, {
value: 8,
metadata: ""
}, {
value: 9,
metadata: ""
}, {
value: 10,
metadata: ""
}, ]
}
]
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body>
<div ng-app="app" ng-controller="AppController">
<my-table ng-model="data"></my-table>
</div>
</body>
It is inappropriate to involve the ngModel controller in a directive that has no user input elements. Also isolate scope is unnecessary. Evaluate the table-data attribute in the watch expression.
Also of course, fix the backwards append statements:
app.directive('myTable', function() {
return {
restrict: 'E',
̶s̶c̶o̶p̶e̶:̶ ̶{̶
̶n̶g̶M̶o̶d̶e̶l̶:̶ ̶"̶=̶"̶,̶
̶}̶,̶
̶r̶e̶q̶u̶i̶r̶e̶:̶ ̶'̶n̶g̶M̶o̶d̶e̶l̶'̶,̶
link: function(scope, element, attrs) {
scope.$watch(attrs.tableData ̶'̶n̶g̶M̶o̶d̶e̶l̶'̶, function(data) {
if (data) {
console.log("table-data not defined yet");
return;
}
element.html('');
var table = angular.element('<table/>');
var tbody = angular.element('<tbody/>');
data.forEach(function(m) {
var tr = angular.element('<tr/>');
m.fields.forEach(function(f) {
var td = angular.element('<td/>')
td.text(f.value);
̶t̶d̶.̶a̶p̶p̶e̶n̶d̶(̶t̶r̶)̶;̶ tr.append(td);
});
̶t̶r̶.̶a̶p̶p̶e̶n̶d̶(̶t̶b̶o̶d̶y̶)̶;̶ tbody.append(tr);
})
̶t̶b̶o̶d̶y̶.̶a̶p̶p̶e̶n̶d̶(̶t̶a̶b̶l̶e̶)̶;̶ table.append(tbody);
̶t̶a̶b̶l̶e̶.̶a̶p̶p̶e̶n̶d̶(̶e̶l̶e̶m̶e̶n̶t̶)̶;̶ element.append(table);
})
}
}
});
Usage:
<my-table table-data="data"></my-table>
THE DEMO
var app = angular.module('app', []);
app.directive('myTable', function() {
return {
restrict: 'E',
link: function(scope, element, attrs) {
scope.$watch(attrs.tableData, function(data) {
console.log(data);
if (!data) {
console.log("tableData not defined yet");
return;
}
element.html('');
var table = angular.element('<table/>');
var tbody = angular.element('<tbody/>');
data.forEach(function(m) {
var tr = angular.element('<tr/>');
m.fields.forEach(function(f) {
var td = angular.element('<td/>')
td.text(f.value);
tr.append(td);
});
tbody.append(tr);
})
table.append(tbody);
element.append(table);
})
}
}
});
app.controller('ctrl', function($scope) {
$scope.data = [{
fields: [{
value: 1,
metadata: ""
}, {
value: 2,
metadata: ""
}, {
value: 3,
metadata: ""
}, {
value: 4,
metadata: ""
}, {
value: 5,
metadata: ""
}, ]
},
{
fields: [{
value: 6,
metadata: ""
}, {
value: 7,
metadata: ""
}, {
value: 8,
metadata: ""
}, {
value: 9,
metadata: ""
}, {
value: 10,
metadata: ""
}, ]
}
]
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app" ng-controller="ctrl">
<my-table table-data="data"></my-table>
</body>

Knockout - Unable to process binding, gridViewModel is not defined

I am new to knockout and I have no idea why I am getting this message.
Unable to process binding "simpleGrid: function (){return gridViewModel }"
Message: gridViewModel is not defined;
library_customization.js
define(['services/logger'], function (logger) {
var title = 'Library Customization';
var vm = {
activate: activate,
title: title
};
return vm;
var initialData = [
{ name: "Well-Travelled Kitten", sales: 352, price: 75.95 },
{ name: "Speedy Coyote", sales: 89, price: 190.00 },
{ name: "Furious Lizard", sales: 152, price: 25.00 },
{ name: "Indifferent Monkey", sales: 1, price: 99.95 },
{ name: "Brooding Dragon", sales: 0, price: 6350 },
{ name: "Ingenious Tadpole", sales: 39450, price: 0.35 },
{ name: "Optimistic Snail", sales: 420, price: 1.50 }
];
var PagedGridModel = function (items) {
this.items = ko.observableArray(items);
this.addItem = function () {
this.items.push({ name: "New item", sales: 0, price: 100 });
};
this.sortByName = function () {
this.items.sort(function (a, b) {
return a.name < b.name ? -1 : 1;
});
};
this.jumpToFirstPage = function () {
this.gridViewModel.currentPageIndex(0);
};
this.gridViewModel = new ko.simpleGrid.viewModel({
data: this.items,
columns: [
{ headerText: "Item Name", rowText: "name" },
{ headerText: "Sales Count", rowText: "sales" },
{ headerText: "Price", rowText: function (item) { return "$" + item.price.toFixed(2) } }
],
pageSize: 4
});
};
ko.applyBindings(new PagedGridModel(initialData));
function activate() {
logger.log(title + ' selected', null, title, true);
return true;
}
});
library_customization.html
<!DOCTYPE html>
<html id="libraryCust">
<head>
<title> Project</title>
<script type="text/javascript" src="../../Scripts/knockout-3.3.0.js
</script>
</head>
<body>
<section>
<h2 class="page-title" data-bind="text: title"></h2>
</section>
<div class='liveExample'>
<div data-bind='simpleGrid: gridViewModel'></div>
<!-- -->
<button data-bind='click: addItem'>
Add item
</button>
<button data-bind='click: sortByName'>
Sort by name
</button>
<button data-bind='click: jumpToFirstPage, enable: gridViewModel.currentPageIndex'>
Jump to first page
</button>
</div>
</body>
</html>
Check the fiddle: JS Fiddle
I think the main problem is that you exit your module earlier than planned in the code below:
var title = 'Library Customization';
var vm = {
activate: activate,
title: title
};
return vm;
/* your main code follows below but never executes */
So I moved these properties into the PagedGridModel constructor.

How do i correctly put a $scope.$watch on a two dimensional array?

Putting an Angular watch on a multidimensional array is proving problematic
I have a screen where the user will see two teams (outer array) with a teamsheet(inner array) for each team. He is able to drag and drop the players to change the batting order.
The battingOrder is updated according to the player's spot in the array.
The following solution is a bit of a cop out/short term, but it does solve my immediate stumbling block.
A more preferable solution would be appreciated though.
The following code is in my controller.
$scope.$watch(
"Teams[0].TeamSheet",
function (newValue, oldValue) {
for (var i = 0; i < newValue.length; i++) {
newValue[i].battingOrder = i + 1;
}
},
true
);
$scope.$watch(
"Teams[1].TeamSheet",
function (newValue, oldValue) {
for (var i = 0; i < newValue.length; i++) {
newValue[i].battingOrder = i + 1;
}
},
true
);
$scope.Teams = [{
TeamName: "South-Africa",
TeamSheet: [
{
name: "A Peterson",
battingOrder: 1,
mode: "view"
},
{
name: "Riley Rossouw",
battingOrder: 2,
mode: "view"
},
{
name: "H Amla",
battingOrder: 3,
mode: "view"
},
{
name: "F Du Plessis",
battingOrder: 4,
mode: "view"
},
{
name: "AB De Villiers",
battingOrder: 5,
mode: "view"
}
]
},
{
TeamName: "Australia",
TeamSheet: [
{
name: "D Warner",
battingOrder: 1,
mode: "view"
},
{
name: "S Watson",
battingOrder: 2,
mode: "view"
},
{
name: "M Clarke",
battingOrder: 3,
mode: "view"
},
{
name: "C Rogers",
battingOrder: 4,
mode: "view"
},
{
name: "S Smith",
battingOrder: 5,
mode: "view"
}
]
}];
you can try to update batting order directly inside the view:
<div ng-repeat="member in team" ng-init="member.battingOrder = $index">
</div>
then you do not need to use $watch
EDIT
the previous solution will not work after you swap items in your array. Use the following code to overcome this problem:
<body ng-controller="MainCtrl">
<div ng-repeat="member in team">
{{setIndex(member,$index)}}
{{member.name}},{{member.index}}
</div>
<button ng-click="swap()">swap first with last</button>
</body>
controller:
app.controller('MainCtrl', function($scope) {
$scope.team = [ { index: 0, name : 'first' }, { index: 0, name : 'second' }, { index: 0, name : 'third' } ];
$scope.swap = function () {
var tmp = $scope.team[0];
$scope.team[0] = $scope.team[2];
$scope.team[2] = tmp;
}
$scope.setIndex = function (member, index)
{
member.index = index;
}
});
http://plnkr.co/edit/V3ixkww7dxcx8uZ7f0hj?p=preview

Categories

Resources