ag-grid angular 5 export hidde, columns - angular5

I am working on a export feature for my ag-grid columns on angular 5
here is the code for my columns :
columnDefs = [{
headerName:'',
field:'',
pinned:true,
headerCheckboxSelection:true,
headerCheckboxSelectionFilteredOnly:true,
width:42,
checkboxSelection:true
}, {
headerName:'Actions',
field:'_id.$oid',
cellRenderer:'viewModalRenderer',
pinned:true
}, {
headerName:'Status',
field:'status'
}, {
headerName:'Category',
field:'category',
cellRenderer:'viewCetegoryRenderer',
width:120,
editable:true,
hide:true
}, {
headerName:'Created',
field:'created',
editable:true,
filter:'agDateColumnFilter'
}, {
headerName:'Price',
field:'price',
filter:'agNumberColumnFilter',
width:120,
editable:true
}];
I am calling this function to export
onBtnExport() {
let params = {}
this.gridApi.exportDataAsCsv(params);
}
How to include the Category column marked as hide: true in my export ?

Try this code:
exportCsv() {
var excelParams = {
columnKeys: ['firstName', 'middleName','lastName', 'dob'],
allColumns: false,
fileName: 'Student List.csv',
skipHeader: false,
customHeader: 'Student List' + '\n',
customFooter: '\n \n Total No.Of Students :' + this.gridOptions.api.getModel().getRowCount() + ' \n'
}
this.gridOptions.api.exportDataAsCsv(excelParams);
}
Define the columns to be displayed in columnKeys

Related

Insert Many to Many Data into Shopware 6 Database using the Administration

I have created a plugin in the adminstration and I want to insert the manyToMany products with vehicles into Shopware 6 database. From the code below I am trying to insert '92961afbc50e4380b3af86b257630ade' into the 'product_id' column of the 'vehicles_product' table :
import template from './sw-vehicles-import.html.twig';
const { Component, Mixin } = Shopware;
Component.register('sw-vehicles-import', {
template,
inject: ['importExport', 'repositoryFactory', 'feature'],
mixins: [
Mixin.getByName('notification'),
],
metaInfo() {
return {
title: this.$createTitle()
};
},
data() {
return {
importFile: null,
repository: null,
entity: undefined,
};
},
computed: {
},
created() {
this.repository = this.repositoryFactory.create('vehicles');
},
methods: {
onStartProcess() {
this.entity = this.repository.create(Shopware.Context.api);
this.entity.categoryFilter = 'CategoryName';
this.entity.featureFilter = 'FeatureName';
this.entity.products.productId = '92961afbc50e4380b3af86b257630ade';
this.repository.save(this.entity, Shopware.Context.api);
}
}
});
The build process doesn't work, what am I doing wrong? Could you help me please ?
You need to create a new entity collection for the association if it doesn't exist yet.
const { EntityCollection } = Shopware.Data;
if (!this.entity.products) {
this.entity.products = new EntityCollection(
'/product',
'product',
Shopware.Context.api
);
}
const product = await this.repositoryFactory.create('product').get('92961afbc50e4380b3af86b257630ade', Shopware.Context.api);
this.entity.products.add(product);
this.repository.save(this.entity, Shopware.Context.api);

sequelize findandcountall function return same data when using pagination

I am using sequelize: 6.9.0, sequelize-cli: ^6.3.0, express: 4.17.1, pg: 8.7.1
i have a problem when using sequelize findAndCountAll, when i using include other models it will return same data when i'm using paging.
Here is my code for House Table
index: async (req, res) => {
const { page, size, developer, city, priceone, pricetwo, project, isNew } =
req.query;
const { limit, offset } = getPagination(page, size);
try {
let filter = {};
if (developer) {
filter.developerId = developer;
}
if (city) {
filter.cityId = city;
}
if (project) {
filter.projectId = project;
}
if (isNew) {
filter.isNew = isNew;
}
if (priceone && pricetwo) {
const firstPrice = parseInt(priceone);
const secondPrice = parseInt(pricetwo);
if (firstPrice === 100000000 && secondPrice === 100000000) {
filter.price = { [Op.lte]: firstPrice };
} else if (firstPrice === 2000000000 && secondPrice === 2000000000) {
filter.price = { [Op.gte]: firstPrice };
} else {
filter.price = { [Op.between]: [firstPrice, secondPrice] };
}
}
const HousesData = await Houses.findAndCountAll({
limit,
offset,
where: filter,
attributes: [
"id",
"name",
"description",
"location",
"price",
"tanah",
"bangunan",
"lantai",
"kamar_tidur",
"kamar_mandi",
"isNew",
],
include: [
{ model: Developers, attributes: ["id", "name"] },
{ model: Cities, attributes: ["id", "name"] },
{ model: Projects, attributes: ["id", "name"] },
],
});
if (HousesData) {
const response = getPagingData(HousesData, page, limit);
res.status(200).json({
status: "success",
message: "Data Available",
data: response,
});
} else {
res.status(200).json({
status: "success",
message: "There is No Data",
data: "No Data",
});
}
} catch (error) {
console.log(error);
return next(
new HttpError(
"Something went wrong, could not get project.",
500,
error
)
);
}
}
my paging function
const getPagination = (page, size) => {
const newPage = page ? page - 1 : 0;
const limit = size ? +size : 10;
const offset = newPage != 0 ? newPage * limit : 0;
return { limit, offset };
};
const getPagingData = (data, page, limit) => {
const { count: totalItems, rows: dataRows } = data;
const currentPage = page ? +page : 1;
const totalPages = Math.ceil(totalItems / limit);
return { totalItems, totalPages, currentPage, dataRows };
};
module.exports = { getPagination, getPagingData };
Let's say i have 10 data
a,b,c,d,e,f,g,h,i,j
if i see first page
http://localhost:3006/api/v1/house?size=5&page=1
it will return a,b,c,d,e (this is right)
and if i see next page
http://localhost:3006/api/v1/house?size=5&page=2
it will return e,d,c,b,a (only reverse not showing f,g,h,i,j)
and if i see all the data it will return correct data
http://localhost:3006/api/v1/house?size=10&page=1
it will return j,i,h,g,f,e,d,c,b,a
but if i disabled
include: [
{ model: Developers, attributes: ["id", "name"] },
{ model: Cities, attributes: ["id", "name"] },
{ model: Projects, attributes: ["id", "name"] },
],
it return the right data when use paging.
my model for House is here
"use strict";
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable("Houses", {
id: {
allowNull: false,
primaryKey: true,
type: Sequelize.STRING(22),
},
name: {
type: Sequelize.STRING,
},
projectId: {
type: Sequelize.STRING(22),
onDelete: "CASCADE",
references: {
model: "Projects",
key: "id",
},
},
cityId: {
type: Sequelize.STRING(22),
onDelete: "CASCADE",
references: {
model: "Cities",
key: "id",
},
},
developerId: {
type: Sequelize.STRING(22),
onDelete: "CASCADE",
references: {
model: "Developers",
key: "id",
},
},
description: {
type: Sequelize.TEXT,
},
location: {
type: Sequelize.STRING,
},
price: {
type: Sequelize.BIGINT,
},
tanah: {
type: Sequelize.INTEGER,
},
bangunan: {
type: Sequelize.INTEGER,
},
lantai: {
type: Sequelize.INTEGER,
},
kamar_tidur: {
type: Sequelize.INTEGER,
},
kamar_mandi: {
type: Sequelize.INTEGER,
},
house_thumbnail: {
type: Sequelize.STRING,
},
isNew: {
type: Sequelize.BOOLEAN,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable("Houses");
},
};
i also use same paging method on other table. but other table works fine, only this table that got messed up.
the other table named Project function is here for reference
index: async (req, res) => {
const { page, size, developer, city, priceone, pricetwo } = req.query;
const { limit, offset } = getPagination(page, size);
try {
let filter = { haveDeveloper: true };
if (developer) {
filter.developerId = developer;
}
if (city) {
filter.cityId = city;
}
if (priceone && pricetwo) {
const firstPrice = parseInt(priceone);
const secondPrice = parseInt(pricetwo);
if (firstPrice === 100000000 && secondPrice === 100000000) {
filter.minPrice = { [Op.lte]: firstPrice };
} else if (firstPrice === 2000000000 && secondPrice === 2000000000) {
filter.minPrice = { [Op.gte]: firstPrice };
} else {
filter.minPrice = { [Op.between]: [firstPrice, secondPrice] };
}
}
const projectsData = await Projects.findAndCountAll({
limit,
offset,
where: filter,
attributes: ["id", "name", "image", "location",'minPrice'],
include: [
{ model: Cities, attributes: ["id", "name"] },
{ model: Developers, attributes: ["id", "name"] },
{ model: ProjectFacilities, attributes: ["facility"] },
],
});
if (projectsData) {
const response = getPagingData(projectsData, page, limit);
res.status(200).json({
status: "success",
message: "Data Available",
data: response,
});
} else {
res.status(200).json({
status: "success",
message: "There is No Data",
data: "No Data",
});
}
} catch (error) {
console.log(error);
return next(
new HttpError(
"Something went wrong, could not get project.",
500,
error
)
);
}
},
the Project model
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Projects extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
Projects.belongsTo(models.Developers, { foreignKey: 'developerId' })
Projects.belongsTo(models.Cities, { foreignKey: 'cityId' })
Projects.hasMany(models.ProjectFacilities, { foreignKey: 'projectId' })
Projects.hasMany(models.Houses, { foreignKey: 'projectId' })
}
};
Projects.init({
name: DataTypes.STRING,
image: DataTypes.STRING,
description: DataTypes.TEXT,
location: DataTypes.STRING,
minPrice:DataTypes.BIGINT,
haveDeveloper: DataTypes.BOOLEAN,
cityId: DataTypes.STRING,
developerId: DataTypes.INTEGER
}, {
sequelize,
modelName: 'Projects',
});
return Projects;
};
sql generated by sequelize for House page 1 with 5 data
SELECT "Houses"."id", "Houses"."name", "Houses"."description", "Houses"."location", "Houses"."price", "Houses"."tanah", "Houses"."bangunan", "Houses"."lantai", "Houses"."kamar_tidur", "Houses"."kamar_mandi", "Houses"."isNew", "Developer"."id" AS "Developer.id", "Developer"."name" AS "Developer.name", "City"."id" AS "City.id", "City"."name" AS "City.name", "Project"."id" AS "Project.id", "Project"."name" AS "Project.name" FROM "Houses" AS "Houses" LEFT OUTER JOIN "Developers" AS "Developer" ON "Houses"."developerId" = "Developer"."id" LEFT OUTER JOIN "Cities" AS "City" ON "Houses"."cityId" = "City"."id" LEFT OUTER JOIN "Projects" AS "Project" ON "Houses"."projectId" = "Project"."id" LIMIT 5 OFFSET 0;
sql generated by sequelize for Project page 1 with 5 data
SELECT "Projects".*, "City"."id" AS "City.id", "City"."name" AS "City.name", "Developer"."id" AS "Developer.id", "Developer"."name" AS "Developer.name", "ProjectFacilities"."id" AS "ProjectFacilities.id", "ProjectFacilities"."facility" AS "ProjectFacilities.facility" FROM (SELECT "Projects"."id", "Projects"."name", "Projects"."image", "Projects"."location", "Projects"."minPrice", "Projects"."cityId", "Projects"."developerId" FROM "Projects" AS "Projects" WHERE "Projects"."haveDeveloper" = true LIMIT 5 OFFSET 0) AS "Projects" LEFT OUTER JOIN "Cities" AS "City" ON "Projects"."cityId" = "City"."id" LEFT OUTER JOIN "Developers" AS "Developer" ON "Projects"."developerId" = "Developer"."id" LEFT OUTER JOIN "ProjectFacilities" AS "ProjectFacilities" ON "Projects"."id" = "ProjectFacilities"."projectId";
is there any solution for this? thank you very much for your all help and attention!
Please try thi
const getPagination = (page = 1, size = 10) => {
const offset = (page - 1) * size ;
const limit = size ;
return { limit, offset };
};

Column Visibility is not restored from a saved state via stateLoadCallback

I have added the Column Visibility button to choose to show or hide certain columns. I'm saving the state in a database, I call the stateSaveCallback function via a click on a button.
I cant find documentation about retrieving data this way, so I just link to the page and pass variables to get the data back from the database, and then load that using stateLoadCallback.
Now all this works fine, EXCEPT the column visibility is not restored. It is in the JSON data being returned though.
Here is my full code:
$(document).ready(function() {
$.extend( jQuery.fn.dataTableExt.oSort, {
"date-uk-pre": function (a){
return parseInt(moment(a, "DD/MM/YYYY").format("X"), 10);
},
"date-uk-asc": function (a, b) {
return a - b;
},
"date-uk-desc": function (a, b) {
return b - a;
}
});
var edit_date_col_num = $('th:contains("Edit Date")').index();
var entry_date_col_num = $('th:contains("Entry Date")').index();
var table = $('.mainTable').DataTable( {
pageLength: 50,
colReorder: true,
stateSave: true,
columnDefs: [
{ "type": "date-uk", targets: [ edit_date_col_num, entry_date_col_num ] }
],
dom: 'Blfrtip',
buttons: [
'copy', 'csv', 'excel', 'print',
{
extend: 'colvis',
collectionLayout: 'fixed four-column',
postfixButtons: [ 'colvisRestore' ]
}
],
<?php
$id = $this->input->get('id');
$action = $this->input->get('action');
if(isset($action) && $action == 'load' && isset($id) && $id != '') :
?>
"stateLoadCallback": function (settings) {
var o;
// Send an Ajax request to the server to get the data. Note that
// this is a synchronous request since the data is expected back from the
// function
$.ajax( {
"url": EE.BASE + "&C=addons_modules&M=show_module_cp&module=ion&method=state_save&action=load&id=<?php echo $id;?>",
"async": false,
"dataType": "json",
"success": function (response) {
response = JSON.parse(response);
o = response;
}
});
return o;
},
<?php
endif;
?>
initComplete: function (settings) {
this.api().columns().every( function () {
var column = this;
var select = $('<select><option value=""></option></select>')
.appendTo( $(column.footer()).empty() )
.on( 'change', function () {
var val = $.fn.dataTable.util.escapeRegex(
$(this).val()
);
column
.search( val ? '^'+val+'$' : '', true, false )
.draw();
} );
column.data().unique().sort().each( function ( d, j ) {
select.append( '<option value="'+d+'">'+d+'</option>' )
} );
} );
// Need to re-apply the selection to the select dropdowns
var cols = settings.aoPreSearchCols;
for (var i = 0; i < cols.length; i++)
{
var value = cols[i].sSearch;
if (value.length > 0)
{
value = value.replace("^", "").replace("$","");
console.log(value);
$("tfoot select").eq(i).val(value);
}
}
},
} );
// Save a datatables state by clicking the save button
$( ".save_state" ).click(function(e) {
e.preventDefault();
table.destroy();
$('.mainTable').DataTable( {
colReorder: true,
stateSave: true,
"stateSaveCallback": function (settings, data) {
var save_name = $('.save_name').val();
// Send an Ajax request to the server with the state object
$.ajax( {
"url": EE.BASE + "&C=addons_modules&M=show_module_cp&module=ion&method=state_save&action=save&save_name="+save_name,
"data": data,
"dataType": "json",
"type": "POST",
"success": function (response)
{
//console.log(response);
}
} );
},
});
//table.state.save();
window.location.replace(EE.BASE + "&C=addons_modules&M=show_module_cp&module=ion&method=applications");
});
$( ".clear_state" ).click(function(e) {
e.preventDefault();
table.state.clear();
window.location.replace(EE.BASE + "&C=addons_modules&M=show_module_cp&module=ion&method=applications");
});
} );
Here is the saved JSON with several visible false in the beginning (which are visible once loaded):
{"time":"1449338856556","start":"0","length":"50","order":[["0","asc"]],"search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"},"columns":[{"visible":"false","search":{"search":"","smart":"false","regex":"true","caseInsensitive":"true"}},{"visible":"false","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"false","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"false","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"false","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}}],"ColReorder":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","32","33","34","35","36","37","38","39","40","41","42","43","44","45","46","47","48","49","50","51","52","53","54","55","56","57","58","59","60","61","62","63","64","65","66","67","68","69","70"]}
Thanks
In my case datatables rejects old data according to "stateDuration" and "time" properties..
Solution: ignore state duration
"stateSave": true,
"stateDuration": -1,
Above case:
"visible":"false" may should be "visible":false
After a while of debugging this myself here's what worked for me..
This issue is that all the values in your JSON are strings and they need to be of correct datatypes for the datatables plugin.
Within the "stateSaveCallback" ajax request to save your state I did the following to the json string and then it saved all the values properly which then loaded the state as it should.
"stateSaveCallback": function (settings, data) {
var save_name = $('.save_name').val();
// Send an Ajax request to the server with the state object
$.ajax( {
"url": EE.BASE + "&C=addons_modules&M=show_module_cp&module=ion&method=state_save&action=save&save_name="+save_name,
//"data": data,
"data": JSON.stringify(data), // change to this..
"dataType": "json",
"type": "POST",
"success": function (response)
{
//console.log(response);
}
} );
},

Integrate tinyMCE 4 into extJS 4

Since tinyMCE 4 has a big change compared with the previous version, is somebody already tried to integrate extjs 4.* to the new version of the tinyMCE?
Basic integration is quite straightforward to achieve:
Ext.define('TinyMceField', {
extend: 'Ext.form.field.TextArea'
,alias: 'widget.tinymce'
/**
* TinyMCE editor configuration.
*
* #cfg {Object}
*/
,editorConfig: undefined
,afterRender: function() {
this.callParent(arguments);
var me = this,
id = this.inputEl.id;
var editor = tinymce.createEditor(id, Ext.apply({
selector: '#' + id
,resize: false
,height: this.height
,width: this.width
,menubar: false
}, this.editorConfig));
this.editor = editor;
// set initial value when the editor has been rendered
editor.on('init', function() {
editor.setContent(me.value || '');
});
// render
editor.render();
// --- Relay events to Ext
editor.on('focus', function() {
me.previousContent = editor.getContent();
me.fireEvent('focus', me);
});
editor.on('blur', function() {
me.fireEvent('blur', me);
});
editor.on('change', function(e) {
var content = editor.getContent(),
previousContent = me.previousContent;
if (content !== previousContent) {
me.previousContent = content;
me.fireEvent('change', me, content, previousContent);
}
});
}
,getRawValue: function() {
var editor = this.editor,
value = editor && editor.initialized ? editor.getContent() : Ext.value(this.rawValue, '');
this.rawValue = value;
return value;
}
,setRawValue: function(value) {
this.callParent(arguments);
var editor = this.editor;
if (editor && editor.initialized) {
editor.setContent(value);
}
return this;
}
});
Example usage (see fiddle):
Ext.widget('window', {
width: 400
,height: 350
,layout: 'form'
,items: [{
xtype: 'textfield'
,fieldLabel: 'Foo'
}, {
xtype: 'tinymce'
,id: 'tinyEditor'
,fieldLabel: 'Bar'
,value: '<p>Foo</p><p><strong>Bar</strong></p>'
,listeners: {
change: function(me, newValue, oldValue) {
console.log('content changed: ' + oldValue + ' => ' + newValue);
}
,blur: function() { console.log('editor blurred'); }
,focus: function() { console.log('editor focused'); }
}
}]
,bbar: [{
text: 'Get value'
,handler: function() {
var e = Ext.getCmp('tinyEditor');
alert(e.getValue());
}
}]
});
I've created an Ext 4.2.1 plugin for TinyMCE 4.0.20 as well as an associated Sencha Architect extension to easily plug TinyMCE into your Ext 4 apps.
Full details are explained here, along with links to GIT repository:
http://druckit.wordpress.com/2014/03/30/integrating-ext-js-4-and-the-tinymce-4-rich-text-wysiwyg-editor/

Rally Cumulative Flow Diagram with Points

I'm looking to try and do a cumulative flow diagram by story points in rally with their newer API/SDK and found some sample code on their GitHub page RallyAnalytics GitHub
So after some work I have it working to some degree but don't understand or can find any documentation for how to configure this more. It looks like the report being generated is doing count and not the PlanEstimate which I tried to add in fieldsToSum. How can I get it to sum the PlanEstimate field by c_KanbanState and not just give me a count of stories that matched the c_KanbanState for that week? Sample code below minus the minified code from GitHub.
var userConfig = {
title: 'Cumulative Flow Diagram',
debug: false,
trace: false,
// asOf: "2012-11-01", // Optional. Only supply if want a specific time frame. Do not send in new Date().toISOString().
granularity: 'week',
fieldsToSum: ['PlanEstimate'],
scopeField: "Project", // Supports Iteration, Release, Tags, Project, _ProjectHierarchy, _ItemHierarchy
scopeValue: 'scope',
scopeData: {
StartDate: new Date("2012-12-01T07:00:00.000Z"),
EndDate: new Date(new Date()),
Name: ""
},
//fieldNames: ['count', 'PlanEstimate']
kanbanStateField: 'c_KanbanState',
chartSeries: [
{name: 'To Do'},
{name: 'Dev Ready'},
{name: 'In Dev'},
{name: 'Peer Review'},
{name: 'QA Ready'},
{name: 'QA Done'},
{name: 'Accepted'}
]
}
(function() {
var charts = {};
var visualizer;
var nameToDisplayNameMap;
createVisualization = function(visualizationData) {
if (typeof visualizationData !== "undefined" && visualizationData !== null) {
categories = visualizationData.categories;
series = visualizationData.series;
charts.lowestValueInLastState = visualizationData.lowestValueInLastState;
charts.chart = new Highcharts.Chart({
chart: {
renderTo: 'chart-container',
defaultSeriesType: 'column',
zoomType: 'x'
},
legend: {
enabled: true
},
credits: {
enabled: false
},
title: {
text: userConfig.title
},
subtitle: {
text: userConfig.scopeData.Name
},
xAxis: {
categories: categories,
tickmarkPlacement: 'on',
tickInterval: Math.floor(categories.length / 12) + 1,
title: {
text: userConfig.granularity.slice(0, 1).toUpperCase() + userConfig.granularity.slice(1) + 's'
}
},
yAxis: [
{
title: {
text: 'Total Points',
},
min: charts.lowestValueInLastState
}
],
tooltip: {
formatter: function() {
point = this.point
s = point.series.name + ': <b>' + point.y + '</b><br \>';
if (point.x == point.series.data.length - 1) {
s += point.category.slice(0, point.category.length - 1) + ' to-date';
} else {
s += point.category;
}
return s;
}
},
plotOptions: {
series: {
events: {
legendItemClick: function(event) {
if (this.chart.series.length == this.index + 1) {
if (!this.visible) {
this.chart.yAxis[0].setExtremes(charts.lowestValueInLastState);
} else {
this.chart.yAxis[0].setExtremes(0);
};
};
return true;
}
}
}
},
series: series
}); // end of chart
} else {
// Put a spinner in the chart containers until first fetch returns
$('#chart-container')
.html('<img height="20px" src="https://rally1.rallydev.com/slm/js-lib/ext/2.2/resources/images/default/grid/loading.gif"></img>')
.attr("style", "text-align:center");
};
};
$(document).ready(function() {
visualizer = new CFDVisualizer(charts, userConfig, createVisualization);
});
})();
You may be using a slightly older version because the latest doesn't have the fieldsToSum parameter in the config, but you can upgrade the chart to sum PlanEstimate by chaging a few lines in the CFDVisualizer.coffee to this:
#config.lumenizeCalculatorConfig.metrics = [
{f: 'groupBySum', field: 'PlanEstimate', groupByField: #config.kanbanStateField, allowedValues: allowedValues}
]
from:
#config.lumenizeCalculatorConfig.metrics = [
{f: 'groupByCount', groupByField: #config.kanbanStateField, allowedValues: allowedValues}
]
You should probably also change the axis label in the cfd.html.
If this proves too difficult to accomplish (CoffeeScript may be unfamiliar), let me know and I'll post a new version to GitHub.