google is undefined error while using charts - charts

Trying to display statistics as per table data.
I want to use google charts, but there is a google is not defined error. Only the data in the HTML part is displayed. The necessary bar chart is not displayed.
The code works fine on jsfiddle.The code is as below:
google.charts.load('current', {'packages':['bar']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Days', 'Service', 'Incident', 'Others'],
['1-10 Days', 10, 6, 4],
['11-20 Days', 0, 0, 2],
['21-30 Days', 0, 4, 4]
]);
var options = {
chart: {
title: 'TAT CHART',
subtitle: 'Service, Incident, and Others',
},
bars: 'vertical',
vAxis: {format: 'decimal'},
height: 300,
colors: ['#1b9e77', '#d95f02', '#7570b3']
};
var chart = new google.charts.Bar(document.getElementById('chart_div'));
chart.draw(data, google.charts.Bar.convertOptions(options));
google.visualization.events.addListener(chart, 'select', function () {
var selection = chart.getSelection();
if (selection.length) {
var row = selection[0].row;
document.querySelector('#myValueHolder').innerHTML = data.getValue(row, 1);
var view = new google.visualization.DataView(data);
}
});
}
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
<br/>
<div id="disp_table">
<table class="display" style="width:50%;">
<thead>
<th>Days</th>
<th>Service</th>
<th>Incident</th>
<th>Others</th>
</thead>
<tbody>
<?php
for ($i = 0; $i < count($plot); $i++) {?>
<tr>
<td><?php echo $plot[$i][0]['days']; ?></td>
<td><?php echo $plot[$i][0]['service']; ?></td>
<td><?php echo $plot[$i][0]['incident']; ?></td>
<td><?php echo $plot[$i][0]['other']; ?></td>
</tr>
<?php }
?>
</tbody>
</table/>
Trying to display statistics as per table data.
I want to use google charts, but there is a google is not defined error. Only the data in the HTML part is displayed. The necessary bar chart is not displayed.
The code works fine on jsfiddle.The code is as below:

Related

webapp form value to spreadsheet

I have a webapp form and I'm looking for a way to push the value of the form into google spreadsheet.
My current attempt is to assign a name to each form input (a1,a2,a3...) then attempt to iterate the form values into an array like this:
Code.gs
function doGet(e) {
return HtmlService
.createTemplateFromFile('Index')
.evaluate()
.setSandboxMode(HtmlService.SandboxMode.NATIVE)
}
function writeForm(form) {
var ss =
SpreadsheetApp.openById('1bKrGjBV*****');
var sheet = ss.getSheets()[0];
var data = ss.getDataRange().getValues();
var input = [''];
var ndata = form
for(var j=0;j<data.length;j++){
var value = form.a+j
input.push(value)
}
for(var k=0;k<data.length;k++){
sheet.getRange(k+1,4).setValue(ndata[k]);
}
var range = sheet.getRange(1, 5);
}
function getData(){
return SpreadsheetApp
.openById('1bKrGjBV*****')
.getSheets()[0]
.getDataRange()
.getValues();
}
Index.html
<body>
<center><h1>Produce Inventory Form </h1></center>
<style>
table,th,td{border:1px solid black;}
</style>
<? var data = getData(); ?>
<form id="invform">
<input type = "submit" value="Submit" onclick
="google.script.run.writeForm(this.parentNode)">
<table align="center">
<tr><th>Code</th><th>Name</th><th>ChName</th><th>On Hand</th></tr>
<? for(var i=0;i<data.length;i++){ ?>
<tr>
<th><?= data[i][0] ?></th>
<th><?= data[i][1] ?></th>
<th><?= data[i][2] ?></th>
<th><input type = "text" style="width:40px" min="0" maxlength="3" name=a<?
=i ?>>
</tr>
<? } ?>
</table>
</body>
With this method, the problem I'm getting into is
var value = form.a+j
Doesn't do what I was hoping for, which is to assign a variable to form.a1, form.a2, form.a3, ... then push it into an array.
I'm pretty sure there's a better way but I have yet to find a solution. Apologize for the messy code, but I was focused on getting the result.
How about a following modification?
Modification points :
For Index.html, </form> is missing.
About form.a+j, you can retrieve the values using form["a" + j].
ndata is JSON like {a1: "value", a2: "value"}. So when ndata is imported to cells, it becomes undefined.
When several values are imported to cells, the importing efficiency becomes higher by using setValues().
When these are reflected to your script, the modified script is as follows. The values inputted to forms are imported to "D1:D" of spreadsheet.
Modified script :
Code.gs
function doGet(e) {
return HtmlService
.createTemplateFromFile('Index')
.evaluate()
.setSandboxMode(HtmlService.SandboxMode.NATIVE)
}
function writeForm(form) {
var ss = SpreadsheetApp.openById('1bKrGjBV*****');
var sheet = ss.getSheets()[0];
var data = ss.getDataRange().getValues();
var input = []; // Modified
// var ndata = form
for(var j=0;j<data.length;j++){
var value = form["a" + j]; // Modified
input.push([value]) // Modified
}
sheet.getRange(1, 4, input.length, input[0].length).setValues(input); // Added
// for(var k=0;k<data.length;k++) {
// sheet.getRange(k+1,4).setValue(ndata[k]);
// }
// var range = sheet.getRange(1, 5);
}
function getData(){
return SpreadsheetApp
.openById('1bKrGjBV*****')
.getSheets()[0]
.getDataRange()
.getValues();
}
Index.html
<body>
<center><h1>Produce Inventory Form </h1></center>
<style>
table,th,td{border:1px solid black;}
</style>
<? var data = getData(); ?>
<form id="invform">
<input type = "submit" value="Submit" onclick="google.script.run.writeForm(this.parentNode)">
<table align="center">
<tr><th>Code</th><th>Name</th><th>ChName</th><th>On Hand</th></tr>
<? for(var i=0;i<data.length;i++){ ?>
<tr>
<th><?= data[i][0] ?></th>
<th><?= data[i][1] ?></th>
<th><?= data[i][2] ?></th>
<th><input type = "text" style="width:40px" min="0" maxlength="3" name=a<?= i ?>>
</tr>
<? } ?>
</table>
</form> <!-- Added -->
</body>
If I misunderstand your question, I'm sorry.

Why i get no data in my table

I can see the table but there are no values in there
heres is my Plunker: http://embed.plnkr.co/RKiEZkxTCJSYpmhR69cI/
I try for hours and cant find a way to do it...
Also i set mySQL to display only 3 results of ~800.000, will this be a Problem if i remove the limit?
I want to paginate it anyway.
HTML
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://unpkg.com/ng-table#4.0.0/bundles/ng-table.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
</head>
<body ng-app="myApp" ng-controller="myController as MC">
<table ng-table="MC.tableParams" show-filter="true" class="table table-condensed table-bordered table-striped">
<tr ng-repeat="x in $data">
<td data-title="'Held'" sortable="'Held'">{{ x.Held }}</td>
<td data-title="'Waffe'" sortable="'Waffe'">{{ x.Waffe }}</td>
<td data-title="'Schild'" sortable="'Schild'">{{ x.Schild }}</td>
<td data-title="'Ring'" sortable="'Ring'">{{ x.Ring }}</td>
<td data-title="'Amulett'" sortable="'Amulett'">{{ x.Amulett }}</td>
<td data-title="'Mantel'" sortable="'Mantel'">{{ x.Mantel }}</td>
<td data-title="'ID'" sortable="'ID'">{{ x.ID }}</td>
</tr>
</table>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script>
<script src="https://unpkg.com/ng-table#4.0.0/bundles/ng-table.min.js"></script>
<script src="script.js"></script>
</body>
</html>
APP
var test = angular.module('myApp', ['ngTable']);
test.controller('myController', function myController($scope, $http, NgTableParams) {
$scope.tableParams = new NgTableParams({
page: 1, // show first page
count: 5 // count per page
}, {
getData: function($defer, params) {
$http.get('http://sanctuments.16mb.com/getData.php').
$promise.then(function(data, status) {
var orderedData = data;
$defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
})
}
})
});
Finally made it:
var test = angular.module('myApp', ['ngTable']);
test.controller('myController', function myController($scope, $http, NgTableParams) {
var self = this;
$http.get('http://sanctuments.16mb.com/getData.php').
success(function(data, status) {
self.tableParams = new NgTableParams({}, {
dataset: data
});
});
});
Or better this one:
var test = angular.module('myApp', ['ngTable']);
test.controller('myController', ['$scope', '$http', 'NgTableParams',
function myController($scope, $http, NgTableParams) {
var self = this;
$http.get('http://sanctuments.16mb.com/getData.php').success(function(data, status) {
self.tableParams = new NgTableParams({
page: 1, // show first page
count: 10 // count per page
}, {
total: data.length,
getData: function(params) {
return data.slice((params.page() - 1) * params.count(), params.page() * params.count());
}
});
});
}
]);

Dynamic form input fields in Cakephp 3

I have seen this: https://waltherlalk.com/blog/dynamic-form-input-fields and have been active in this: Dynamically add form field rows - cakePHP. I have reached the stage where the setup is as per the original tutorial with changes made as per the Stackoverflow post from monsur.hoq.
The form is working fine but, upon saving, it only saves the 'student' part of the data: nothing is sent to grades. The add part of my controller currently looks like this:
public function add()
{
$student = $this->Students->newEntity();
if ($this->request->is('post')) {
$student = $this->Students->patchEntity($student, $this->request->data);
if ($this->Students->save($student)) {
$this->Flash->success(__('The student has been saved.'));
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error(__('The student could not be saved. Please, try again.'));
}
}
$this->set(compact('student'));
$this->set('_serialize', ['student']);
}
All code is as per bake or the tutorial shaped by the monsur.hoq post.
If anyone could help me to arrive at a working Cakephp3 example of the Walther Lalk tutorial I'd be very grateful.
The debugging toolbar shows the following SQL being produced on submitting the form:
INSERT INTO students (name, created, modified)
VALUES
(
'Test Two', '2016-09-13 16:04:07',
'2016-09-13 16:04:07'
)
All that serves to do is confirm the problem. Debugging in PHP Storm on form submission reveals the following:
$_POST = {array} [3]
_method = "POST"
name = "Test Four"
Grade = {array} [1]
0 = {array} [3]
id = ""
subject = "Maths"
grade = "3"
The add.ctp is as follows:
<nav class="large-3 medium-4 columns" id="actions-sidebar">
<ul class="side-nav">
<li class="heading"><?= __('Actions') ?></li>
<li><?= $this->Html->link(__('List Students'), ['action' => 'index']) ?></li>
<li><?= $this->Html->link(__('List Grades'), ['controller' => 'Grades', 'action' => 'index']) ?></li>
<li><?= $this->Html->link(__('New Grade'), ['controller' => 'Grades', 'action' => 'add']) ?></li>
</ul>
</nav>
<div class="students form large-9 medium-8 columns content">
<?= $this->Form->create($student) ?>
<fieldset>
<legend><?= __('Add Student') ?></legend>
<?php
echo $this->Form->input('name');
?>
</fieldset>
<fieldset>
<legend><?php echo __('Grades');?></legend>
<table id="grade-table">
<thead>
<tr>
<th>Subject</th>
<th>Grade achieved</th>
<th> </th>
</tr>
</thead>
<tbody></tbody>
<tfoot>
<tr>
<td colspan="2"></td>
<td class="actions">
Add grade
</td>
</tr>
</tfoot>
</table>
</fieldset>
<script id="grade-template" type="text/x-underscore-template">
<?php echo $this->element('grades');?>
</script>
<?= $this->Form->button(__('Submit')) ?>
<?= $this->Form->end() ?>
</div>
<script>
$(document).ready(function() {
//I changed undescore default template settings
_.templateSettings = {
interpolate: /\{\{(.+?)\}\}/g
}
var
gradeTable = $('#grade-table'),
gradeBody = gradeTable.find('tbody'),
gradeTemplate = _.template($('#grade-template').remove().text()),
numberRows = gradeTable.find('tbody > tr').length;
gradeTable
.on('click', 'a.add', function(e) {
e.preventDefault();
$(gradeTemplate({key: numberRows++}))
.hide()
.appendTo(gradeBody)
.fadeIn('fast');
})
.on('click', 'a.remove', function(e) {
e.preventDefault();
$(this)
.closest('tr')
.fadeOut('fast', function() {
$(this).remove();
});
});
if (numberRows === 0) {
gradeTable.find('a.add').click();
}
});
</script>
Change from CakePHP 2 to CakePHP 3 fields name conventions,
Grade.{$key}.grade to grades.{$key}.grade
Create View/Elements/grades.ctp file with the following contents.
https://waltherlalk.com/blog/dynamic-form-input-fields
<?php
$key = isset($key) ? $key : '<%= key %>';
?>
<tr>
<td>
<?= $this->Form->hidden('grades.{$key}.id') ?>
<?= $this->Form->text('grades.{$key}.subject'); ?>
</td>
<td>
<?= $this->Form->select("grades.{$key}.grade",
[
'A+',
'A',
'B+',
'B',
'C+',
'C',
'D',
'E',
'F'
],
[
'empty' => '-- Select grade --'
]); ?>
</td>
<td class="actions">
Remove grade
</td>
</tr>

kendo sortable widget mvvm UI glitch

I am using kendo's mvvm and sortable widget to allow a user to sort multiple tables with data binded to it. I have implemented the following code. It works, but the data seems to be logging correctly to the console. However, the data in the UI jumps around.
$(".sortable-handlers").kendoSortable({
handler: ".move",
hint:function(element) {
return element.clone().addClass("sortable-hint");
},
change: function(e) {
var services = viewModel.get("services");
console.log(e.oldIndex);
var oldIndex = e.oldIndex;
var newIndex = e.newIndex;
services.splice(newIndex, 0, services.splice(oldIndex, 1)[0]);
//Set it back to the original list
viewModel.set("services", services);
console.log(JSON.stringify(viewModel.get("services")));
}
});
It's been a long time but adding .trigger("change") works for me (I'm using jquery ui sortable instead of kendo ui sortable).
// Define model with dependent method
var MyModel = kendo.data.Model.define({
fields: {
left: "number",
right: "number"
},
total: function() {
return this.get("left") + this.get("right");
}
});
// Create view model
var viewModel = kendo.observable({
items: []
});
// bindings
kendo.bind($("#myView"), viewModel);
// using $.ui.sortable when list changes
var timeout = null;
viewModel.items.bind("change", function(e) {
clearTimeout(timeout);
timeout = setTimeout(function() {
$("#sortable").sortable({
update: function(e, ui) {
// get UID of sorting target
var targetUid = ui.item.attr("uid");
// list before
var beforeIndexes = _.map(viewModel.items, _.iteratee("uid"));
// target's original index
var fromIdx = _.indexOf(beforeIndexes, targetUid);
// list after
var afterIndexes = $("#sortable").sortable("toArray", {
attribute: "uid"
});
// target's new index
var toIdx = _.indexOf(afterIndexes, targetUid);
var changeItem = viewModel.items[fromIdx];
viewModel.items.splice(fromIdx, 1);
if (toIdx >= viewModel.items.length) {
viewModel.items.push(changeItem);
} else {
viewModel.items.splice(toIdx, 0, changeItem);
}
// refresh
viewModel.items.trigger("change");
}
});
}, 500);
});
// add some items to list
viewModel.items.push(new MyModel({
left: 1,
right: 2
}));
viewModel.items.push(new MyModel({
left: 6,
right: 3
}));
viewModel.items.push(new MyModel({
left: 5,
right: 7
}));
<link href="https://code.jquery.com/ui/1.12.0-beta.1/themes/smoothness/jquery-ui.css" rel="stylesheet" />
<link href="https://kendo.cdn.telerik.com/2016.1.112/styles/kendo.common.min.css" rel="stylesheet" />
<link href="https://kendo.cdn.telerik.com/2016.1.112/styles/kendo.default.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.0-beta.1/jquery-ui.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2016.1.112/js/kendo.all.min.js"></script>
<script src="http://underscorejs.org/underscore-min.js"></script>
<div id="myView">
<div class="k-grid k-widget">
<div class="k-grid-header">
<div class="k-grid-header-wrap">
<table>
<thead>
<tr>
<th class="k-header">SORTABLE</th>
</tr>
</thead>
</table>
</div>
</div>
<div class="k-grid-content">
<table>
<tbody id="sortable" data-bind="source: items" data-template="template-item">
</tbody>
</table>
</div>
</div>
<div class="k-grid k-widget">
<div class="k-grid-header">
<div class="k-grid-header-wrap">
<table>
<thead>
<tr>
<th class="k-header">NOT-SORTABLE</th>
</tr>
</thead>
</table>
</div>
</div>
<div class="k-grid-content">
<table>
<tbody id="sortable" data-bind="source: items" data-template="template-item">
</tbody>
</table>
</div>
</div>
</div>
<script type="text/x-kendo-template" id="template-item">
<tr data-bind="attr: {uid: uid}">
<td>
<span data-bind="text: left" />+
<span data-bind="text: right" />=
<span data-bind="text: total" />
</td>
</tr>
</script>

How to add an add button in in my custom module

I have a module which is used to add banner images through admin panel. I have created the module successfully. My module edit page has two tabs. One for adding general informations of banner and second one for adding images. The general information tab is working fine now.
I need to have a button 'add banner image' in my second tab initially. When clicked on it, it should load an file type button.We can use this button for loading the image. We can use 'add banner image' in any number of times for loading the image. This is just similar to the add custom option for a product. I need that exact same functionality here.
I have searched a lot. But couldnt find how to add 'add banner image' button to my second tab. Please help me to solve this issue. Give me an idea of how can impliment this functionality. Sorry for my bad english.Thanks
I have created a similar functionality where I can add postcode ranges in my custom module using below code.
In my Module_name/Block/Adminhtml/Regions/Edit/Tab/Form.php I have added.
$fieldset->addField('postcodes', 'text', array(
'name'=>'postcodes',
'class'=>'requried-entry'
));
$form->getElement('postcodes')->setRenderer(
$this->getLayout()->createBlock('zones/adminhtml_regions_edit_tab_postcodes')
);
This will add postcodes field in my tab with renderer adminhtml_regions_edit_tab_postcodes
In my Module_name/Block/Adminhtml/Regions/Edit/Tab/Postcodes.php I have added the button with the code.
class Ripples_Zones_Block_Adminhtml_Regions_Edit_Tab_Postcodes
extends Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Price_Group_Abstract
{
public function __construct()
{
$this->setTemplate('zones/postcodes.phtml');
}
protected function _prepareLayout()
{
$button = $this->getLayout()->createBlock('adminhtml/widget_button')
->setData(array(
'label' => Mage::helper('zones')->__('Add Postcode Range'),
'onclick' => 'return addPostCodeRange.addItem()',
'class' => 'add'
));
$button->setName('add_postcode_range_button');
$this->setChild('add_button', $button);
return parent::_prepareLayout();
}
}
This will add a button on my tab with the onclick function addPostCodeRange.addItem().
After this I have added a phtml file in design/adminhtml/default/default/template/zones/postcodes.phtml
<?php $_htmlId = $this->getElement()->getHtmlId() ?>
<?php $_htmlName = 'postcodes';?>
<tr>
<td class="label">Postcode Range</td>
<td colspan="10" class="grid">
<table cellspacing="0" class="data border" id="postcodes_table">
<col width="50" />
<col width="50" />
<col width="1" />
<thead>
<tr class="headings">
<th><?php echo Mage::helper('zones')->__('From') ?></th>
<th><?php echo Mage::helper('zones')->__('To') ?></th>
<th class="last"><?php echo Mage::helper('catalog')->__('Action') ?></th>
</tr>
</thead>
<tbody id="<?php echo $_htmlId ?>_container"></tbody>
<tfoot>
<tr>
<td colspan="3" class="a-right"><?php echo $this->getAddButtonHtml() ?></td>
</tr>
</tfoot>
</table>
<script type="text/javascript">
//<![CDATA[
var tierPriceRowTemplate = '<tr>'
+ '<td><input type="text" value="{{from}}" class="custgroup required-entry" name="<?php echo $_htmlName ?>[{{index}}][from]" id="postcodes_row_{{index}}_from" />'
+ '</td>'
+ '<td><input type="text" value="{{to}}" class="custgroup required-entry" name="<?php echo $_htmlName ?>[{{index}}][to]" id="postcodes_row_{{index}}_to" />'
+ '</td>'
+ '<td class="last"><input type="hidden" name="<?php echo $_htmlName ?>[{{index}}][delete]" class="delete" value="" id="postcodes_row_{{index}}_delete" />'
+ '<button title="<?php echo Mage::helper('zones')->__("Delete Range") ?>" type="button" class="scalable delete icon-btn delete-product-option" id="postcodes_row_{{index}}_delete_button" onclick="return addPostCodeRange.deleteItem(event);">'
+ '<span><span><span><?php echo Mage::helper('zones')->__("Delete") ?></span></span></span></button></td>'
+ '</tr>';
var addPostCodeRange = {
template: new Template(tierPriceRowTemplate, new RegExp('(^|.|\\r|\\n)({{\\s*(\\w+)\\s*}})', "")),
itemsCount: 0,
addItem : function () {
var data = {
from: '',
to: '',
readOnly: false,
index: this.itemsCount++
};
if(arguments.length >= 2) {
data.from = arguments[0];
data.to = arguments[1];
}
if (arguments.length == 3) {
data.readOnly = arguments[2];
}
Element.insert($('<?php echo $_htmlId ?>_container'), {
bottom : this.template.evaluate(data)
});
$('postcodes_row_' + data.index + '_from').value = data.from;
$('postcodes_row_' + data.index + '_to').value = data.to;
if (data.readOnly == '1') {
['from', 'to', 'delete'].each(function(idx){
$('postcodes_row_'+data.index+'_'+idx).disabled = true;
});
$('postcodes_row_'+data.index+'_delete_button').hide();
}
},
disableElement: function(el) {
el.disabled = true;
el.addClassName('disabled');
},
deleteItem: function(event) {
var tr = Event.findElement(event, 'tr');
if (tr) {
Element.select(tr, '.delete').each(function(elem){elem.value='1'});
Element.hide(tr);
Element.addClassName(tr, 'no-display template');
}
return false;
}
};
<?php $collection = Mage::getModel('zones/regions')->getCollection()->addFieldToFilter('regions_id',array('eq' => $this->getRequest()->getParam('id'))); ?>
<?php foreach ($collection as $_item): ?>
<?php $postcodes = unserialize($_item['postcodes']); ?>
<?php foreach ($postcodes as $postcode): ?>
addPostCodeRange.addItem( '<?php echo $postcode['from'] ?>', '<?php echo $postcode['to'] ?>');
<?php endforeach; ?>
<?php endforeach; ?>
//]]>
</script>
</td></tr>
This file contains the function. I have added two textboxes on function call. You can add file field in this function.
Hope this helps.