Not able to view more than 4 dimensions in QlikSense - qliksense
I have included Sankey JS as external plugin to Qlik sense. I have added total of 5 dimensions and 1 measure to my chart. But when I view the chart, I'm able to see only 4 dimensions and the last dimension replaces the previous dimensions. For Ex:
Dim1, Dim2, Dim3, Dim4 - It looks fine when I include only 4 dimensions.
Dim1, Dim2, Dim3, Dim5 - If I add 5th dimension to the chart.
The problem is when I view QDataPages[0] size object, I'm able to see only values for 4 dimensions under the qMatrix object. How do I crease the size or see more dimensions. Your help is really appreciated.
requirejs.config({
shim : {
"extensions/SenseSankey/sankeymore" : {
"deps" : ["extensions/SenseSankey/d3.min"]
}
}
});
//define(["jquery", "text!./style.css","extensions/SenseSankey/sankeymore"], function($, cssContent) {
define(["jquery", "text!./style.css","core.utils/theme","extensions/SenseSankey/md5.min","extensions/SenseSankey/sankeymore"], function($, cssContent, Theme, md5) {
'use strict';
$( "<style>" ).html( cssContent ).appendTo( "head" );
return {
initialProperties: {
version: 1.3,
qHyperCubeDef: {
qDimensions: [],
qMeasures: [],
qInitialDataFetch: [{
qWidth: 5,
qHeight: 2000
}]
},
selectionMode: "QUICK"
},
definition: {
type: "items",
component: "accordion",
items: {
dimensions: {
uses: "dimensions",
min: 2,
max: 7
},
measures: {
uses: "measures",
min: 1,
max: 1
},
//sorting: {
// uses: "sorting"
//},
settings: {
uses: "settings",
type: "items",
items : {
SankeyGroup:{
label : "Sankey Settings",
type:"items",
items : {
flowMax:{
type: "integer",
label: "Flow max (10 to 2000)",
ref: "flowMax (max is 2000)",
defaultValue: 500,
min : 10,
max : 2000
},
flowChoice:{
ref:"flowChoice",
type:"integer",
component:"dropdown",
label:"Color Flow",
options:
[
{
value:1,
label:"Qlik Color"
},
{
value:2,
label:"Custom Color"
}
],
defaultValue: 1
},
flowColor:{
type: "string",
component: "color-picker",
//component: "ColorsPickerComponent",
expression: "optional",
label: "Color Flow if no Hex Color",
ref: "flowColor",
defaultValue: 2,
show: function(layout) { return layout.flowChoice == 1 }
},
flowColorCustom:{
type: "string",
label: "Custom Hex Color for Flow",
ref: "flowColorCustom",
defaultValue: "#999999",
show: function(layout) { return layout.flowChoice == 2 }
},
Separateur:{
ref: "displaySeparateur",
type: "string",
component: "dropdown",
label: "Pop-up Separator",
options:
[
{
value:" - ",
label:"-"
},
{
value:" <-> ",
label:"<->"
},
{
value: " → ",
label: " → "
},
],
defaultValue: " - "
},
Format:{
ref: "displayFormat",
type: "string",
component: "dropdown",
label: "Pop-up Format",
options:
[
{
value: "Number2",
label: "1000.12"
},
{
value: "Number1",
label: "1000.1"
},
{
value: "Number",
label: "1000"
},
{
value: "Money2",
label: "1000.12 €"
},
{
value: "Money1",
label: "1000.1 €"
},
{
value: "Money",
label: "1000 €"
},
],
defaultValue: "Number"
},
Palette:{
ref:"displayPalette",
type:"string",
component: "dropdown",
label : "Palette",
options:
[
{
value: "D3-20",
label: "Ordinal Palette 20 colors"
},
{
value: "D3-20c",
label: "Blue-Grey Palette 20 colors"
},
{
value: "D3-20b",
label: "Blue-Purple Palette 20 colors"
},
{
value: "20",
label: "Palette 20 colors"
},
{
value: "20a",
label: "Other Palette 20 colors"
},
{
value: "20b",
label: "Spectral 14 color Palette" // Added by Anand.V.N for Spectral Color Palette
},
],
defaultValue: "D3-20"
},
colorPersistence:{
ref: "colorPersistence",
component: "switch",
type: "boolean",
translation: "Persistence",
defaultValue: false,
trueOption: {
value: true,
translation: "properties.on"
},
falseOption: {
value: false,
translation: "properties.off"
},
show: true
}
}
}
}
}
}
},
snapshot: {
canTakeSnapshot: true
},
paint: function ( $element, layout ) {
// Fonction format pop-up
function formatMoney(n, c, d, t, m, l){
var c = isNaN(c = Math.abs(c)) ? 2 : c,
d = d == undefined ? "." : d,
t = t == undefined ? "," : t,
s = n < 0 ? "-" : "",
i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "",
j = (j = i.length) > 3 ? j % 3 : 0;
return l + ' \n ' + s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "")+ m;
};
// Persistent color function
var hashScale = d3.scale.linear().domain([1, 4294967295]).range([ 0, 19.9999 ]);
function hashL(str) {
var hashL = 5381,
i = str.length
while(i)
hashL = (hashL * 33) ^ str.charCodeAt(--i)
//hash = md5(str)
return hashL >>> 0;
}
function getColorForNode(strValue) {
if (colorPersistence===true) {
return colours[parseInt(Math.floor(hashScale(hashL(md5(strValue)))))];
} else
{
return colours[Math.floor(Math.random() * (19))];
}
}
var _this = this;
var maxHeight = layout.flowMax;
var displayFormat = layout.displayFormat;
var displaySeparateur = layout.displaySeparateur;
var displayPalette = layout.displayPalette;
var colorPersistence = layout.colorPersistence;
if (displayPalette === "D3-20") {
var colours = ['#1f77b4','#aec7e8','#ff7f0e','#ffbb78','#2ca02c','#98df8a','#d62728','#ff9896','#9467bd','#c5b0d5','#8c564b',
'#c49c94','#e377c2','#f7b6d2','#7f7f7f','#c7c7c7','#bcbd22','#dbdb8d','#17becf','#9edae5' ];
}
else if (displayPalette === "D3-20b") {
var colours = ['#393b79','#5254a3','#6b6ecf','#9c9ede','#637939','#8ca252','#b5cf6b','#cedb9c','#8c6d31','#bd9e39',
'#e7ba52','#e7cb94','#843c39','#ad494a','#d6616b','#e7969c','#7b4173','#a55194','#ce6dbd','#de9ed6'];
}
else if (displayPalette === "D3-20c") {
var colours = ['#3182bd','#6baed6', '#9ecae1','#c6dbef','#e6550d','#fd8d3c','#fdae6b','#fdd0a2','#31a354',
'#74c476','#a1d99b','#c7e9c0','#756bb1','#9e9ac8','#bcbddc','#dadaeb','#636363','#969696','#bdbdbd','#d9d9d9' ];
}
else if (displayPalette === "20") {
var colours = [ '#1abc9c','#7f8c8d','#2ecc71','#bdc3c7','#3498db','#c0392b','#9b59b6','#d35400','#34495e','#f39c12',
'#16a085','#95a5a6','#27ae60','#ecf0f1','#2980b9','#e74c3c','#8e44ad','#e67e22','#2c3e50','#f1c40f' ];
}
else if (displayPalette === "20a") {
var colours = [ '#023FA5','#7D87B9','#BEC1D4','#D6BCC0','#BB7784','#FFFFFF','#4A6FE3','#8595E1','#B5BBE3','#E6AFB9',
'#E07B91','#D33F6A','#11C638','#8DD593','#C6DEC7','#EAD3C6','#F0B98D','#EF9708','#0FCFC0','#9CDED6'];
}
else if (displayPalette === "20b") { // Added by Anand.V.N for Spectral Color Palette
var colours = [ '#F46D43','#E78162','#FDAE61','#F0B880','#FEE08B','#F1CA5F','#E6F598','#D4E86D','#ABDDA4','#85D07B',
'#66C2A5','#44B591','#3288BD','#5E4FA2','#D9D9D9','#BFBFBF','#A6A6A6','#7F7F7F','#595959','#9CDED6'];
}
var flowColor = (layout.flowChoice == 2) ? layout.flowColorCustom : Theme.palette[layout.flowColor];
var qData = layout.qHyperCube.qDataPages[0];
// create a new array that contains the dimension labels
var qDim = layout.qHyperCube.qDimensionInfo.map(function(d) {
return d.qFallbackTitle;
});
console.log(layout.qHyperCube);
var divName = layout.qInfo.qId;
var qMatrix = qData.qMatrix.sort();
var source = qMatrix.map(function(d) {
var path = "";
var sep = "";
for (var i = 0; i < d.length - 1; i++) {
path += sep + (d[i].qText.replace('|', ' ')) + '|' + (d[i].qElemNumber);
sep = ",";
}
return {
//"Path":d[0].qText,
"Path": path,
"Frequency": d[d.length - 1].qNum
}
});
var id = "sk_"+ layout.qInfo.qId;
if (document.getElementById(id)) {
$("#" + id).empty();
}
else {
$element.append($('<div />').attr("id", id));
}
$("#" + id).width($element.width()).height($element.height());
var sLinks = [];
var endArr = [];
var catArray = [];
//********Creates Duplicate IDs*************
// $element.attr("id",id)
//******************************************
//var td = _this.Data;
var sNodes = [];
var jNodes = [];
var rev = 0; //permet de pivoter les dimensions
source=source.slice(0,maxHeight);
//source foreach
source.forEach(function(d) {
//var row = d;
var path = d.Path;
var val = parseFloat(d.Frequency);
if(val > 0) {
var tArr = path.split(",",4);
//tArr.sort();
if (rev == "1") {
tArr.reverse();
}
if (tArr.length > 1) {
$.each(tArr, function(i) {
if(tArr.length === (i + 1)){
tArr[i] = this.toString().trim() + "~end";
}else{
tArr[i] = this.toString().trim() + "~" + i;
}
});
$.each(tArr, function(i) {
if ($.inArray(this.toString().trim(), sNodes) === -1) {
sNodes.push(this.toString().trim());
}
});
}
}
});
sNodes.forEach(function(d) {
jNodes.push({
name: d.toString()
})
});
//source foreach
source.forEach(function(d) {
//var row = d;
var path = d.Path
var val = parseFloat(d.Frequency);
if(val > 0) {
var tArr = path.split(",");
if (rev == "1") {
tArr.reverse();
}
if (tArr.length > 1) {
$.each(tArr, function(i) {
if(tArr.length === (i + 1)){
tArr[i] = this.toString().trim() + "~end";
}else{
tArr[i] = this.toString().trim() + "~" + i;
}
});
$.each(tArr, function(i) {
var tFlag = "no";
if ((i + 1) != tArr.length) {
var cS = $.inArray(this.toString().trim(), sNodes);
var cT = $.inArray(tArr[i + 1].toString().trim(), sNodes);
$.each(sLinks, function(i, v) {
if ((v.source === cS) && (v.target === cT)) {
tFlag = "yes";
v.value = v.value + val;
}
});
if (tFlag == "no") {
sLinks.push({
"source" : cS,
"target" : cT,
"value" : val
});
}
}
});
}
}
});
var margin = {
top : 1,
right : 1,
bottom : 0,
left : 1
}, width = $element.width(), height = $element.height();
// Added svgHeader class for Scrollbars by Anand.V.N
var svg = d3.select("#sk_" + divName).attr("class","svgHeader").append("svg").attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom).append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var sankey = d3.sankey().nodeWidth(15).nodePadding(10).size([width -10 , height-10]);
var path = sankey.link();
sankey.nodes(jNodes).links(sLinks).layout(32);
var link = svg.append("g").selectAll(".link").data(sLinks).enter().append("path").attr("class", "link").attr("d", path).style("stroke-width",function(d) {
return Math.max(1, d.dy);
}).sort(function(a, b) {
return b.dy - a.dy;
});
//Color of Flow
link.style('stroke', flowColor);
// affiche la valeur sur le flux en popup
link.append("title").text(function(d) {
//Je supprime les tildes et les pipes
var start = d.source.name.split('|')[0];
//var start = d.source.name.substr(0, d.source.name.length - 2).split('|')[0];
var end = d.target.name.split('|')[0];
if (displayFormat === "Number"){
return formatMoney(d.value, 0, '.', ' ','' , start + displaySeparateur + end);
}
if (displayFormat === "Number1"){
return formatMoney(d.value, 1, '.', ' ','' , start + displaySeparateur + end);
}
if (displayFormat === "Number2"){
return formatMoney(d.value, 2, '.', ' ','' , start + displaySeparateur + end);
}
if (displayFormat === "Money"){
return formatMoney(d.value, 0, '.', ' ',' €' , start + displaySeparateur + end);
}
if (displayFormat === "Money1"){
return formatMoney(d.value, 1, '.', ' ',' €' , start + displaySeparateur + end);
}
if (displayFormat === "Money2"){
return formatMoney(d.value, 2, '.', ' ',' €' , start + displaySeparateur + end);
}
});
var node = svg
.append("g").selectAll(".node").data(jNodes).enter().append("g").attr("class", "node").attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
})
node.on("click",function(d, i) {
//on passe a la fonction l'identifiant qElement precedemment stocké dans le nom et le nom de la dimension sous forme d'un tableau
_this.backendApi.selectValues(
parseInt(d.name.split('~')[1].replace('end', qDim.length - 1)),
[ parseInt(d.name.split('~')[0].split('|')[1]) ],
true
);
})
// Start of Node and Path/Link Color. Declared variables for the arrays to store unique colors for specific nodes Added by Anand.V.N
var nodeLinkColor='';
var nodeName='';
var colorArray= new Array();
var objColor={};
var tempArr=new Array();
// End of Node and Path/Link Color Added by Anand.V.N
// AVEC POPUP sur le carré de couleur
node.append("rect").attr("height", function(d) {
return d.dy;
}).attr("width", sankey.nodeWidth()).style("fill", function(d) {
// Implemented Logic for the arrays to store unique colors for specific nodes Added by Anand.V.N
nodeName= d.name.split('|')[0];
if (!tempArr.contains(nodeName)) {
d.color = getColorForNode(d.name);
nodeLinkColor=d.color;
objColor[nodeName]=nodeLinkColor
colorArray.push(objColor);
}
else
{
colorArray.forEach(function(i){
d.color=i[nodeName];
});
}
tempArr.push(nodeName);
// End of Node and Path/Link Color Added by Anand.V.N
return d.color;
}).style("stroke", function(d) {
return d3.rgb(d.color).darker(2);
}).append("title").text(function(d) {
var level = d.name.substr(d.name.indexOf("~")+1,1);
if (level === "e" ){level = qDim.length -1;}
var entete = qDim[level] + ' : ' + d.name.split('|')[0];
if (displayFormat === "Number"){
return formatMoney(d.value, 0, '.', ' ','', entete);
}
if (displayFormat === "Number1"){
return formatMoney(d.value, 1, '.', ' ','',entete);
}
if (displayFormat === "Number2"){
return formatMoney(d.value, 2, '.', ' ','',entete);
}
if (displayFormat === "Money"){
return formatMoney(d.value, 0, '.', ' ',' €',entete);
}
if (displayFormat === "Money1"){
return formatMoney(d.value, 1, '.', ' ',' €',entete);
}
if (displayFormat === "Money2"){
return formatMoney(d.value, 2, '.', ' ',' €',entete);
}
});
var link = svg.append("g").selectAll(".link").data(sLinks).enter().append("path").attr("class", "link").attr("d", path).style("stroke-width",function(d) {
return Math.max(1, d.dy);
}).sort(function(a, b) {
return b.dy - a.dy;
});
link.style('stroke', function(d) {
// Implemented Logic to compare node arrays for specific colors and assign to the link/path. Added by Anand.V.N
var start = d.source.name.split('|')[0];
var end = d.target.name.split('|')[0];
colorArray.forEach(function(i){
// console.log(i);
if(colorArray.indexOf(start)==-1)
d.color=i[start];
});
// End of Node and Path/Link Color Added by Anand.V.N
return d.color;
});
link.append("title").text(function(d) {
var start = d.source.name.split('|')[0];
//var start = d.source.name.substr(0, d.source.name.length - 2).split('|')[0];
var end = d.target.name.split('|')[0];
if (displayFormat === "Number"){
return formatMoney(d.value, 0, '.', ' ','' , start + displaySeparateur + end);
}
if (displayFormat === "Number1"){
return formatMoney(d.value, 1, '.', ' ','' , start + displaySeparateur + end);
}
if (displayFormat === "Number2"){
return formatMoney(d.value, 2, '.', ' ','' , start + displaySeparateur + end);
}
if (displayFormat === "Money"){
return formatMoney(d.value, 0, '.', ' ',' €' , start + displaySeparateur + end);
}
if (displayFormat === "Money1"){
return formatMoney(d.value, 1, '.', ' ',' €' , start + displaySeparateur + end);
}
if (displayFormat === "Money2"){
return formatMoney(d.value, 2, '.', ' ',' €' , start + displaySeparateur + end);
}
});
// Changes the 'x' attribute size for the <text> to include text within <rect> nodes. Also have updated <text> tag by appending it next to <rect> tag. Added by Anand.V.N
node.append("text").attr("class", "nodeTitle").attr("x", 5).attr("y", function(d) {
return d.dy / 2;
}).attr("dy", ".35em").attr("text-anchor", "middle").attr("alignment-baseline", "middle").attr("transform", null).text(function(d) {
var str = d.name.substring(0, d.name.indexOf("~")).split('|')[0];
return str
}).filter(function(d) {
return d.x < width / 2;
}).attr("text-anchor", "start");
// End of <text> tag. Added by Anand.V.N
/*
function dragmove(d) {
d3.select(this).attr("transform", "translate(" + d.x + "," + (d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))) + ")");
sankey.relayout();
link.attr("d", path);
}
*/
}
};
} );
Regards,
Just an assumption: Did you change this code from qWidth=4 to qWidth=5?
qInitialDataFetch: [{
qWidth: 5,
qHeight: 2000
}
If this is the case, then remove the extension from your sheet, refresh the browser and re-add the extension again!
I think you just have to recreate the app, qwidth and max/min dimensions has been set correctly.
Just recreate the app or re-add the extension.
I faced the same problem, after recreating the app, the problem has been solved.
Related
While horizontal scrolling the datalabels of charjs is overlapping to y-axis
To show all bars I have set the horizontal scrolling to chartjs in Ionic angular project , and i have used the DataLabelsPlugin constant for bars label. and while scrolling the datalabels is overlapping with y-axis its not hiding before y-axis like bars. and also horizontal scroll is not happening smoothly. graph working fine as a expected output marked with issue about - after scrolling the datalabels went over the y-axis not hide below y-axis like bars I have tried to add and used the custom datalabels but same issue i am getting and i didnt find any css or attribute on 'https://www.chartjs.org/docs/latest/' official site or not on any other sites -> to hide the datalabels from over the y-axis. ts file code: createBarChart() { const footer = (tooltipItems) => { let sum = 0; tooltipItems.forEach(function(tooltipItem) { sum += tooltipItem.parsed.y; }); return this.util.getFormatValue(sum)+'%'; }; const toolLabel = (tooltipItems) => { return ""; }; const toolTitle = (tooltipItems) => { var string_to_array = function (str) { return str.trim().split("#$#$"); }; var ss; tooltipItems.forEach(function(tooltipItem) { ss = string_to_array(tooltipItem.label.replace(/(.{40})/g, "$1#$#$")) }); return ss; }; let graphSize = Math.max(...this.daywise_occupancy); if(graphSize == 0){ graphSize =1; } const plugin = { id: 'customCanvasBackgroundColor', beforeDraw: (chart, args, options) => { const {ctx} = chart; ctx.save(); ctx.globalCompositeOperation = 'destination-over'; ctx.fillStyle = '#ffffff'; ctx.fillRect(0, 0, chart.width, chart.height); ctx.restore(); } }; this.bars = new Chart(this.barchart6.nativeElement, { type: 'bar', data: { labels: this.daywise_date, datasets: [{ data: this.daywise_occupancy, backgroundColor: function(context) { var value = context.dataset.data[context.dataIndex]; return value <= 15 ? '#f95959' : value > 15 && value <=60 ? '#F5A623' : '#00ADB5' }, borderColor: function(context) { var value = context.dataset.data[context.dataIndex]; return value <= 15 ? '#f95959' : value > 15 && value <=60 ? '#F5A623' : '#00ADB5' }, borderWidth: 1, barThickness:30, }] }, plugins: [DataLabelsPlugin,plugin], options: { animations: { tension: { duration: 1000, easing: 'linear', from: 1, to: 0, loop: true } }, scales: { x: { min:0, max:5, ticks : { maxRotation: 70, minRotation: 70, font:{ size:10, }, callback: function(value : any, index, ticks_array) { let characterLimit = 12; let label = this.getLabelForValue(value); if ( label.length >= characterLimit) { return label.slice(0, label.length).substring(0, characterLimit -1).trim() + '..'; } return label; } } }, y: { // defining min and max so hiding the dataset does not change scale range min: 0, max: this.loader.getGraphsizeRound(graphSize), title: { display: true, text: (this.titleSet)? '% of Branches Contribution' : '% of Seat Occupancy' }, beginAtZero: true, display: true, position: 'left', // ticks: { // stepSize: 6, // }, } }, plugins: { legend: { display: false }, datalabels:{ anchor: 'end', align: 'end',labels: { value: { color: '#2C3A45;', formatter: function (value) { // return Math.round(value) + '%'; return value + '%'; }, font:{ weight:700, size:14 } } } }, tooltip: { callbacks: { footer:footer, label: toolLabel, title:toolTitle }, displayColors:false } } } }); this.bars.canvas.addEventListener('touchmove',(eve) => { this.touchmove(eve,this.bars) }); this.bars.canvas.addEventListener('touchstart',(eve) => { this.touchstart(eve) }); } touchstart(e) { this.startX = e.touches[0].clientX; this.startY = e.touches[0].clientY; } touchmove(e,chart) { var deltaX = e.touches[0].clientX - this.startX, deltaY = e.touches[0].clientY - this.startY; const dataLength = chart.data.labels.length; let min = chart.options.scales.x.min; if(deltaX < 0){ if( chart.options.scales.x.max >= dataLength ){ chart.options.scales.x.min = dataLength - 5; chart.options.scales.x.max = dataLength; }else{ chart.options.scales.x.min += 1; chart.options.scales.x.max += 1; } // console.log( chart.options.scales.x.min); // chart1line.options.scales.y.max = graphSize }else if(deltaX > 0){ if( chart.options.scales.x.min <= 0 ){ chart.options.scales.x.min = 0; chart.options.scales.x.max = 4; }else{ chart.options.scales.x.min -= 1; chart.options.scales.x.max -= 1; } }else{ } chart.update(); } HTML code: <div class="chartWrapper"> <div class="chartAreaWrapper"> <canvas #barchart6 height="190" max-height="190" width="0"></canvas> </div> </div> My expected output horizontal scroll work smoothly. after scrolling label should not overlap on y-axis.
Custom GL Lines Plug-in creates error on paid in full invoices
I created a script that re-books certain transactions depending on the account they were booked to. The script is running fine on all invoices and creating the expected outcome except when an invoice has the status "paid in full". The error states Cannot use 0 as input to setDebitAmount(). Amount to debit must be positive. Already tried the script on the same invoice with different statuses - same outcome. Why does the invoice status make a difference here? /** * Custom GL lines Plug-In Implementation for rebooking Invoices (articles and discounts) * Configuration of Plug-In Implementation: * Transaction Type: Invoice * Subsidiaries: MTE * #param {*} transactionRecord * #param {*} standardLines * #param {*} customLines */ function customizeGlImpact( transactionRecord, standardLines, customLines ) { function sign(x) { // If x is NaN, the result is NaN. // If x is -0, the result is -0. // If x is +0, the result is +0. // If x is negative and not -0, the result is -1. // If x is positive and not +0, the result is +1. return ((x > 0) - (x < 0)) || +x; } if (standardLines.getCount() > 0) { var tranid = transactionRecord.getFieldValue("tranid"); var customername = transactionRecord.getFieldValue("entityname"); for (var i = 0; i < standardLines.getCount(); i++) { // get information for GL standard line var currLineStandard = standardLines.getLine(i); var taxCodeId = currLineStandard.getTaxItemId(); var accountID = currLineStandard.getAccountId(); nlapiLogExecution("debug", "Line: " + i, JSON.stringify({ "taxCodeId": taxCodeId, "accountID": accountID })); if (taxCodeId === null || accountID === null) {// specific lines don't have accountID continue; } var correctAccountId = targetAccountSearch(accountID, taxCodeId); nlapiLogExecution("debug", "Line: " + i, JSON.stringify({ "correctAccountId": correctAccountId })); if (correctAccountId === -1) { continue; } if (correctAccountId !== accountID) { var salestaxitem = nlapiLoadRecord("salestaxitem", taxCodeId); var newLine = customLines.addNewLine(); if (currLineStandard.creditAmount === "0") { if (sign(currLineStandard.debitAmount) === 1) { newLine.setCreditAmount(currLineStandard.debitAmount); } else { newLine.setDebitAmount(currLineStandard.debitAmount); } } else { if (sign(currLineStandard.creditAmount) === 1) { newLine.setDebitAmount(currLineStandard.creditAmount); } else { newLine.setCreditAmount(currLineStandard.creditAmount); } } newLine.setAccountId(accountID); newLine.setLocationId(currLineStandard.getLocationId()); newLine.setDepartmentId(currLineStandard.getDepartmentId()); newLine.setClassId(currLineStandard.getClassId()); newLine.setEntityId(currLineStandard.getEntityId()); newLine.setMemo(( "Umbuchung " + salestaxitem.getFieldValue("itemid") + " - " + tranid + " - " + customername + (currLineStandard.getMemo() !== null ? " - " + currLineStandard.getMemo() : "")).substring(0, 100) ); var newLine = customLines.addNewLine(); if (currLineStandard.creditAmount === "0") { if (sign(currLineStandard.debitAmount) === 1) { newLine.setDebitAmount(currLineStandard.debitAmount); } else { newLine.setCreditAmount(currLineStandard.debitAmount); } } else { if (sign(currLineStandard.creditAmount) === 1) { newLine.setCreditAmount(currLineStandard.creditAmount); } else { newLine.setDebitAmount(currLineStandard.creditAmount); } } newLine.setAccountId(correctAccountId); newLine.setLocationId(currLineStandard.getLocationId()); newLine.setDepartmentId(currLineStandard.getDepartmentId()); newLine.setClassId(currLineStandard.getClassId()); newLine.setEntityId(currLineStandard.getEntityId()); newLine.setMemo(( "Umbuchung " + salestaxitem.getFieldValue("itemid") + " - " + tranid + " - " + customername + (currLineStandard.getMemo() !== null ? " - " + currLineStandard.getMemo() : "")).substring(0, 100) ); } } } } /** * * #param {*} custrecord_pg_source_account * #param {*} custrecord_pg_lookup_tax_code * #returns */ function targetAccountSearch( custrecord_pg_source_account, custrecord_pg_lookup_tax_code ) { // saved search for mapping var accountRebookingSearch = nlapiCreateSearch( "customrecord_pg_account_rebooking", [ nlobjSearchFilter( "custrecord_pg_source_account", null, "is", custrecord_pg_source_account ), nlobjSearchFilter( "custrecord_pg_lookup_tax_code", null, "is", custrecord_pg_lookup_tax_code ), nlobjSearchFilter( "isinactive", null, "is", "F" ) ], [ new nlobjSearchColumn('custrecord_pg_source_account'), new nlobjSearchColumn('custrecord_pg_lookup_tax_code'), new nlobjSearchColumn('custrecord_pg_target_account') ] ); // run search var accountRebookingSearchResults = accountRebookingSearch .runSearch() .getResults(0, 2); accountRebookingSearchResults = JSON.parse( JSON.stringify(accountRebookingSearchResults) ); nlapiLogExecution("debug", "accountRebookingSearchResults", JSON.stringify({ "accountRebookingSearchResults": accountRebookingSearchResults })); if (accountRebookingSearchResults.length === 0) { return -1; // no mapping found } if (accountRebookingSearchResults.length > 1) { throw "more than one mapping found"; } var accountRebookingSearchResult = accountRebookingSearchResults[0]; return parseInt(accountRebookingSearchResult.columns.custrecord_pg_target_account.internalid); }
Apparently, the standardlines contains datalines with credit amoung && debit amount == 0. Why that is, I don't know - maybe someone knows and leaves a comment about that. So all I needed was a check for both values.
ag-grid continues to show the loading icon when no data returned from the server
I'm facing a strange behavior in Ag-grid (Angular). When I use the serverSide option and when there is no data returned from the server, the grid is showing the loading icon for all the rows mentioned in the cacheBlockSize. I've tried as many options I could to hide these empty loading rows, but nothing has worked out. I've tried to replicate the same in the official example page. Luckily I could replicate the similar behavior. Refer to this edited version of an official example page, where I'm passing an empty array from the fake server call: https://plnkr.co/edit/Egw9ToJmNE7Hl6Z6 onGridReady(params) { this.gridApi = params.api; this.gridColumnApi = params.columnApi; this.http .get('https://www.ag-grid.com/example-assets/olympic-winners.json') .subscribe((data) => { let idSequence = 0; data.forEach((item) => { item.id = idSequence++; }); const server = new FakeServer(data); const datasource = new ServerSideDatasource(server); params.api.setServerSideDatasource(datasource); }); } } function ServerSideDatasource(server) { return { getRows: (params) => { setTimeout(() => { const response = server.getResponse(params.request); if (response.success) { params.successCallback(response.rows, response.lastRow); } else { params.failCallback(); } }, 2000); }, }; } function FakeServer(allData) { return { getResponse: (request) => { console.log( 'asking for rows: ' + request.startRow + ' to ' + request.endRow ); const rowsThisPage = allData.slice(request.startRow, request.endRow); const lastRow = allData.length <= request.endRow ? data.length : -1; return { success: true, rows: [], lastRow: lastRow, }; }, }; } The screenshot of the plunker output is given below.
Just figured out that its a problem with lastRow value. If the rows are empty but lastRow is not -1, then its trying to load the data and showing the loading icon for all the rows as per the cacheBlockSize. Fixed code below: function FakeServer(allData) { return { getResponse: (request) => { console.log( 'asking for rows: ' + request.startRow + ' to ' + request.endRow ); let data = []; //allData; const rowsThisPage = data.slice(request.startRow, request.endRow); const lastRow = data.length <= request.endRow ? data.length : -1; return { success: true, rows: rowsThisPage, lastRow: lastRow, }; }, }; }
Update for AG Grid 28: function FakeServer(allData) { return { getResponse: (params) => { const request = params.request; console.log( 'asking for rows: ' + request.startRow + ' to ' + request.endRow ); let data = []; //allData; const rowsThisPage = data.slice(request.startRow, request.endRow); const lastRow = data.length <= request.endRow ? data.length : -1; params.success({ rowData: rowsThisPage, rowCount: lastRow }); }, }; }
ckeditor editiable widget content
I created a plugin and widget, the content is generated dynamically in a dialog, when the dialog is closed, the content is inserted into the CKEditor window, but the content itself cannot be edited. How can I make it that the widget content can be edited from the main CKEditor input after it has been created via the dialog? Plugin Code (function() { CKEDITOR.plugins.add( 'cc_widget', { icons: "cc_widget_button", init: function(editor) { // Styles editor.addContentsCss( this.path + 'cc-widget.css' + '?' + new Date()); var str_html = "<div class=\"credit-card credit-card-widget\" data-cke-widget-editable=\"true\"> " + "<div class=\"h3\"><a id=\"card-title-link\" href=\"/card-details/card-name\">CARD NAME</a></div>" + "<div class=\"card-info\">" + "<div class=\"card-image\">" + "<a id=\"card-image-link\" href=\"/card-details/card-name\">" + "<img id=\"card-image\" alt=\"CARD NAME\" src=\"\">" + "</a>" + "</div>" + "<div class=\"card-details\">" + "<div class=\"h4\">Fees and interest</div>" + "<dl id=\"card-attributes\">" + "<dt>Annual fee:</dt> " + "<dd id=\"annual-fee\">$ANNUAL FEE</dd>" + "<dd id=\"annual-fee-note\" class=\"note\">annual fee note</dd>" + "<dt>Purchase interest rate:</dt> " + "<dd id=\"int-purch\">INT RATE%</dd>" + "<dd id=\"int-purch-note\" class=\"note\">intrest rate note</dd>" + "<dt>Cash advance rate:</dt> " + "<dd id=\"cash-adv\">CASH ADV RATE%</dd>" + "<dd id=\"cash-adv-note\" class=\"note\">cash adv note</dd>" + "<dt>Balance transfer rate:</dt> " + "<dd id=\"balance-trans\">BALANCE TRANS RATE%</dd>" + "<dd id=\"balance-trans-note\" class=\"note\">balance trans note</dd>" + "<dt>Rewards Rate:</dt> " + "<dd id=\"reward-rate\">REWARDS RATE</dd>" + "<dt>Bonus Offer:</dt> " + "<dd id=\"bonus-offer\">BONUS OFFER</dd>" + "<dt>Card Type:</dt> " + "<dd id=\"card-type\">CARD TYPE(S)</dd>" + "<dt>Credit Needed:</dt> " + "<dd id=\"credit-needed\">CREDIT SCORE</dd>" + "</dl>" + "</div>" + "</div>" + "<div class=\"card-description\">" + "<p>Add a card description here</p>" + "<div class=\"buttons\" style=\"text-align:center;\">" + "<a class=\"btn secondary\" id=\"learn-more\" href=\"/card-details/card-name\\\">Learn More</a> </div>" + "</div>" + "</div>"; // Dialog CKEDITOR.dialog.add( 'cc_widget', this.path + 'dialog.js' ); // Widget definition editor.widgets.add("cc_widget",{ dialog : "cc_widget", init : function(){ var card_title_link = this.element.findOne('#card-title-link'); this.data.card_title_link_url = card_title_link.getAttribute("href"); this.data.card_title_link_text = card_title_link.getHtml(); var card_image_link = this.element.findOne('#card-image-link'); this.data.card_image_link_url = card_image_link.getAttribute("href"); var card_image = this.element.findOne('#card-image'); this.data.card_image_alt = card_image.getAttribute("alt"); this.data.card_image_src = card_image.getAttribute("src"); var annual_fee = this.element.findOne('#annual-fee'); var annual_fee_note = this.element.findOne('#annual-fee-note'); this.data.annual_fee_text = annual_fee.getHtml(); this.data.annual_fee_note_text = annual_fee_note.getHtml(); var purchase_interest_rate = this.element.findOne('#int-purch'); var interest_info = this.element.findOne('#int-purch-note'); this.data.purchase_interest_rate = purchase_interest_rate.getHtml(); this.data.purchase_interest_rate_note = interest_info.getHtml(); var cash_advance_rate = this.element.findOne('#cash-adv'); var cash_advance_info = this.element.findOne('#cash-adv-note'); this.data.cash_advance_rate = cash_advance_rate.getHtml(); this.data.cash_advance_rate_note = cash_advance_info.getHtml(); var balance_transfer_rate = this.element.findOne('#balance-trans'); var balance_transfer_info = this.element.findOne('#balance-trans-note'); this.data.balance_transfer_rate = balance_transfer_rate.getHtml(); this.data.balance_transfer_rate_note = balance_transfer_info.getHtml(); var reward_rate = this.element.findOne('#reward-rate'); this.data.reward_rate = reward_rate.getHtml(); var bonus_offer = this.element.findOne('#bonus-offer'); this.data.bonus_offer = bonus_offer.getHtml(); var card_type = this.element.findOne('#card-type'); this.data.card_type = card_type.getHtml(); var credit_needed = this.element.findOne('#credit-needed'); this.data.credit_needed = credit_needed.getHtml(); var learn_more = this.element.findOne('#learn-more'); this.data.learn_more = learn_more.getAttribute("href"); var card_data = this.element.findOne('#card_data'); this.data.card_data = (card_data ? card_data : ''); }, upcast : function(element) { return element.hasClass("credit-card-widget"); }, template : str_html , editables : { card_title_link: { selector: '#card-title-link' }, card_image_link: { selector: '#card-image-link' }, card_image: { selector: '#card-image' }, annual_fee: { selector: '#annual-fee' }, annual_fee_note: { selector: '#annual-fee-note' }, purchase_interest_rate: { selector: '#int-purch' }, interest_info: { selector: '#int-purch-note' }, cash_advance_rate: { selector: '#cash-adv' }, cash_advance_info: { selector: '#cash-adv-note' }, balance_transfer_rate: { selector: '#balance-trans' }, balance_transfer_info: { selector: '#balance-trans-note' }, reward_rate: { selector: '#reward-rate' }, bonus_offer: { selector: '#bonus-offer' }, card_type: { selector: '#card-type' }, credit_needed: { selector: '#credit-needed' }, card_description: { selector: '#card-description' }, }, data : function() { console.log(this); console.log(this.data); var card_title_link = this.element.findOne('#card-title-link'); card_title_link.setHtml(this.data.card_data.card_name); card_title_link.setAttribute('href', '/card-details/' + this.data.card_data.card_slug); var card_image_link = this.element.findOne('#card-image-link'); card_image_link.setAttribute('href', '/card-details/' + this.data.card_data.card_slug); var card_image = this.element.findOne('#card-image'); card_image.setAttribute('alt', this.data.card_data.card_name); card_image.setAttribute('src', this.data.card_data.card_image); var annual_fee = this.element.findOne('#annual-fee'); var annual_fee_note = this.element.findOne('#annual-fee-note'); annual_fee.setHtml('$' + this.data.card_data.annual_fee); if(this.data.card_data.annual_fee_info){ annual_fee_note.removeAttribute( 'style' ); annual_fee_note.setHtml(this.data.card_data.annual_fee_info); }else { annual_fee_note.setAttribute('style', 'display:none;'); annual_fee_note.setHtml(''); } var purchase_interest_rate = this.element.findOne('#int-purch'); var purchase_interest_rate_note = this.element.findOne('#int-purch-note'); purchase_interest_rate.setHtml(this.data.card_data.purchase_interest_rate); if(this.data.card_data.annual_fee_info){ purchase_interest_rate_note.removeAttribute( 'style' ); purchase_interest_rate_note.setHtml(this.data.card_data.interest_info); }else { purchase_interest_rate_note.setAttribute('style', 'display:none;'); purchase_interest_rate_note.setHtml(''); } var cash_advance_rate = this.element.findOne('#cash-adv'); var cash_advance_info = this.element.findOne('#cash-adv-note'); cash_advance_rate.setHtml(this.data.card_data.cash_advance_rate + '%'); if(this.data.card_data.annual_fee_info){ cash_advance_info.removeAttribute( 'style' ); cash_advance_info.setHtml(this.data.card_data.cash_advance_info); }else { cash_advance_info.setAttribute('style', 'display:none;'); cash_advance_info.setHtml(''); } var balance_transfer_rate = this.element.findOne('#balance-trans'); var balance_transfer_info = this.element.findOne('#balance-trans-note'); balance_transfer_rate.setHtml(this.data.card_data.balance_transfer_rate + '%'); if(this.data.card_data.annual_fee_info){ balance_transfer_info.removeAttribute( 'style' ); balance_transfer_info.setHtml(this.data.card_data.balance_transfer_info); }else { balance_transfer_info.setAttribute('style', 'display:none;'); balance_transfer_info.setHtml(''); } var reward_rate = this.element.findOne('#reward-rate'); reward_rate.setHtml(this.data.card_data.rewards_rate); var bonus_offer = this.element.findOne('#bonus-offer'); bonus_offer.setHtml(this.data.card_data.bonus_offer); var card_type = this.element.findOne('#card-type'); card_type.setHtml(this.data.card_data.card_type); var credit_needed = this.element.findOne('#credit-needed'); credit_needed.setHtml(this.data.card_data.credit_needed); var learn_more = this.element.findOne('#learn-more'); learn_more.setAttribute('href', '/card-details/' + this.data.card_data.card_slug); } }); // Button action editor.addCommand( 'add_cc_widget_box', { exec : function(editor) { editor.execCommand("cc_widget"); } }); // Button definition editor.ui.addButton( 'cc_widget_button', { label: 'Add cc-widget link', command: 'add_cc_widget_box', icon: this.path + 'cc-widget.png' }); } });})(); TIA
You should try to set contenteditable="false" attribute to root tag of content which you insert into ckeditor
highcharts can't render
I use Ajax to get data, when I debug with firebug, the result shows highcharts option's data has data. But the chart can't render correctly. The charts background is rended correctely, but there is no chart. here is my code. // # author:wang var chart; var element; var chart_type_element; var y_title_1; var y_title_2; var y_title_3; var date = new Date(); var y = date.getUTCFullYear(); var m = date.getUTCMonth(); var d = date.getUTCDate()-1; var h = date.getUTCHours(); var minute = date.getUTCMinutes(); /** * 返回图表的类型 * */ function chart_type(element){ var type; var wind = '风向风速'; var t_h = '温湿度'; if ( element== 'wind' ){ type = wind; } else if ( element == 't_h') { type = t_h; } return type; } /** * *return y-axis title * */ function y_title(element, serie){ var title; if ( element== 'wind' ){ switch (serie){ case 1: title = '风速'; break; case 2: title = '阵风'; break; case 3: title = '风向'; break; } } else if ( element == 't_h') { switch (serie){ case 1: title = '温度'; break; case 2: title = '湿度'; break; default: title = ''; } } return title; } function getLocTime(nS) { return new Date(parseInt(nS)).toLocaleString().replace(/年|月/g, "-").replace(/日/g, " "); } /** * 气压配置选项 */ var option_p = { chart: { renderTo: 'station_curve', zoomType: 'x' }, title:{ text:'气压序列图' }, subtitle: { text: '信科气象台' }, xAxis: { type: 'datetime', maxZoom: 3600000, // one hour title: { text: null } }, yAxis: { plotLines: [{ value: 0, width: 1, color: '#808080' }], min:980, max:1040 }, tooltip: { formatter: function() { return getLocTime(this.x) +': '+ this.y; } }, legend: { layout: 'vertical', align: 'left', x: 220, verticalAlign: 'top', y: 30, floating: true, backgroundColor: '#FFFFFF' }, series: [{ name: '海平面气压', color: '#4572A7', type: 'line', pointInterval: 60 * 1000, pointStart: Date.UTC(y,m,d,h,minute), marker: { enabled: false } }, { name: '甲板气压', type: 'line', color: '#AA4643', pointInterval: 60 * 1000, pointStart: Date.UTC(y,m,d,h,minute), marker: { enabled: false } }/*, { name: '3', color: '#89A54E', pointInterval: 60 * 1000, pointStart: Date.UTC(y,m,d,h,minute), type: 'spline', marker: { enabled: false } }*/] }; function draw_curve(platformID,element){ option.series[0].data = []; option.series[1].data = []; option_th.series[0].data = []; option_th.series[1].data = []; jQuery.getJSON('get_last_3d.php',{platformID:platformID,element:element}, function(data) { var serie=[]; var serie1=[]; if (element == 'wind_dir'){ $.each(data,function(i,value){ serie[i]=parseInt(value.wd); }); option.series[0].data = serie.reverse(); } else if (element == 'wind_speed'){ $.each(data,function(i,value){ serie[i]=parseInt(value.ws); serie1[i]=parseInt(value.ws_max); }); option_wind_speed.series[0].data = serie.reverse(); option_wind_speed.series[1].data = serie1.reverse(); } else if (element == 't_h') { $.each(data,function(i,value){ serie[i]=parseInt(value.t); serie1[i]=parseInt(value.h); }); option_th.series[0].data = serie.reverse(); option_th.series[1].data = serie1.reverse(); } else if (element == 'p') { $.each(data,function(i,value){ serie[i]=parseInt(value.sea_p); serie1[i]=parseInt(value.deck_p); }); option_p.series[0] = serie.reverse(); option_p.series[1] = serie1.reverse(); } else if (element == 'wave_height') { $.each(data,function(i,value){ serie[i]=parseInt(value.wave_height); }); option.series[0].data = serie.reverse(); } else if (element == 'visibility') { $.each(data,function(i,value){ serie[i]=parseInt(value.visibility); }); option.series[0].data = serie.reverse(); } else if (element == 'cloudheight') { $.each(data,function(i,value){ serie[i]=parseInt(value.cloud_height); }); option.series[0].data = serie.reverse(); } switch(element){ case 'p' : chart = new Highcharts.Chart(option_p); break; case 't_h': chart = new Highcharts.Chart(option_th); break; case 'wind_speed': chart = new Highcharts.Chart(option_wind_speed); break; default: chart = new Highcharts.Chart(option); } /* old code, will be replaced with switch if (element == 'p') chart = new Highcharts.Chart(option_p); else { chart = new Highcharts.Chart(option); } */ }); } $( function(){ draw_curve(105,'t_h'); })//end of jquery function ![the chart][1] thank you advance
The reason it doesn't work is because you didn't provide the values for y,m,d,h,minute for the Date.UTC(y,m,d,h,minute) in the pointStart property for your series. See working: http://jsfiddle.net/LzfM3/