CQ, custom widget for text, link, checkbox in multifield - extjs

please see the image below, this is the component i am trying to build. a custom widget with text, link and checkbox.
so far, i can manage to get interface party showing up correctly, as you can see in the image.
but, soon as i click 'ok' it will throw me a 'Uncaught TypeError: undefined is not a function'
as showed in red underline in image...so obviously it wont be able to pass any object data into JSP layer for me to use later....
so, basically, it complaining about that 'vt' is undefined.... i dont have a clud why it is happening...
here is my code for generating the widget
/**
* #class MapLinks.CustomWidget
* #extends CQ.form.CompositeField
* This is a custom widget based on {#link CQ.form.CompositeField}.
* #constructor
* Creates a new CustomWidget.
* #param {Object} config The config object
*/
CQ.form.KeyValueLinkSelection = CQ.Ext.extend(CQ.form.CompositeField, {
/**
* #private
* #type CQ.Ext.form.TextField
*/
hiddenField: null,
/**
* #private
* #type CQ.Ext.form.Label
*/
textLabel: null,
/**
* #private
* #type CQ.Ext.form.TextField
*/
textField: null,
/**
* #private
* #type CQ.Ext.form.Label
*/
pathLabel: null,
/**
* #private
* #type CQ.form.PathField
*/
pathField: null,
/**
* #private
* #type CQ.Ext.form.Label
*/
checkboxLabel: null,
/**
* #private
* #type CQ.Ext.form.Checkbox
*/
checkbox: null,
constructor: function(config) {
config = config || { };
var defaults = {
"border": false,
"layout": "table",
"columns": 6
};
config = CQ.Util.applyDefaults(config, defaults);
CQ.form.KeyValueLinkSelection.superclass.constructor.call(this, config);
},
// overriding CQ.Ext.Component#initComponent
initComponent: function() {
CQ.form.KeyValueLinkSelection.superclass.initComponent.call(this);
this.hiddenField = new CQ.Ext.form.Hidden({
name: this.name
});
this.add(this.hiddenField);
this.textLabel = new CQ.Ext.form.Label({
cls:"keyvaluelinkselection-1",
text:"Text:",
style:"font-size: 12px; font-family: Arial, Verdana, sans-serif; vertical-align:text-bottom; padding-bottom:0px; padding-right:5px; padding-left:10px;"
});
this.add(this.textLabel);
this.textField = new CQ.Ext.form.TextField({
cls:"keyvaluelinkselection-2",
listeners: {
change: {
scope:this,
fn:this.updateHidden
}
}
});
this.add(this.textField);
this.pathLabel = new CQ.Ext.form.Label({
cls:"keyvaluelinkselection-3",
text:"Link:",
style:"font-size: 12px; font-family: Arial, Verdana, sans-serif; vertical-align:text-bottom; padding-bottom:0px; padding-right:5px; padding-left:15px;"
});
this.add(this.pathLabel);
this.pathField = new CQ.form.PathField({
cls:"keyvaluelinkselection-4",
width:"150",
listeners: {
change: {
scope:this,
fn:this.updateHidden
},
dialogselect: {
scope:this,
fn:this.updateHidden
}
}
});
this.add(this.pathField);
this.checkboxLabel = new CQ.Ext.form.Label({
cls:"keyvaluelinkselection-5",
text:"open in new tab:",
style:"font-size: 12px; font-family: Arial, Verdana, sans-serif; vertical-align:text-bottom; padding-bottom:0px; padding-right:5px; padding-left:20px;"
});
this.add(this.checkboxLabel);
this.checkbox = new CQ.Ext.form.Checkbox({
cls:"keyvaluelinkselection-6",
width:"30",
listeners: {
change: {
scope:this,
fn:this.updateHidden
},
dialogselect: {
scope:this,
fn:this.updateHidden
}
}
});
this.add(this.checkbox);
},
// overriding CQ.form.CompositeField#processPath
processPath: function(path) {
this.textField.processPath(path);
},
// overriding CQ.form.CompositeField#processRecord
processRecord: function(record, path) {
this.textField.processRecord(record, path);
},
// overriding CQ.form.CompositeField#setValue
setValue: function(value) {
var parts = value.split("}={");
this.textField.setValue(parts[0]);
this.pathField.setValue(parts[1]);
this.checkbox.setValue(parts[2]);
this.hiddenField.setValue(value);
},
// overriding CQ.form.CompositeField#getValue
getValue: function() {
return this.getRawValue();
},
// overriding CQ.form.CompositeField#getRawValue
getRawValue: function() {
return this.textField.getValue() + "}={" +
this.pathField.getValue() + "}={" +
this.checkbox.getValue();
},
// private
updateHidden: function() {
this.hiddenField.setValue(this.getValue());
}
});
// register xtype
CQ.Ext.reg('keyvaluelinkselection', CQ.form.KeyValueLinkSelection);
bascially, i was flowing the tutorial giving by adobe -> http://helpx.adobe.com/experience-manager/using/dynamically-updating-aem-custom-xtype.html
any hints will be helpful, thanks

i actually figured out myself....
basically, just override validateValue: function(value)
here is the whole code example:
CQ.form.KeyValueLinkSelection = CQ.Ext.extend(CQ.form.CompositeField, {
/**
* #private
* #type CQ.Ext.form.TextField
*/
hiddenField: null,
/**
* #private
* #type CQ.Ext.form.Label
*/
textLabel: null,
/**
* #private
* #type CQ.Ext.form.TextField
*/
textField: null,
/**
* #private
* #type CQ.Ext.form.Label
*/
pathLabel: null,
/**
* #private
* #type CQ.form.PathField
*/
pathField: null,
/**
* #private
* #type CQ.Ext.form.Label
*/
checkboxLabel: null,
/**
* #private
* #type CQ.Ext.form.Checkbox
*/
checkbox: null,
constructor: function(config) {
config = config || { };
var defaults = {
"border": false,
"layout": "table",
"columns": 6
};
config = CQ.Util.applyDefaults(config, defaults);
CQ.form.KeyValueLinkSelection.superclass.constructor.call(this, config);
},
// overriding CQ.Ext.Component#initComponent
initComponent: function() {
CQ.form.KeyValueLinkSelection.superclass.initComponent.call(this);
this.hiddenField = new CQ.Ext.form.Hidden({
name: this.name
});
this.add(this.hiddenField);
this.textLabel = new CQ.Ext.form.Label({
cls:"keyvaluelinkselection-1",
text:"Text:",
style:"font-size: 12px; font-family: Arial, Verdana, sans-serif; vertical-align:text-bottom; padding-bottom:0px; padding-right:5px; padding-left:10px;"
});
this.add(this.textLabel);
this.textField = new CQ.Ext.form.TextField({
cls:"keyvaluelinkselection-2",
allowBlank: false,
listeners: {
change: {
scope:this,
fn:this.updateHidden
}
}
});
this.add(this.textField);
this.pathLabel = new CQ.Ext.form.Label({
cls:"keyvaluelinkselection-3",
text:"Link:",
style:"font-size: 12px; font-family: Arial, Verdana, sans-serif; vertical-align:text-bottom; padding-bottom:0px; padding-right:5px; padding-left:15px;"
});
this.add(this.pathLabel);
this.pathField = new CQ.form.PathField({
cls:"keyvaluelinkselection-4",
width:"150",
allowBlank: false,
listeners: {
change: {
scope:this,
fn:this.updateHidden
},
dialogselect: {
scope:this,
fn:this.updateHidden
}
}
});
this.add(this.pathField);
this.checkboxLabel = new CQ.Ext.form.Label({
cls:"keyvaluelinkselection-5",
text:"open in new tab:",
style:"font-size: 12px; font-family: Arial, Verdana, sans-serif; vertical-align:text-bottom; padding-bottom:0px; padding-right:5px; padding-left:20px;"
});
this.add(this.checkboxLabel);
this.checkbox = new CQ.Ext.form.Checkbox({
cls:"keyvaluelinkselection-6",
width:"30",
listeners: {
change: {
scope:this,
fn:this.updateHidden
},
dialogselect: {
scope:this,
fn:this.updateHidden
}
}
});
this.add(this.checkbox);
},
validateValue: function(value) {
if(value.length < 1){ // if it's blank
if(this.allowBlank){
this.clearInvalid();
return true;
}else{
this.markInvalid(this.blankText);
return false;
}
}
if(this.vtype){
//TO DO, may need this condition checker later on
}
if(typeof this.validator == "function"){
var msg = this.validator(value);
if(msg !== true){
this.markInvalid(msg);
return false;
}
}
if(this.regex && !this.regex.test(value)){
this.markInvalid(this.regexText);
return false;
}
return true;
},
// overriding CQ.form.CompositeField#processPath
processPath: function(path) {
this.textField.processPath(path);
},
// overriding CQ.form.CompositeField#processRecord
processRecord: function(record, path) {
this.textField.processRecord(record, path);
},
// overriding CQ.form.CompositeField#setValue
setValue: function(value) {
var parts = value.split("|");
this.textField.setValue(parts[0]);
this.pathField.setValue(parts[1]);
this.checkbox.setValue(parts[2]);
this.hiddenField.setValue(value);
},
// overriding CQ.form.CompositeField#getValue
getValue: function() {
return this.getRawValue();
},
// overriding CQ.form.CompositeField#getRawValue
getRawValue: function() {
return this.textField.getValue() + "|" +
this.pathField.getValue() + "|" +
this.checkbox.getValue();
},
// private
updateHidden: function() {
this.hiddenField.setValue(this.getValue());
}
});
// register xtype
CQ.Ext.reg('keyvaluelinkselection', CQ.form.KeyValueLinkSelection);
and it 100% works....

Related

ExtJS Drag and Drop in tree on modern toolkit

Actually I'm going to implement a tree view, where the user should have the option to reorder the structure with drag and drop. Actually I can't figure out how to enable drag and drop. I found a lot of examples using the 'treeviewdragdrop' plugin, which is just working with the classic toolkit.
The following Code made me move the first node but not more.
this.toParentSource = new Ext.drag.Source({
element: this.getView().element.down('.x-gridcell'),
constrain: {
element: this.getView().body,
vertical: true
}
});
Can you help me with this problem? I'm using ExtJS 6.5.2 modern toolkit.
This is how I enabled drag and drop for trees in modern Ext JS:
First I've written a plugin which creates the sources that should be draggable.
Plugin
Ext.define('test.component.plugin.TreeDragger', {
extend: 'Ext.AbstractPlugin',
alias: 'plugin.treedrag',
mixins: ['Ext.mixin.Observable'],
constructor: function (config) {
this.mixins.observable.constructor.call(this, config);
},
init: function (component) {
var me = this;
this.source = new Ext.drag.Source({
element: component.element,
handle: '.x-gridrow',
constrain: {
element: true,
vertical: true
},
describe: function (info) {
var row = Ext.Component.from(info.eventTarget, component);
info.row = row;
info.record = row.getRecord();
},
proxy: {
type: 'placeholder',
getElement: function (info) {
console.log('proxy: getElement');
var el = Ext.getBody().createChild({
style: 'padding: 10px; width: 100px; border: 1px solid gray; color: red;',
});
el.show().update(info.record.get('description'));
return el;
}
},
// autoDestroy: false,
listeners: {
scope: me,
beforedragstart: me.makeRelayer('beforedragstart'),
dragstart: me.makeRelayer('dragstart'),
dragmove: me.makeRelayer('dragmove'),
dragend: me.makeRelayer('dragend')
}
});
},
disable: function () {
this.source.disable();
},
enable: function () {
this.source.enable();
},
doDestroy: function () {
Ext.destroy(this.source);
this.callParent();
},
makeRelayer: function (name) {
var me = this;
return function (source, info) {
return me.fireEvent(name, me, info);
};
}
});
Next I used this plugin inside my tree.
Tree
xtype: 'tree',
hideHeaders: true,
plugins: {
treedrag: {
type: 'treedrag',
listeners: {
beforedragstart: function (plugin, info) {
// logic to identify the root and prevent it from being moved
console.log('listeners: beforedragstart');
}
}
}
},
columns: [{
xtype: 'treecolumn',
flex: 1,
}
]
Then I defined the drop targets inside the controller.
Controller
afterLoadApportionmentObjectsForTree: function (succes) {
if (succes) {
tree = this.getView().down('tree');
if (tree) {
tree.expandAll();
tree.updateHideHeaders(tree.getHideHeaders());
var store = tree.getStore();
store.remoteFilter = false;
store.filterer = 'bottomup';
this.createDropTargets();
}
}
},
createDropTargets: function () {
var me = this,
rows = tree.innerItems;
Ext.each(rows, function (el) {
var target = new Ext.drag.Target({
element: el.element,
listeners: {
scope: me,
drop: me.onDrop,
beforeDrop: me.onBeforeDrop
}
});
});
},
onDrop: function (target, info, eOpts) {
var source = info.record,
row = Ext.Component.from(target.getElement(), tree),
destination = row.getRecord(),
parentNode = source.parentNode;
destination.appendChild(source);
destination.expand();
if (!parentNode.hasChildNodes()) {
parentNode.set('leaf', true);
}
},
onBeforeDrop: function (target, info, eOpts) {
var source = info.record,
row = Ext.Component.from(target.getElement(), tree),
destination = row.getRecord();
// prevent the user to drop the node on itself
// this would lead to an error caused by recursive method calls
if (source == destination) {
return false;
}
// prevent the user to drop a node on it's children
// this would lead to an error caused by recursive method calls
if (source.findChild('number', destination.get('number'), true) != null) {
return false;
}
return true;
}

How to use smartimage or smartfile in compositefield?

I would like to composite some fields (textField, URL and image). I read some tutorial about how to composite some elements with the
CQ.Ext.form.CompositeField widget.
my javascript looks like this CustomPathField.js:
/**
* #class VRBANKENPORTAL.CustomPathFieldWidget
* #extends CQ.form.CompositeField
* This is a custom path field with link text and target
* #param {Object} config the config object
*/
/**
* #class Ejst.CustomWidget
* #extends CQ.form.CompositeField
* This is a custom widget based on {#link CQ.form.CompositeField}.
* #constructor
* Creates a new CustomWidget.
* #param {Object} config The config object
*/
VRBANKENPORTAL.CustomPathFieldWidget = CQ.Ext.extend(CQ.form.CompositeField, {
/**
* #private
* #type CQ.Ext.form.TextField
*/
hiddenField: null,
/**
* #private
* #type CQ.Ext.form.TextField
*/
linkText: null,
/**
* #private
* #type CQ.form.SmartImage
*/
smartImage: null,
/**
* #private
* #type CQ.Ext.form.TextField
*/
linkURL: null,
/**
* #private
* #type CQ.Ext.form.CheckBox
*/
openInNewWindow: null,
/**
* #private
* #type CQ.Ext.form.FormPanel
*/
formPanel: null,
constructor: function (config) {
config = config || {};
var defaults = {
"border": true,
"labelWidth": 75,
"layout": "form"
//"columns":6
};
config = CQ.Util.applyDefaults(config, defaults);
VRBANKENPORTAL.CustomPathFieldWidget.superclass.constructor.call(this, config);
},
//overriding CQ.Ext.Component#initComponent
initComponent: function () {
VRBANKENPORTAL.CustomPathFieldWidget.superclass.initComponent.call(this);
// Hidden field
this.hiddenField = new CQ.Ext.form.Hidden({
name: this.name
});
this.add(this.hiddenField);
// Link text
this.add(new CQ.Ext.form.Label({
cls: "customwidget-label",
text: "Link Text"
}));
this.linkText = new CQ.Ext.form.TextField({
cls: "customwidget-1",
fieldLabel: "Link Text: ",
maxLength: 80,
maxLengthText: "A maximum of 80 characters is allowed for the Link Text.",
allowBlank: true,
listeners: {
change: {
scope: this,
fn: this.updateHidden
}
}
});
this.add(this.linkText);
// Link SmartImage
this.smartImage = new CQ.form.SmartImage({
cls: "customwidget-smartimage",
title: "Image",
allowUpload: true,
fileNameParameter: "./image/fileName",
fileReferenceParameter: "./image/fileReference",
height: 100,
mimeTypes: "*.jpg;*.jpeg;*.gif;*.png",
name: "./image/file",
fieldLabel: "Banner"
});
this.add(this.smartImage);
// Link URL
this.add(new CQ.Ext.form.Label({
cls: "customwidget-label",
text: "Überschrift"
}));
this.linkURL = new CQ.form.BrowseField({
cls: "customwidget-2",
fieldLabel: "URL: ",
allowBlank: false,
width: 225,
listeners: {
change: {
scope: this,
fn: this.updateHidden
},
dialogclose: {
scope: this,
fn: this.updateHidden
}
}
});
this.add(this.linkURL);
// Link openInNewWindow
this.openInNewWindow = new CQ.Ext.form.Checkbox({
cls: "customwidget-3",
boxLabel: "New window",
listeners: {
change: {
scope: this,
fn: this.updateHidden
},
check: {
scope: this,
fn: this.updateHidden
}
}
});
this.add(this.openInNewWindow);
},
processInit: function (path, record) {
this.linkText.processInit(path, record);
this.smartImage.processInit(path, record);
this.linkURL.processInit(path, record);
this.openInNewWindow.processInit(path, record);
},
setValue: function (value) {
var link = JSON.parse(value);
this.linkText.setValue(link.text);
this.smartImage.setValue(link.smartImage);
this.linkURL.setValue(link.url);
this.openInNewWindow.setValue(link.openInNewWindow);
this.hiddenField.setValue(value);
},
getValue: function () {
return this.getRawValue();
},
getRawValue: function () {
var link = {
"url": this.linkURL.getValue(),
"text": this.linkText.getValue(),
"smartImage": this.smartImage.getValue(),
"openInNewWindow": this.openInNewWindow.getValue()
};
return JSON.stringify(link);
},
updateHidden: function () {
this.hiddenField.setValue(this.getValue());
}
});
CQ.Ext.reg('mypathfield', VRBANKENPORTAL.CustomPathFieldWidget);
my Dialog.xml looks like this:
...
....
<items jcr:primaryType="cq:WidgetCollection">
<links
jcr:primaryType="cq:Widget"
fieldDescription="Press + to add more links"
fieldLabel="Links"
hideLabel="true"
name="./links"
width="1000"
xtype="multifield">
<fieldConfig
jcr:primaryType="cq:Widget"
xtype="mypathfield"/>
<listeners
jcr:primaryType="nt:unstructured" />
</links>
</items>
...
.....
the result dispayed in the dialog can be seen in the following screenshot.
my Question is: How to use the smartImage or smartFile in CompositeField? What did I do wrong?
I have not tried this with a smartimage widget, but I've found that the ACS Commons multifieldpanel is superior to the multifield.
Have a look:
http://adobe-consulting-services.github.io/acs-aem-commons/features/widgets.html#multi-field-panel-since-150

How to override a function of extjs in CQ/AEM?

I'm using selection Xtype and checkbox type property (CQ.form.Selection) to create a checkbox group in CQ5 (API docs at http://docs.adobe.com/docs/en/cq/5-6/widgets-api/index.html?class=CQ.form.Selection).
But I want to override setValue, getValue and validate functions of it in order to meet my requirement. How can I do that via JCR node declaration ?
many thanks and appreciate.
Not sure what you mean by "do that via JCR node declaration". But if you need to make a few additional steps with standard xtype you just need to create a custom xtype, which wraps the standard one, and use it.
Here is an example of JS-code that creates and registers new xtype (combines values of 2 different fields into a single value).
Ejst.CustomWidget = CQ.Ext.extend(CQ.form.CompositeField, {
/**
* #private
* #type CQ.Ext.form.TextField
*/
hiddenField: null,
/**
* #private
* #type CQ.Ext.form.ComboBox
*/
allowField: null,
/**
* #private
* #type CQ.Ext.form.TextField
*/
otherField: null,
constructor: function(config) {
config = config || { };
var defaults = {
"border": false,
"layout": "table",
"columns":2
};
config = CQ.Util.applyDefaults(config, defaults);
Ejst.CustomWidget.superclass.constructor.call(this, config);
},
// overriding CQ.Ext.Component#initComponent
initComponent: function() {
Ejst.CustomWidget.superclass.initComponent.call(this);
this.hiddenField = new CQ.Ext.form.Hidden({
name: this.name
});
this.add(this.hiddenField);
this.allowField = new CQ.form.Selection({
type:"select",
cls:"ejst-customwidget-1",
listeners: {
selectionchanged: {
scope:this,
fn: this.updateHidden
}
},
optionsProvider: this.optionsProvider
});
this.add(this.allowField);
this.otherField = new CQ.Ext.form.TextField({
cls:"ejst-customwidget-2",
listeners: {
change: {
scope:this,
fn:this.updateHidden
}
}
});
this.add(this.otherField);
},
// overriding CQ.form.CompositeField#processPath
processPath: function(path) {
console.log("CustomWidget#processPath", path);
this.allowField.processPath(path);
},
// overriding CQ.form.CompositeField#processRecord
processRecord: function(record, path) {
console.log("CustomWidget#processRecord", path, record);
this.allowField.processRecord(record, path);
},
// overriding CQ.form.CompositeField#setValue
setValue: function(value) {
var parts = value.split("/");
this.allowField.setValue(parts[0]);
this.otherField.setValue(parts[1]);
this.hiddenField.setValue(value);
},
// overriding CQ.form.CompositeField#getValue
getValue: function() {
return this.getRawValue();
},
// overriding CQ.form.CompositeField#getRawValue
getRawValue: function() {
if (!this.allowField) {
return null;
}
return this.allowField.getValue() + "/" +
this.otherField.getValue();
},
// private
updateHidden: function() {
this.hiddenField.setValue(this.getValue());
}
});
// register xtype
CQ.Ext.reg('ejstcustom', Ejst.CustomWidget);
Creating custom xtype in AEM6's touch UI

how to Fit row height to content in ng-grid?

Any idea how to Fit row height to content in ng-grid? See that the text is wrapped but not shown as the row has a fix height.
I saw several posts claiming there is no support for that... thought maybe someone can enlighten me...
Thanks.
Here is my code:
this.gridOptions = { data: 'tenants.elements',
selectedItems: this.mySelections,
enableColumnResize: true,
enableColumnReordering: true,
enableRowReordering: true,
showSelectionCheckbox: true,
selectWithCheckboxOnly: true,
showFooter: true,
//sortInfo: {fields: ['percent'], directions: ['desc']},
columnDefs:
[
{width: '7%', field:'apartment', displayName:'דירה'},
{width: '2%', field:'tenant_type', displayName:'-', cellTemplate: '<i ng-class="tenants.getTenantType(row.entity.tenant_type)" class="fa fa-child"></i>'},
{width: '2%', field:'defecto', displayName:'-', cellTemplate: '<i ng-show="row.entity.defecto" class="fa fa-child defecto"></i>'},
{width: '30%', field:'tenant_name', displayName:'שם דייר', cellTemplate: '{{row.entity.tenant_name}}'},
{width: '25%' ,field:'phones', displayName:'טלפונים'},
{width: '25%' ,field:'mails', displayName:'מיילים'}
],
filterOptions: this.filterOptions,
plugins: [new ngGridAutoRowHeightPlugin()]
//plugins: [new ngGridFlexibleHeightPlugin()]
}
Here is a plugin, some code taken from the ngGridFlexibleHeightPlugin
Be warned, that height will be changed on all rows by maximum height
ngGridAutoRowHeightPlugin = function () {
var self = this;
self.grid = null;
self.scope = null;
self.init = function (scope, grid, services) {
self.domUtilityService = services.DomUtilityService;
self.grid = grid;
self.scope = scope;
var recalcHeightForData = function () { setTimeout(innerRecalcForData, 1); };
var innerRecalcForData = function () {
var gridId = self.grid.gridId,
rowHeight = self.grid.config.rowHeight;
$('.' + gridId + ' .ngRow [ng-cell-text]').each(function (index, cellText) {
//+10 for default top and bottom padding of .ngCellText class
rowHeight = Math.max(rowHeight, $(cellText).outerHeight() + 10);
});
if (self.grid.config.rowHeight < rowHeight) {
self.grid.config.rowHeight = rowHeight;
//update grid's scope.rowHeight as vertical bars height depends on it
if (scope.$$phase == '$apply' || scope.$$phase == '$digest') {
updateGridScopeHeight();
} else {
scope.$apply(updateGridScopeHeight);
}
self.domUtilityService.RebuildGrid(self.scope, self.grid);
function updateGridScopeHeight() {
self.grid.$root.scope().rowHeight = rowHeight;
}
}
};
self.scope.catHashKeys = function () {
var hash = '',
idx;
for (idx in self.scope.renderedRows) {
hash += self.scope.renderedRows[idx].$$hashKey;
}
return hash;
};
self.scope.$watch('catHashKeys()', innerRecalcForData);
self.scope.$watch(self.grid.config.data, recalcHeightForData);
};
};
And also, add this style rule to your css (after ng-grid css)
.ngCellText {
white-space: normal !important;
}
Plunker here

Export google chart?

I wrote this code to create chart, table and toolbar.
google.load("visualization", "1", { packages: ["corechart"] });
google.load('visualization', '1', { packages: ['table'] });
//google.setOnLoadCallback(drawChart);
function drawChart() {
$.ajax({
type: "GET",
url: '#Url.Action("GunlukOkumalar", "Enerji")',
data: "startDate=" + $('#start_date').val() + "&endDate=" + $('#end_date').val() + "&sayac_id=" + $("#sayaclar").val(), //belirli aralıklardaki veriyi cekmek için
success: function (result) {
if (result.success) {
var evalledData = eval("(" + result.chartData + ")");
var opts = { curveType: "function", width: '100%', height: 500, pointSize: 5 };
new google.visualization.LineChart($("#chart_div").get(0)).draw(new google.visualization.DataTable(evalledData, 0.5), opts);
$('#chart_div').show();
var visualization;
var data;
var options = { 'showRowNumber': true };
data = new google.visualization.DataTable(evalledData, 0.5);
// Set paging configuration options
// Note: these options are changed by the UI controls in the example.
options['page'] = 'enable';
options['pageSize'] = 10;
options['pagingSymbols'] = { prev: 'prev', next: 'next' };
options['pagingButtonsConfiguration'] = 'auto';
// Create and draw the visualization.
visualization = new google.visualization.Table(document.getElementById('table'));
visualization.draw(data, options);
var components = [
{ type: 'html', datasource: data },
{ type: 'csv', datasource: data }
];
var container = document.getElementById('toolbar_div');
google.visualization.drawToolbar(container, components);
return false;
}
else {
$('#chart_div').html('<span style="color:red;"><b>' + result.Error + '</b></span>');
$('#chart_div').show();
$('#table').html('<span style="color:red;"><b>' + result.Error + '</b></span>');
$('#table').show();
return false;
}
}
});
}
Google example
function drawToolbar() {
var components = [
{type: 'igoogle', datasource: 'https://spreadsheets.google.com/tq?key=pCQbetd-CptHnwJEfo8tALA',
gadget: 'https://www.google.com/ig/modules/pie-chart.xml',
userprefs: {'3d': 1}},
{type: 'html', datasource: 'https://spreadsheets.google.com/tq?key=pCQbetd-CptHnwJEfo8tALA'},
{type: 'csv', datasource: 'https://spreadsheets.google.com/tq?key=pCQbetd-CptHnwJEfo8tALA'},
{type: 'htmlcode', datasource: 'https://spreadsheets.google.com/tq?key=pCQbetd-CptHnwJEfo8tALA',
gadget: 'https://www.google.com/ig/modules/pie-chart.xml',
userprefs: {'3d': 1},
style: 'width: 800px; height: 700px; border: 3px solid purple;'}
];
var container = document.getElementById('toolbar_div');
google.visualization.drawToolbar(container, components);
};
Google get dataSource from url, but I get dataSource dynamicly from controller. When I try to export It forwards page to another page like this:
http://localhost:49972/Enerji/%5Bobject%20Object%5D?tqx=out%3Acsv%3B
How can I use exporting toolbar for dynamic Json data? Is there any example about this topic?
I also had this problem and after a lot of trawling I found this!
https://developers.google.com/chart/interactive/docs/dev/implementing_data_source
I haven't implemented it yet but I reckon it's the way to go.

Resources