Cannot read property 'push' of undefined in React with Google charts - javascript

I have a bit of a weird error with react and my google charts, when i first login to my page that shows my chart everything shows fine, but there's a place where i import data for new values to show on my chart and the chart disappears when i import new values and i get the following errors:
Uncaught TypeError: processedData[(index + 1)] is undefined
This shows in the browser dev tools console, and when i run my debugger it shows this:
Uncaught TypeError: Cannot read property 'push' of undefined
/src/components/Charts/DoubleColumnChart/DoubleColumnChart.js:48
The above error occurred in the <DoubleColumnChart> component:
in DoubleColumnChart
The error seems to be in this part of my code:
data.datasets.forEach(function (dataset) {
processedData[0].push(dataset.label);
dataset.data.forEach(function (data, index) {
processedData[index + 1].push(data);
});
});
I read some documentation on withRouter but i dont know if that would work here. Here is my full code:
import React from 'react';
import { Chart } from "react-google-charts";
import { withRouter } from "react-router";
export const DoubleColumnChart = (props) => {
const processData = (data) => {
if (data == null) return [[]];
if (data.labels == null) return [[]];
var processedData = [[]];
processedData[0].push('Category');
data.labels.forEach(function (label) {
var finalLabel = label[0];
if (label.length > 1) {
for (var i = 1; i < label.length; i++) {
if (finalLabel.length > parseInt(160 / data.labels.length, 10)) {
finalLabel = finalLabel + '...';
break;
}
finalLabel = finalLabel + '\n' + label[i];
}
}
processedData.push([finalLabel]);
});
console.log(data.datasets);
data.datasets.forEach(function (dataset) {
processedData[0].push(dataset.label);
dataset.data.forEach(function (data, index) {
processedData[index + 1].push(data);
});
});
return processedData;
}
const processColors = (data) => {
if (data == null) return [];
if (data.datasets == null) return [[]];
var processedColors = [];
data.datasets.forEach(function (dataset) {
processedColors.push(dataset.backgroundColor);
});
return processedColors
}
if (props.isVisible == false) {
return <div></div>;
}
return (
<Chart
width={'99%'}
height={'375px'}
chartType="ColumnChart"
loader={<div>Loading Chart</div>}
data={processData(props.data)}
options={{
animation: {
duration: 1500,
easing: 'out',
startup: true,
},
legend: { position: 'bottom', textStyle: { color: 'gray' } },
vAxis: { textStyle: { color: 'gray' } },
hAxis: { textStyle: { fontSize: 10, color: 'gray' } },
tooltip: { trigger: 'hover', showColorCode: true },
chartArea: {
top: '2%',
left: '5%',
height: "77%",
width: "100%",
},
colors: processColors(props.data),
dataOpacity: '0.9',
}}
chartEvents={[
{
eventName: 'select',
callback: ({ chartWrapper }) => {
const chart = chartWrapper.getChart()
const selection = chart.getSelection()
if (selection.length === 1) {
const [selectedItem] = selection;
const { row } = selectedItem;
var labelData = props.data.labels[row];
var finalLabel = '';
for (var i = 0; i < labelData.length; i++) {
finalLabel = finalLabel + labelData[i];
}
finalLabel = finalLabel.replace(/ /g, '');
if (props.onSegmentClick) props.onSegmentClick(finalLabel);
}
},
},
]}
rootProps={{ 'data-testid': '1' }}
/>
);
}
Can anyone help me with this? Thanks.

When you are pushing data to an array with index+1 logic, so you should check that the next index of the array exists and then push data to that or convert the next index to an array and then push.
So, the typesafe way is something like this:
if(Array.isArray(processedData[index + 1])) {
processedData[index + 1].push(data);
}else {
processedData[index + 1] = [data]
}

In javascript push method can be used on array.
For example:
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.push("Kiwi");
But in the below method you are using processedData[0].push(dataset.label) which is like acessing the first element of the array and pushing into it which is wrong. You can do like processedData.push(dataset.label).
data.datasets.forEach(function (dataset) {
processedData[0].push(dataset.label);
dataset.data.forEach(function (data, index) {
processedData[index + 1].push(data);
});

Related

console.log() to TextArea

I wrote a code that opens csv files with FileDialog and converts them to JSON. I sum the values ​​I want for each TimeStamp in the CSV file and print them to the console. In the function openFile() you can see the values ​​I send to the console. However, I cannot print the values ​​I have printed on the console to a TextArea or Label. I would be glad if you can help with this.
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Demo App")
function getControl(){
return {
data: null,
getTotalBataryCount:()=>{
let battery = 0;
for(let i=0;i<this.data.length;i++){
battery += ((this.data[i]["battery0.mahConsumed"]!="--.--")?parseFloat(this.data[i]["battery0.mahConsumed"]):0);
}
return battery;
},
getAltitudeCountHigh:()=>{
let amslHigh = 0;
for(let i=0;i<this.data.length;i++){
if((this.data[i]["altitudeAMSL"]>amslHigh)){
amslHigh = this.data[i]["altitudeAMSL"];
}
}
return amslHigh;
},
getTotalFlighttime : ()=> {
let flighttime= 0;
for(let i=0; i<this.data.length;i++){
flighttime += ((this.data[i]["flightTime"]!= "00:00:00")?parseFloat(this.data[i]["flightTime"]):0);
}
return flighttime;
},
};
}
function openFile(fileUrl, items){
return new Promise((resolve,reject)=>{
var parser = [];
if (fileUrl.toString())
parser = csvJSON
if (parser) {
var request = new XMLHttpRequest()
request.open('GET', fileUrl)
request.onreadystatechange = function(event) {
if (request.readyState === XMLHttpRequest.DONE) {
let controlObject = getControl();
controlObject.data = parser(request.responseText);
items.push(controlObject.getTotalBataryCount(), controlObject.getAltitudeCountHigh(), controlObject.getTotalFlighttime())
console.log("deneme", items)
console.log(controlObject.getTotalBataryCount());
console.log(controlObject.getAltitudeCountHigh());
console.log(controlObject.getTotalFlighttime());
resolve(data);
}
}
request.send()
}
reject(false);
});
}
function saveFile(fileUrl, text) {
var request = new XMLHttpRequest();
request.open("PUT", fileUrl, false);
request.send(text);
return request.status;
}
function csvJSON(csvText) {
let lines = [];
const linesArray = csvText.split('\n');
linesArray.forEach((e, any) => {
const row = e.replace(/[\s]+[,]+|[,]+[\s]+/g, ',').trim();
lines.push(row);
});
lines.splice(lines.length - 1, 1);
const result = [];
const headers = lines[0].split(",");
for (let i = 1; i < lines.length; i++) {
const obj = {};
const currentline = lines[i].split(",");
for (let j = 0; j < headers.length; j++) {
obj[headers[j]] = currentline[j];
}
result.push(obj);
}
return result;
}
FileDialog {
id: openFileDialog
nameFilters: [ "All files (*)"]
onAccepted: openFile(openFileDialog.fileUrl)
}
FileDialog {
id: saveFileDialog
selectExisting: false
nameFilters: ["Text files (*.txt)", "All files (*)"]
onAccepted: saveFile(saveFileDialog.fileUrl, textEdit.text)
}
menuBar: MenuBar {
Menu {
title: qsTr("File")
MenuItem {
text: qsTr("&Open")
onTriggered: openFileDialog.open()
}
MenuItem {
text: qsTr("&Save")
onTriggered: saveFileDialog.open()
}
MenuItem {
text: qsTr("Exit")
onTriggered: Qt.quit();
}
}
}
ColumnLayout {
visible:true
spacing: 4
Rectangle{
id: flighttimerect
width: 100
height:100
Layout.alignment: Qt.AlignCenter
color: "grey"
TextArea{
id: flighttimerect1
textColor: "black"
text: "deneme"
}
}
Rectangle {
id: batteryconsumptrect
width:100
height:100
Layout.alignment: Qt.AlignHCenter
color: "grey"
TextArea{
id:batteryconsumptvalue
text: "test"
}
}
Rectangle {
id: flightdistance
width:100
height:100
Layout.alignment: Qt.AlignCenter
color: "grey"
TextArea{
id:distancetext
text: ""
}
}
Rectangle {
id: altituderect
width:100
height:100
Layout.alignment: Qt.AlignCenter
color: "grey"
TextArea{
id:altitudetext
text: ""
}
}
}
}
You can override the console.log method, or any other function, like this:
(()=>{
const console_log = window.console.log;
window.console.log = function(...args){
console_log(...args);
var textarea = document.getElementById('my_console');
if(!textarea) return;
args.forEach(arg=>textarea.value += `${JSON.stringify(arg)}\n`);
}
})();
console.log("Hello, world");
console.log([1, 2, 3]);
<textarea id=my_console></textarea>

Go JS Tree view equivalent in React

I need to achieve the tree view (Go JS Tree View). The respective tree view sample source code without React JS is at (Tree View Source Code). I'm trying to do the same using React JS and have the following code written. But somehow I'm missing something and the diagram/tree view is not rendering. Can you please help me to figure out the issue?
import React from 'react';
import * as go from 'gojs';
import { ReactDiagram } from 'gojs-react';
import '../../../App.css';
go.Shape.defineFigureGenerator("ExpandedLine", function(shape, w, h) {
return new go.Geometry()
.add(new go.PathFigure(0, 0.25*h, false)
.add(new go.PathSegment(go.PathSegment.Line, .5 * w, 0.75*h))
.add(new go.PathSegment(go.PathSegment.Line, w, 0.25*h)));
});
// use a sideways V figure instead of PlusLine in the TreeExpanderButton
go.Shape.defineFigureGenerator("CollapsedLine", function(shape, w, h) {
return new go.Geometry()
.add(new go.PathFigure(0.25*w, 0, false)
.add(new go.PathSegment(go.PathSegment.Line, 0.75*w, .5 * h))
.add(new go.PathSegment(go.PathSegment.Line, 0.25*w, h)));
});
let nodeDataArray = [{ key: 0 }];
const initDiagram = () => {
let $ = go.GraphObject.make;
const diagram =
$(go.Diagram, "myDiagramDiv",
{
allowMove: false,
allowCopy: false,
allowDelete: false,
allowHorizontalScroll: false,
layout:
$(go.TreeLayout,
{
alignment: go.TreeLayout.AlignmentStart,
angle: 0,
compaction: go.TreeLayout.CompactionNone,
layerSpacing: 16,
layerSpacingParentOverlap: 1,
nodeIndentPastParent: 1.0,
nodeSpacing: 0,
setsPortSpot: false,
setsChildPortSpot: false
})
});
diagram.nodeTemplate =
$(go.Node,
{ // no Adornment: instead change panel background color by binding to Node.isSelected
selectionAdorned: false,
// a custom function to allow expanding/collapsing on double-click
// this uses similar logic to a TreeExpanderButton
doubleClick: function(e, node) {
let cmd = diagram.commandHandler;
if (node.isTreeExpanded) {
if (!cmd.canCollapseTree(node)) return;
} else {
if (!cmd.canExpandTree(node)) return;
}
e.handled = true;
if (node.isTreeExpanded) {
cmd.collapseTree(node);
} else {
cmd.expandTree(node);
}
}
},
$("TreeExpanderButton",
{ // customize the button's appearance
"_treeExpandedFigure": "ExpandedLine",
"_treeCollapsedFigure": "CollapsedLine",
"ButtonBorder.fill": "whitesmoke",
"ButtonBorder.stroke": null,
"_buttonFillOver": "rgba(0,128,255,0.25)",
"_buttonStrokeOver": null
}),
$(go.Panel, "Horizontal",
{ position: new go.Point(18, 0) },
new go.Binding("background", "isSelected",
s => (s ? 'lightblue' : 'white')).ofObject(),
$(go.Picture,
{
width: 18, height: 18,
margin: new go.Margin(0, 4, 0, 0),
imageStretch: go.GraphObject.Uniform
},
// bind the picture source on two properties of the Node
// to display open folder, closed folder, or document
new go.Binding("source", "isTreeExpanded", imageConverter).ofObject(),
new go.Binding("source", "isTreeLeaf", imageConverter).ofObject()),
$(go.TextBlock,
{ font: '9pt Verdana, sans-serif' },
new go.Binding("text", "key", function(s) { return "item " + s; }))
) // end Horizontal Panel
); // end Node
diagram.linkTemplate = $(go.Link);
let max = 499;
let count = 0;
while (count < max) {
count = makeTree(3, count, max, nodeDataArray, nodeDataArray[0]);
}
diagram.model = new go.TreeModel(nodeDataArray);
return diagram;
}
function makeTree(level, count, max, nodeDataArray, parentData) {
let numChildren = Math.floor(Math.random() * 10);
for (let i = 0; i < numChildren; i++) {
if (count >= max) return count;
count++;
let childData = { key: count, parent: parentData.key };
nodeDataArray.push(childData);
if (level > 0 && Math.random() > 0.5) {
count = makeTree(level - 1, count, max, nodeDataArray, childData);
}
}
return count;
}
function imageConverter(prop, picture) {
let node = picture.part;
if (node.isTreeLeaf) {
return "images/document.svg";
} else {
if (node.isTreeExpanded) {
return "images/openFolder.svg";
} else {
return "images/closedFolder.svg";
}
}
}
window.addEventListener('DOMContentLoaded', initDiagram);
const TreeView = () => {
return (
<>
GO JS
<div id="myDiagramDiv">
<ReactDiagram
initDiagram={initDiagram}
divClassName='diagram-component'
nodeDataArray={nodeDataArray}
skipsDiagramUpdate={false}
/>
</div>
</>
);
}
export default TreeView;
When React start executing, the DOMContentLoaded event have already been fired. Instead try to call initDiagram in a useEffect hook
const TreeView = () => {
useEffect(initDiagram);
return (
<>
GO JS
<div id="myDiagramDiv">
<ReactDiagram
initDiagram={initDiagram}
divClassName='diagram-component'
nodeDataArray={nodeDataArray}
skipsDiagramUpdate={false}
/>
</div>
</>
);
}

Convert ES6 javascript file to ES5 online

I'm trying to convert a ES6 javascript file to ES5 as I'm need to target an old browser (ie: A webview on Android 4.4.2).
I've seen that Babeljs.io provide a tool to do a conversion, but the output code don't seems valid... (see here)
Any idea how to achieve this conversion (just once) ?
The file concerned is siiimple-toast.js (a toast notification plugin)
/* success + alert + warning + message */
var setStyles = (el, styles) => {
Object.keys(styles).forEach((key) => {
el.style[key] = styles[key];
});
};
const setAttrs = (el, attrs) => {
Object.keys(attrs).forEach((key) => {
el.setAttribute(key, attrs[key]);
});
};
const getAttr = (el, attr) => el.getAttribute(attr);
const privateKeys = {
defaultOptions: Symbol('defaultOptions'),
render: Symbol('render'),
show: Symbol('show'),
hide: Symbol('hide'),
removeDOM: Symbol('removeDOM'),
};
const siiimpleToast = {
[privateKeys.defaultOptions]: {
container: 'body',
class: 'siiimpleToast',
position: 'top|center',
margin: 15,
delay: 0,
duration: 3000,
style: {},
},
setOptions(options = {}) {
return {
...siiimpleToast,
[privateKeys.defaultOptions]: {
...this[privateKeys.defaultOptions],
...options,
},
};
},
[privateKeys.render](state, message, options = {}) {
const mergedOptions = {
...this[privateKeys.defaultOptions],
...options,
};
const {
class: className,
position,
delay,
duration,
style,
} = mergedOptions;
const newToast = document.createElement('div');
// logging via attrs
newToast.className = className;
var toatsLoaded=1;
newToast.innerHTML = '<span class="toastIcon '+state+'">';
setAttrs(newToast, {
'data-position': position,
'data-state': state,
});
setStyles(newToast, style);
// use .setTimeout() instead of $.queue()
let time = 0;
setTimeout(() => {
this[privateKeys.show](newToast, mergedOptions);
}, time += delay);
setTimeout(() => {
this[privateKeys.hide](newToast, mergedOptions);
}, time += temps);
// support method chaining
return this;
},
[privateKeys.show](el, { container, class: className, margin }) {
const hasPos = (v, pos) => getAttr(v, 'data-position').indexOf(pos) > -1;
const root = document.querySelector(container);
root.insertBefore(el, root.firstChild);
// set initial position
setStyles(el, {
position: container === 'body' ? 'fixed' : 'absolute',
[hasPos(el, 'top') ? 'top' : 'bottom']: '-100px',
[hasPos(el, 'left') && 'left']: '15px',
[hasPos(el, 'center') && 'left']: `${(root.clientWidth / 2) - (el.clientWidth / 2)}px`,
[hasPos(el, 'right') && 'right']: '15px',
});
setStyles(el, {
transform: 'scale(1)',
opacity: 1,
});
// distance de départ
let pushStack = 20;
Array
.from(document.querySelectorAll(`.${className}[data-position="${getAttr(el, 'data-position')}"]`))
.filter(toast => toast.parentElement === el.parentElement)// matching container
.forEach((toast) => {
setStyles(toast, {
[hasPos(toast, 'top') ? 'top' : 'bottom']: `${pushStack}px`,
});
pushStack += toast.offsetHeight + margin;
});
},
[privateKeys.hide](el) {
const hasPos = (v, pos) => getAttr(v, 'data-position').indexOf(pos) > -1;
const { left, width } = el.getBoundingClientRect();
setStyles(el, {
[hasPos(el, 'left') && 'left']: `${width}px`,
[hasPos(el, 'center') && 'left']: `${left + width}px`,
[hasPos(el, 'right') && 'right']: `-${width}px`,
opacity: 0,
});
const whenTransitionEnd = () => {
this[privateKeys.removeDOM](el);
el.removeEventListener('transitionend', whenTransitionEnd);
};
el.addEventListener('transitionend', whenTransitionEnd);
},
[privateKeys.removeDOM](el) {// eslint-disable-line
const parent = el.parentElement;
parent.removeChild(el);
},
default(message, options) {
return this[privateKeys.render]('default', message, options);
}
};
$(document).on('click', '.toastClose', function(e){
e.preventDefault();
$(this).parent('.siiimpleToast').remove();
});
Thanks a lot for your feedbacks 🙏
Ben

React Data Grid using row drag and drop and Drag Columns to Reorder features togather

I am trying to use React Data Grid in my project and I want to use row drag and drop and Drag Columns to Reorder features together.
I tried to do this by passing draggable: true for ReactDataGrid column property and wrapping the ReactDataGrid and Draggable.Container with DraggableHeader.DraggableContainer.
It makes column header moveable but it does not trigger onHeaderDrop action in DraggableContainer and it gave a console error Uncaught TypeError: Cannot read property 'id' of undefined.
I change example23-row-reordering.js according to the description above.
const ReactDataGrid = require('react-data-grid');
const exampleWrapper = require('../components/exampleWrapper');
const React = require('react');
const {
Draggable: { Container, RowActionsCell, DropTargetRowContainer },
Data: { Selectors },
DraggableHeader: {DraggableContainer}
} = require('react-data-grid-addons');
import PropTypes from 'prop-types';
const RowRenderer = DropTargetRowContainer(ReactDataGrid.Row);
class Example extends React.Component {
static propTypes = {
rowKey: PropTypes.string.isRequired
};
static defaultProps = { rowKey: 'id' };
constructor(props, context) {
super(props, context);
this._columns = [
{
key: 'id',
name: 'ID',
draggable: true
},
{
key: 'task',
name: 'Title',
draggable: true
},
{
key: 'priority',
name: 'Priority',
draggable: true
},
{
key: 'issueType',
name: 'Issue Type',
draggable: true
}
];
this.state = { rows: this.createRows(1000), selectedIds: [1, 2] };
}
getRandomDate = (start, end) => {
return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime())).toLocaleDateString();
};
createRows = (numberOfRows) => {
let rows = [];
for (let i = 1; i < numberOfRows; i++) {
rows.push({
id: i,
task: 'Task ' + i,
complete: Math.min(100, Math.round(Math.random() * 110)),
priority: ['Critical', 'High', 'Medium', 'Low'][Math.floor((Math.random() * 3) + 1)],
issueType: ['Bug', 'Improvement', 'Epic', 'Story'][Math.floor((Math.random() * 3) + 1)],
startDate: this.getRandomDate(new Date(2015, 3, 1), new Date()),
completeDate: this.getRandomDate(new Date(), new Date(2016, 0, 1))
});
}
return rows;
};
rowGetter = (i) => {
return this.state.rows[i];
};
isDraggedRowSelected = (selectedRows, rowDragSource) => {
if (selectedRows && selectedRows.length > 0) {
let key = this.props.rowKey;
return selectedRows.filter(r => r[key] === rowDragSource.data[key]).length > 0;
}
return false;
};
reorderRows = (e) => {
let selectedRows = Selectors.getSelectedRowsByKey({rowKey: this.props.rowKey, selectedKeys: this.state.selectedIds, rows: this.state.rows});
let draggedRows = this.isDraggedRowSelected(selectedRows, e.rowSource) ? selectedRows : [e.rowSource.data];
let undraggedRows = this.state.rows.filter(function(r) {
return draggedRows.indexOf(r) === -1;
});
let args = [e.rowTarget.idx, 0].concat(draggedRows);
Array.prototype.splice.apply(undraggedRows, args);
this.setState({rows: undraggedRows});
};
onRowsSelected = (rows) => {
this.setState({selectedIds: this.state.selectedIds.concat(rows.map(r => r.row[this.props.rowKey]))});
};
onRowsDeselected = (rows) => {
let rowIds = rows.map(r => r.row[this.props.rowKey]);
this.setState({selectedIds: this.state.selectedIds.filter(i => rowIds.indexOf(i) === -1 )});
};
render() {
return (
<DraggableContainer
onHeaderDrop={()=>{console.log('column dropped');}}
>
<Container>
<ReactDataGrid
enableCellSelection={true}
rowActionsCell={RowActionsCell}
columns={this._columns}
rowGetter={this.rowGetter}
rowsCount={this.state.rows.length}
minHeight={500}
rowRenderer={<RowRenderer onRowDrop={this.reorderRows}/>}
rowSelection={{
showCheckbox: true,
enableShiftSelect: true,
onRowsSelected: this.onRowsSelected,
onRowsDeselected: this.onRowsDeselected,
selectBy: {
keys: {rowKey: this.props.rowKey, values: this.state.selectedIds}
}
}}/>
</Container>
</DraggableContainer>);
}
}
module.exports = exampleWrapper({
WrappedComponent: Example,
exampleName: 'Row Reordering',
exampleDescription: 'This examples demonstrates how single or multiple rows can be dragged to a different positions using components from Draggable React Addons',
examplePath: './scripts/example23-row-reordering.js'
});
I went through their documentation but could not find any place where they say these two features can't use together. But in their examples does not provide any example for this.Any example code for documentation describes how to use these two features together would be greatly appreciated.

SAPUI5 only update specific binding

In SAPUI5 I have a Model ("sModel") filled with metadata.
In this model I have a property "/aSelectedNumbers".
I also have a panel, of which I want to change the visibility depending on the content of the "/aSelectedNumbers" property.
update
first controller:
var oModelMeta = cv.model.recycleModel("oModelZAPRegistratieMeta", that);
//the cv.model.recycleModel function sets the model to the component
//if that hasn't been done so already, and returns that model.
//All of my views are added to a sap.m.App, which is returned in the
//first view of this component.
var aSelectedRegistratieType = [];
var aSelectedDagdelen = ["O", "M"];
oModelMeta.setProperty("/aSelectedRegistratieType", aSelectedRegistratieType);
oModelMeta.setProperty("/aSelectedDagdelen", aSelectedDagdelen);
First Panel (Which has checkboxes controlling the array in question):
sap.ui.jsfragment("fragments.data.ZAPRegistratie.Filters.RegistratieTypeFilter", {
createContent: function(oInitData) {
var oController = oInitData.oController;
var fnCallback = oInitData.fnCallback;
var oModel = cv.model.recycleModel("oModelZAPRegistratieMeta", oController);
var oPanel = new sap.m.Panel( {
content: new sap.m.Label( {
text: "Registratietype",
width: "120px"
})
});
function addCheckBox(sName, sId) {
var oCheckBox = new sap.m.CheckBox( {
text: sName,
selected: {
path: "oModelZAPRegistratieMeta>/aSelectedRegistratieType",
formatter: function(oFC) {
if (!oFC) { return false; }
console.log(oFC);
return oFC.indexOf(sId) !== -1;
}
},
select: function(oEvent) {
var aSelectedRegistratieType = oModel.getProperty("/aSelectedRegistratieType");
var iIndex = aSelectedRegistratieType.indexOf(sId);
if (oEvent.getParameters().selected) {
if (iIndex === -1) {
aSelectedRegistratieType.push(sId);
oModel.setProperty("/aSelectedRegistratieType", aSelectedRegistratieType);
}
} else {
if (iIndex !== -1) {
aSelectedRegistratieType.splice(iIndex, 1);
oModel.setProperty("/aSelectedRegistratieType", aSelectedRegistratieType);
}
}
// arrays update niet live aan properties
oModel.updateBindings(true); //******** <<===== SEE HERE
if (fnCallback) {
fnCallback(oController);
}
},
width: "120px",
enabled: {
path: "oModelZAPRegistratieMeta>/bChanged",
formatter: function(oFC) {
return oFC !== true;
}
}
});
oPanel.addContent(oCheckBox);
}
addCheckBox("Presentielijst (dag)", "1");
addCheckBox("Presentielijst (dagdelen)", "2");
addCheckBox("Uren (dagdelen)", "3");
addCheckBox("Tijd (dagdelen)", "4");
return oPanel;
}
});
Here is the panel of which the visibility is referred to in the question. Note that it DOES work after oModel.updateBindings(true) (see comment in code above), but otherwise it does not update accordingly.
sap.ui.jsfragment("fragments.data.ZAPRegistratie.Filters.DagdeelFilter", {
createContent: function(oInitData) {
var oController = oInitData.oController;
var fnCallback = oInitData.fnCallback;
var oModel = cv.model.recycleModel("oModelZAPRegistratieMeta", oController);
var oPanel = new sap.m.Panel( {
content: new sap.m.Label( {
text: "Dagdeel",
width: "120px"
}),
visible: {
path: "oModelZAPRegistratieMeta>/aSelectedRegistratieType",
formatter: function(oFC) {
console.log("visibility");
console.log(oFC);
if (!oFC) { return true; }
if (oFC.length === 0) { return true; }
return oFC.indexOf("2") !== -1;
}
}
});
console.log(oPanel);
function addCheckBox(sName, sId) {
var oCheckBox = new sap.m.CheckBox( {
text: sName,
selected: {
path: "oModelZAPRegistratieMeta>/aSelectedDagdelen",
formatter: function(oFC) {
if (!oFC) { return false; }
console.log(oFC);
return oFC.indexOf(sId) !== -1;
}
},
select: function(oEvent) {
var aSelectedDagdelen = oModel.getProperty("/aSelectedDagdelen");
var iIndex = aSelectedDagdelen.indexOf(sId);
if (oEvent.getParameters().selected) {
if (iIndex === -1) {
aSelectedDagdelen.push(sId);
oModel.setProperty("/aSelectedDagdelen", aSelectedDagdelen);
}
} else {
if (iIndex !== -1) {
aSelectedDagdelen.splice(iIndex, 1);
oModel.setProperty("/aSelectedDagdelen", aSelectedDagdelen);
}
}
if (fnCallback) {
fnCallback(oController);
}
},
enabled: {
path: "oModelZAPRegistratieMeta>/bChanged",
formatter: function(oFC) {
return oFC !== true;
}
},
width: "120px"
});
oPanel.addContent(oCheckBox);
}
addCheckBox("Ochtend", "O", true);
addCheckBox("Middag", "M", true);
addCheckBox("Avond", "A");
addCheckBox("Nacht", "N");
return oPanel;
}
});
The reason that the model doesn´t trigger a change event is that the reference to the Array does not change.
A possible way to change the value is to create a new Array everytime you read it from the model:
var newArray = oModel.getProperty("/aSelectedNumbers").slice();
// do your changes to the array
// ...
oModel.setProperty("/aSelectedNumbers", newArray);
This JSBin illustrates the issue.

Categories