Using checkboxes inside my ag-grid with boolean fields behind and check/uncheck only with the keyboard - ag-grid

I have some boolean fields inside my ag-grid. In addition to be possible to navigate with the keyboard, I would also like to be possible to check/uncheck these checkboxes with the keyboard. I mean let the user move inside the grid with cursor keys, then when the current cell is a checkbox simply use the Space of Enter keys to check/uncheck.
I ended with the solution showed below but I am curious if there is a better/nicer solution for that ?
The trick I used is to catch keyboard events on the grid and change values (true/false) if focused cell is a checkbox.
Example: Plunker demo here
var columnDefs = [
{headerName: "Athlete", field: "athlete", width: 150, editable: true},
{headerName: "Age", field: "age", width: 60, editable: true},
{headerName: "Country", field: "country", width: 120, editable: true},
{headerName: "Boo1", field: "boo1", width: 60, cellRenderer: boolRenderer},
{headerName: "Boo2", field: "boo2", width: 60, cellRenderer: boolRenderer}
];
function boolRenderer(params) {
return `<input type="checkbox" ${params.value ? 'checked' : ''} />`;
}
var gridOptions = {
columnDefs: columnDefs,
onCellKeyPress: cellKeyPress
};
function cellKeyPress(e) {
let ENTER_KEY = 13;
let SPACE_KEY = 32;
var event = e.event;
if (event.keyCode == SPACE_KEY || event.keyCode == ENTER_KEY)
{
var isCheckbox = $(event.target).find("input[type='checkbox']").length > 0;
if (isCheckbox)
{
var currentCell = gridOptions.api.getFocusedCell();
var rowIndex = currentCell.rowIndex;
var colId = currentCell.column.getId();
var rowNode = gridOptions.api.getDisplayedRowAtIndex(rowIndex);
var cellValue = gridOptions.api.getValue(colId, rowNode) || false;
rowNode.setDataValue(colId, !cellValue);
}
}
}
// setup the grid after the page has finished loading
document.addEventListener('DOMContentLoaded', function() {
var gridDiv = document.querySelector('#myGrid');
new agGrid.Grid(gridDiv, gridOptions);
// do http request to get our sample data - not using any framework to keep the example self contained.
// you will probably use a framework like JQuery, Angular or something else to do your HTTP calls.
var httpRequest = new XMLHttpRequest();
httpRequest.open('GET', 'https://raw.githubusercontent.com/ag-grid/ag-grid/master/packages/ag-grid-docs/src/olympicWinnersSmall.json');
httpRequest.send();
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState === 4 && httpRequest.status === 200) {
var httpResult = JSON.parse(httpRequest.responseText);
gridOptions.api.setRowData(httpResult);
}
};
});
.test-container {
height: 100%;
display: flex;
flex-direction: column;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script> var __basePath = ''; </script>
<style>
html, body {
height: 100%;
width: 100%;
margin: 0;
box-sizing: border-box;
-webkit-overflow-scrolling: touch;
}
html {
position: absolute;
top: 0;
left: 0;
padding: 0;
overflow: auto;
}
body {
padding: 1rem;
overflow: auto;
}
</style>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="https://unpkg.com/ag-grid-community#21.2.0/dist/ag-grid-community.min.js"></script> <link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="test-container">
<div id="myGrid" class="ag-theme-balham" style="height: calc(100% - 30px);"></div>
</div>
<script src="main.js"></script>
</body>
</html>

if you asking about alternative way , this is my suggestion .
you can try agSelectCellEditor in the columnDefs , user will still be able to change it using keyboard by pressing enter and select true or false using arrow key.
this.columnDefs = [
{
headerName: 'ID',
field: 'id',
width: 50
},
headerName: 'IsCompleted',
field: 'isCompleted',
editable: true,
filter: true,
sortable: true,
cellEditor: "agSelectCellEditor",
cellEditorParams:
{
values: ["True", "False"]
},
width: 105}
]
And to save your changes on the server side:
(cellEditingStopped)="UpdateTrainingData()" //as an example your ag-grid html tag.

Related

Bound popup removed when layer changed in control

I have a map with a layer control that has overlays specified in the baselayer parameter:
var overlays = {
'Layer 1': mylayer1,
'Layer 2': mylayer2
};
L.control.layers( overlays, null, { collapsed: false } ).addTo( map );
I specify my layers as follows:
var mylayer1 = L.esri.featureLayer({
url: 'https://.../MapServer/5'
}).on( 'load', function ( e ) {
...
}).on( 'loading', function ( e ) {
...
}).bindPopup( function ( layer ) {
return L.Util.template( '<p>{_score}</p>', layer.feature.properties );
});
The issue is that when I change layers in the control the bindPopup event no longer gets called.
It's almost like the layer z-index is not updated. Would appreciate any insight on how I can address this.
See: https://codepen.io/jvanulde/pen/LYyOWZo
I see no one has given an answer.
A little around, but it works.
You add the id: x to each layer. Later in the loop you check which layer is active, and all the rest of the layers you add the style display: none.
window.addEventListener('DOMContentLoaded', () => {
let tiles = L.tileLayer('//{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors, Points &copy 2012 LINZ'
});
let l1 = L.esri.featureLayer({
url: 'https://maps-cartes.services.geo.ca/server_serveur/rest/services/NRCan/nhsl_en/MapServer/1',
id: 0, // required
simplifyFactor: 0.25,
precision: 5,
fields: ['OBJECTID'],
renderer: L.canvas()
}).bindPopup(function(layer) {
return L.Util.template('<p>Layer 1: <strong>{OBJECTID}</strong></p>', layer.feature.properties);
});
let l2 = L.esri.featureLayer({
url: 'https://maps-cartes.services.geo.ca/server_serveur/rest/services/NRCan/nhsl_en/MapServer/2',
id: 1, // required
simplifyFactor: 0.25,
precision: 5,
fields: ['OBJECTID'],
renderer: L.canvas()
}).bindPopup(function(layer) {
return L.Util.template('<p>Layer 2: <strong>{OBJECTID}</strong></p>', layer.feature.properties);
});
let map = L.map('map', {
center: [49.2827, -123.1207],
zoom: 12,
layers: [tiles]
});
let overlays = {
'Layer 1': l1,
'Layer 2': l2
};
L.control.layers(overlays, null, {
collapsed: false
}).addTo(map);
l1.addTo(map);
map.on('baselayerchange', function(e) {
const layersCanvas = document.querySelectorAll('.leaflet-overlay-pane > canvas');
layersCanvas.forEach((layer, index) => {
layer.style.display = '';
if (index !== e.layer.options.id) {
layer.style.display = 'none';
}
});
});
});
html {
height: 100%;
}
body {
min-height: 100%;
margin: 0;
padding: 0;
}
#map {
width: 100%;
height: 100vh;
}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.7.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet#1.7.1/dist/leaflet.js"></script>
<script src="https://unpkg.com/esri-leaflet#3.0.2/dist/esri-leaflet.js"></script>
<div id="map"></div>

ag-grid - space between column header and first row

There is a space between grid header row and first data row - how do i remove this? Thanks
My code:
<div>
<ag-grid-angular style="width: 500px; height: 500px;" [headerHeight]="0" [rowData]="rowData"
[rowSelection]="rowSelection" [rowMultiSelectWithClick]="true" [columnDefs]="columnDefs"
[floatingFiltersHeight]="0" (gridReady)="onGridReady($event)">
</ag-grid-angular>
</div>
columnDefs = [{
headerName: 'id', field: 'id', editable: true, suppressToolPanel: true, filter: false, hide: true
},
{
headerName: 'payrollcode', field: 'payrollcode', editable: true, suppressToolPanel: true, filter: false
},
{
headerName: 'select', field: 'select', editable: true, suppressToolPanel: true, filter: true, cellRendererParams: { checkbox: true }
}];
Please find code for screenshot gird below.
#Input()
displayObject: Array<any> = [];
#Input()
title = '';
columnDefs = [];
calcHeight$ = of(30);
loading$;
rowData = [];
constructor(
public activeModal: NgbActiveModal,
private calendarService: CalendarService,
private injector: Injector,
private modalService: NgbModal,
private sdToastService: SdToastService) { }
ngOnInit() {
Object.keys(this.displayObject[0]).forEach(key => {
this.columnDefs.push({ headerName: key, field: key, sortable: true, filter: true });
});
// this.rowData.concat(this.displayObject);
this.rowData = this.displayObject;
console.log(this.rowData);
}
<div style="width: 400px; height: 400px;">
<ag-grid-angular style="width: 600px; height:300px;" class="ag-theme-balham" [rowData]="rowData"
[columnDefs]="columnDefs">
</ag-grid-angular>
</div>
I added the code for the grid in the screenshot.
Here is a screenshot showing better the issue:
import { Component, Injector, Input, OnInit } from '#angular/core';
import { NgbActiveModal, NgbModal } from '#ng-bootstrap/ng-bootstrap';
import { of } from 'rxjs';
import { CalendarService } from '../calendar.service';
#Component({
selector: 'app-preview-calendars',
templateUrl: './preview-calendars.component.html',
styleUrls: ['./preview-calendars.component.css']
})
export class PreviewCalendarsComponent implements OnInit {
#Input()
displayObject: Array<any> = [];
#Input()
title = '';
columnDefs = [];
calcHeight$ = of(30);
loading$;
rowData = [];
constructor(
public activeModal: NgbActiveModal,
private calendarService: CalendarService,
private injector: Injector,
private modalService: NgbModal,
) { }
ngOnInit() {
Object.keys(this.displayObject[0]).forEach(key => {
this.columnDefs.push({ headerName: key, field: key, sortable: true, filter: true });
});
// this.rowData.concat(this.displayObject);
this.rowData = this.displayObject;
console.log(this.rowData);
}
}
<div style="width: 400px; height: 400px;">
<ag-grid-angular class="ag-theme-balham" [rowData]="rowData" [columnDefs]="columnDefs">
</ag-grid-angular>
</div>
You will see that the first row is occupies too much space and the last row is hidden - this is the issue it seems there is an empty row being displayed.
The data:
I had the exact same issue. I was embedding the grid in a prosemirror document. white-space: break-spaces is what broke ag-grid.
Setting white-space: normal !important fixed the header spacing issue.
Your problem may be caused by duplicate rows. Try adding a unique id for each element and adding getRowNodeId: data => data.id to the gridOptions.

How to add "Follow the link popup" into TinyMCE 4

I implemented somethink like on this picture:
if you click on a link popup will appear and you can follow the link.
jQuery(function($){
/**
* add the follow link popup to all TinyMCE instances
*/
if (!window.tinymce) return;
tinymce.on('AddEditor', function( event ) {
tinymce.editors.forEach(function(editor) {
if (!editor.isFollowLinkAdded) {
editor.isFollowLinkAdded = true;
editor.on('blur', function(e) {
jQuery(e.target.contentDocument.body).find('#followLink').remove();
});
editor.on('click', function(e) {
var link = jQuery(e.target).closest('a');
jQuery(e.view.document.body).find('#followLink').remove();
if (link.length) {
e.preventDefault();
var POPUP_WIDTH = 215,
isRightSide = (jQuery(e.view.document).width()-e.pageX) >= POPUP_WIDTH,
boxCss = {
top: e.pageY,
padding: '6px 10px',
position: 'absolute',
backgroundColor: '#ffffff',
border: '1px solid #a8a8a8',
borderRadius: '2px',
boxShadow: '0 1px 3px rgba(0, 0, 0, 0.2)',
color: '#666666',
cursor: 'pointer',
whiteSpace: 'nowrap',
zIndex: 502
};
boxCss[(isRightSide) ? 'left' : 'right'] = (isRightSide) ? e.pageX : jQuery(e.view.document).width()-e.pageX;
jQuery('<a/>', {
href: link.attr('href'),
text: link.attr('href'),
target: '_blank'
}).css({
cursor: 'pointer',
display: 'inline-block',
maxWidth: '100px',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap'
}).wrap(
jQuery('<p/>', {
text: 'Click to follow: ',
id: 'followLink',
}).on('click', function(){
var win = window.open(link.attr('href'), '_blank');
win.focus();
}).css(boxCss)
).parent().appendTo(e.view.document.body);
}
});
}
});
}, true );
});
The most recent version of TinyMCE 4 (4.5.3) includes the option to open a link in the right click menu of the editor - no need to write your own custom code.

nvd3 Display 2 Chart

at my work I try to print some graph with nvd3.
But I can only display 1 graph on my page, and I don't understand why the previous graph don't appear.
Could you give me some hint ?
<!DOCTYPE html>
<meta charset="utf-8">
<head>
<link href="lib/css/nv.d3.css" rel="stylesheet">
</head>
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: auto;
position: relative;
width: 960px;
}
/**********
* Legend
*/
.nvd3 .nv-legend .nv-series {
cursor: pointer;
}
.nvd3 .nv-legend .nv-disabled circle {
fill-opacity: 0;
}
text {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
form {
position: absolute;
right: 10px;
top: 10px;
}
#chart, #pid svg {
height: 600px;
width: 600px;
}
</style>
<div id="pid">
<svg></svg>
</div>
<div id="chart">
<svg></svg>
</div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="lib/js/nv.d3.js"></script>
<script>
var divs = ["pid", "chart"];
divs["pid"]= {id:"#pid svg", datam:[
{
values:[
{x:"M",y:1},
{x:"T",y:2},
{x:"W",y:3},
{x:"R",y:3},
{x:"F",y:4},
{x:"S",y:5},
{x:"U",y:6}
],
key:"Apples"
},
{
values:[
{x:"M",y:5},
{x:"T",y:2},
{x:"W",y:6},
{x:"R",y:8},
{x:"F",y:2},
{x:"S",y:4},
{x:"U",y:1}
],
key:"Zebras"
},
{
values:[
{x:"M",y:4},
{x:"T",y:6},
{x:"W",y:5},
{x:"R",y:7},
{x:"F",y:7},
{x:"S",y:2},
{x:"U",y:5}
],
key:"Bananas"
}
], color:['purple', 'black', 'yellow']};
divs["chart"]= {id:"#chart svg", datam:[
{
values:[
{x:"M",y:1},
{x:"T",y:2},
{x:"W",y:3},
{x:"R",y:3},
{x:"F",y:4},
{x:"S",y:5},
{x:"U",y:6}
],
key:"Apples"
},
{
values:[
{x:"M",y:5},
{x:"T",y:2},
{x:"W",y:6},
{x:"R",y:8},
{x:"F",y:2},
{x:"S",y:4},
{x:"U",y:1}
],
key:"Zebras"
}
], color:['red', 'blue', 'green']};
console.log(divs)
var i=0;
var chart = new Array(2);
nv.render = function render(step) {
// number of graphs to generate in each timeout loop
step = step || 1;
nv.render.active = true;
nv.dispatch.render_start();
setTimeout(function() {
var chart, graph;
for (var i = 0; i < step && (graph = nv.render.queue[i]); i++) {
chart = graph.generate();
if (typeof graph.callback == typeof(Function)) graph.callback(chart);
nv.graphs.push(chart);
}
nv.render.queue.splice(0, i);
if (nv.render.queue.length) setTimeout(arguments.callee, 0);
else {
nv.dispatch.render_end();
nv.render.active = false;
}
}, 0);
};
nv.render.active = false;
nv.render.queue = [];
for (var key in divs) {
console.log(i);
nv.addGraph(function(obj) {
if (typeof arguments[0] === typeof(Function)) {
obj = {generate: arguments[0], callback: arguments[1]};
}
nv.render.queue.push(obj);
console.log(nv.render.queue.length);
if (!nv.render.active) {
nv.render();
}
chart[i] = nv.models.multiBarChart().showControls(true).groupSpacing(0.5).color(divs[key]['color']);
chart[i].yAxis
.tickFormat(d3.format(',.1f'));
d3.select(divs[key]['id'])
.datum(divs[key]['datam'])
.transition().duration(500).call(chart[i]);
nv.utils.windowResize(chart[i].update);
return chart[i];
});
i++;
};
// render function is used to queue up chart rendering
// in non-blocking timeout functions
</script>
I hope you colud help me, thanks.

Getting toggle to work with different Google Fusion Tables

fairly new person to Javascript here.
I have tried to get a toggle to work for busline stops coordinators from Google Fusion Table on my Google Maps but I can seem to fix it. Tried several solutions that I found here on stackoverflow.
Anyone that can shed some light on this?
var map;
var busLine3;
var busLine3Id = "1kc0F0rZl17KNJZCyrvFrDbPVyTtbWZm14nxABgBR";
function initialize() {
var map = new google.maps.Map(document.getElementById('googft-mapCanvas'), {
center: new google.maps.LatLng(59.327677777000000, 18.062950644241347),
zoom: 13,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var busLine3 = new google.maps.FusionTablesLayer({
map: map,
heatmap: { enabled: false },
query: {
select: "col2",
from: busLine3Id,
},
options: {
styleId: 2,
templateId: 2
}
});
busLine3.setMap(map);
}
// Toggle the layer to hide/show
function changeLayer(tableidselections) {
if (tableidselections == busLine3Id){
if (document.getElementById("show_hide_layer1").checked == true) {
if(busLine3.getMap() == null) { busLine3.setMap(map); }
}
if (document.getElementById("show_hide_layer1").checked == false) {
busLine3.setMap(null); /*layersetoff*/
}
}
My index.html:
<head>
<style type="text/css">
html, body, #googft-mapCanvas {
height: 600px;
margin: 0;
padding: 0;
width: 800px;
}
</style>
<script type="text/javascript" src="https://maps.google.com/maps/api/js?sensor=false&v=3"></script>
<script type="text/javascript" src="mapScript.js"></script>
</head>
<body onload="initialize()";>
<h2>Enabled with Google Maps API (HTML and Javascript)</h2>
<input type="checkbox" id="show_hide_layer1" onclick="changeLayer(this.value);" checked="checked">Bus Line 3</input>
<input type="checkbox" id="show_hide_layer2" onclick="changeLayer(this.value);" checked="checked">Locations</input>
<div id="googft-mapCanvas"></div>
<br/>
Your problem is this line:
if (tableidselections == busLine3Id)
tableidselections is "on"; busLine3Id is "1kc0F0rZl17KNJZCyrvFrDbPVyTtbWZm14nxABgBR"
Once I fix that (change busLine3Id to "on", I get Uncaught TypeError: Cannot read property 'setMap' of undefined because busLine3 is local to your initialize function (you declare it in the global scope, var buseLin3, but then re-declare it locally in initalize.
Same issue with your map variable.
Working code snippet:
var map;
var busLine3;
var busLine3Id = "1kc0F0rZl17KNJZCyrvFrDbPVyTtbWZm14nxABgBR";
function initialize() {
map = new google.maps.Map(document.getElementById('googft-mapCanvas'), {
center: new google.maps.LatLng(59.327677777000000, 18.062950644241347),
zoom: 13,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
busLine3 = new google.maps.FusionTablesLayer({
map: map,
heatmap: {
enabled: false
},
query: {
select: "col2",
from: busLine3Id
},
options: {
styleId: 2,
templateId: 2
}
});
busLine3.setMap(map);
}
// Toggle the layer to hide/show
function changeLayer(tableidselections) {
if (tableidselections == "on") {
if (document.getElementById("show_hide_layer1").checked == true) {
if (busLine3.getMap() == null) {
busLine3.setMap(map);
}
}
if (document.getElementById("show_hide_layer1").checked == false) {
busLine3.setMap(null); /*layersetoff*/
}
}
}
google.maps.event.addDomListener(window, 'load', initialize);
html,
body,
#googft-mapCanvas {
height: 600px;
margin: 0;
padding: 0;
width: 800px;
}
<script src="https://maps.googleapis.com/maps/api/js?sensor=false&ext=.js"></script>
<h2>Enabled with Google Maps API (HTML and Javascript)</h2>
<input type="checkbox" id="show_hide_layer1" onclick="changeLayer(this.value);" checked="checked">Bus Line 3</input>
<input type="checkbox" id="show_hide_layer2" onclick="changeLayer(this.value);" checked="checked">Locations</input>
<div id="googft-mapCanvas"></div>
<br/>
working fiddle