Custom Cell Format ListView TornadoFx on delete item - tornadofx

I'm new to TornadoFx but am trying it out (also new to JavaFX by extension).
I have a listview defined as so:
private var colorList = mutableListOf<Color>
//other things in init block
colorpicker(mode = ColorPickerMode.MenuButton) {
valueProperty().onChange {
if (it != null) {
colorList.add(it)
}
}
}(Color.BLACK,Color.WHITE).observable()
listview(colorList) {
cellFormat {
text = it.toString()
style {
baseColor = it
}
}
contextmenu {
item("Delete").action {
if (selectedItem != null) {
colorList.remove(selectedItem)
}
}
}
}
//continue init block
Adding and taking away colors from the listview works just fine but the color inside the cell does not disapear if it is no longer occupied
Example of what is happening

The cellFormat function allows you to configure the list cell for each item in your list.
However, when there is no list item for a certain row, the callback is not run, so that you have no way of applying a style to an empty row using the cellFormat approach. One solution would be to implement your own ListCell and always clearing the style property of the cell, but I believe this might actually be fixed within the framework by always clearing the style property before a cell is reused. I just tried to make this change in the framework, and it fixes the issue with your code sample.
I will commit the change now, please try it out with tornadofx-1.7.17-SNAPSHOT :)

Related

How to get specific RadCalendar Day Cell on a cellTap Event and add custom style to it

I'm using RadCalendar in my NativeScript Project, the problem is I want to add custom styling on specific day cell from a cellTap Event.
So I started with listening to the Event
<RadCalendar (cellTap)="onCellTap($event)"></RadCalendar>
in my component.ts file:
onCellTap(args: CalendarCellTapEventData) {
// here, it return the whole RadCalendar Object
console.log(args.object);
// and in the line below it returns the native cell Element
console.log(args.cell)
}
I tried to change directly the CSS properties like this:
args.object.style.backgroundColor = new Color('#ff0000')
but it doesn't work.
Is there a way to perform the required behaviour ?
I don't think adjusting cell style upon tap is supported but it should be possible. To adjust background color of cell,
import { CalendarCellTapEventData } from "nativescript-ui-calendar";
import { Color } from "tns-core-modules/color";
onCellTap(event: CalendarCellTapEventData) {
const color = new Color('#ff0000');
if (color.android) {
// https://docs.telerik.com/devtools/android/AndroidControlsDoc/com/telerik/widget/calendar/CalendarDayCell.html
event.cell.setBackgroundColor(color.android);
} else {
// https://docs.telerik.com/devtools/ios/api/Classes/TKCalendarDayCell.html
event.cell.style().backgroundColor = color.ios;
}
}

Block vertical scroll while using SlidingListTile

I would like to use the SlidingListTile, but I am having some issues.
I think that when we use the horizontal sliding the vertical scroll should be locked, because is getting hard to complete de slide on the phone.
Did someone get a situation like that?
Thanks in advance,
Here is part of my code:
slidingTile.swipedLeftProperty().addListener((obs, ov, nv) -> {
if (nv && edit != null) {
edit.accept(currentItem);
}
slidingTile.resetTilePosition();
});
slidingTile.swipedRightProperty().addListener((obs, ov, nv) -> {
if (nv && edit != null) {
edit.accept(currentItem);
}
slidingTile.resetTilePosition();
});
Indeed, there is an error in the Comments 2.0 sample.
The CommentsPresenter defines a custom ListCell for the ListView, and creates a binding from a single BooleanProperty to each of the cells in the list view:
commentsList.setCellFactory(cell -> {
final CommentListCell commentListCell = new CommentListCell(
service,...);
// notify view that cell is sliding
sliding.bind(commentListCell.slidingProperty());
return commentListCell;
});
Obviously, the sliding property of each cell may vary in time, but only the last one set will prevail, so it won't reflect the change of this property for any of the rest of the cells.
The fix is easy: don't use bindings, but a listener for each cell that will set the value when that cell is sliding:
commentsList.setCellFactory(cell -> {
final CommentListCell commentListCell = new CommentListCell(
service,...);
// notify view that cell is sliding
commentListCell.slidingProperty().addListener((obs, ov, nv) ->
sliding.set(nv));
return commentListCell;
});
I've filed an issue.

Kendo Grid: Removing dirty cell indicators

I have been looking at a way to save off my client side edited grid data automatically when the user changes to another row (just like in access, sql management studio etc). It really seems to be a bit of a challenge to do.
One scheme was to use the data source sync, but this ha the problem of loosing our cell position (it always jumped to cell 0, 0).
I have been shown some clever work arounds (go back to the cell after the case, which by the way is hugely appreciated thanks),
but it after some lengthy testing (by myself and others) seemed to be a little "glitchy" (perhaps I just need to work on this more)
At any rate, I wanted to explore perhaps not using this datasource sync and perhaps just do the server side calls "manually" (which is a bit is a pity, but if that's what we need to do, so be it). If I do this, I would want to reset the cell little red cell "dirty" indicators.
I thought I could use something similar to this scheme (except rather than resetting the flag, I want to unset).
So, as in the above link, I have the following..
var pendingChanges = [];
function gridEdit(e) {
var cellHeader = $("#gridID").find("th[data-field='" + e.field + "']");
if (cellHeader[0] != undefined) {
var pendingChange = new Object();
pendingChange.PropertyName = e.field;
pendingChange.ColumnIndex = cellHeader[0].cellIndex;
pendingChange.uid = e.items[0].uid;
pendingChanges.push(pendingChange);
}
}
where we call gridEdit from the datasource change..
var dataSrc = new kendo.data.DataSource({
change: function (e) {
gridEdit(e);
},
Now assuming we have a callback that detects the row change, I thought I could do the following...
// clear cell property (red indicator)
for (var i = 0; i < pendingChanges.length; i++) {
var row = grid.tbody.find("tr[data-uid='" + pendingChanges[i].uid + "']");
var cell = row.find("td:eq(" + pendingChanges[i].ColumnIndex + ")");
if (cell.hasClass("k-dirty-cell")) {
cell.removeClass("k-dirty-cell");
console.log("removed dirty class");
}
}
pendingChanges.length = 0;
// No good, we loose current cell again! (sigh..)
//grid.refresh();
When this didn't work, I also tried resetting the data source dirty flag..
// clear dirty flag from the database
var dirtyRows = $.grep(vm.gridData.view(),
function (item) {
return item.dirty == true;
})
if (dirtyRows && dirtyRows.length > 0) {
dirtyRows[0].dirty = false;
}
demo here
After none of the above worked, I tried the grid.refresh(), but this has the same problem as the datasource sync (we loose our current cell)
Would anyone have any idea how I can clear this cell indicator, without refreshing the whole grid that seems to totally loose our editing context?
Thanks in advance for any help!
Css :
.k-dirty-clear {
border-width:0;
}
Grid edit event :
edit: function(e) {
$("#grid .k-dirty").addClass("k-dirty-clear"); //Clear indicators
$("#grid .k-dirty").removeClass("k-dirty-clear"); //Show indicators
}
http://jsbin.com/celajewuwe/2/edit
Simple solution for resolve that problem is to override the color of the "flag" to transparent.
just override the ".k-dirty" class (border-color)
just adding the above lines to your css
CSS:
//k-dirty is the class that kendo grid use for mark edited cells that not saved yet.
//we override that class cause we do not want the red flag
.k-dirty {
border-color:transparent transparent transparent transparent;
}
This can also be done by applying the below style,
<style>
.k-dirty{
display: none;
}
</style>

Show image when a ListBox contains no elements in Windows Phone 7

I want to show a list of items in a grid(in a listbox ofc) but if there are no items to show, I want to display in image instead of the listbox. The best way for this would be to create a Datateplate to determinate weather to show the listbox, or the image.
I would like to avoid setting the visibility of the image or the listbox in code.
Can this be done, and how? Or I have to use the method I wanted to avoid.
If you use MVVM, you could add property IsEmptyListVisibility and bind to it your image Visibility property to control when it displayed:
Visibility IsEmptyListVisibility
{
get
{
return (list.Count == 0) ? Visibility.Visible : Visibility.Collapsed;
}
}
Also, call NotifyPropertyChanged when сollection are changed to keep all in consistence
ObservableCollection<...> list
{
get { return _list; }
set
{
_list = value;
list.OnCollectionChanged += (s, e) =>
{
NotifyPropertyChanged("IsEmptyListVisibility");
}
}
}

Slickgrid - One-click checkboxes?

When I create a checkbox column (through use of formatters/editors) in Slickgrid, I've noticed that it takes two clicks to interact with it (one to focus the cell, and one to interact with the checkbox). (Which makes perfect sense)
However, I've noticed that I am able to interact with the checkbox selectors plugin (for selecting multiple rows) with one click. Is there any way I can make ALL of my checkboxes behave this way?
For futher readers I solved this problem by modifing the grid data itself on click event. Setting boolean value to opposite and then the formatter will display clicked or unclicked checkbox.
grid.onClick.subscribe (function (e, args)
{
if ($(e.target).is(':checkbox') && options['editable'])
{
var column = args.grid.getColumns()[args.cell];
if (column['editable'] == false || column['autoEdit'] == false)
return;
data[args.row][column.field] = !data[args.row][column.field];
}
});
function CheckboxFormatter (row, cell, value, columnDef, dataContext)
{
if (value)
return '<input type="checkbox" name="" value="'+ value +'" checked />';
else
return '<input type="checkbox" name="" value="' + value + '" />';
}
Hope it helps.
The way I have done it is pretty straight forward.
First step is you have to disable the editor handler for your checkbox.
In my project it looks something like this. I have a slickgridhelper.js to register plugins and work with them.
function attachPluginsToColumns(columns) {
$.each(columns, function (index, column) {
if (column.mandatory) {
column.validator = requiredFieldValidator;
}
if (column.editable) {
if (column.type == "text" && column.autocomplete) {
column.editor = Slick.Editors.Auto;
}
else if (column.type == "checkbox") {
//Editor has been diasbled.
//column.editor = Slick.Editors.Checkbox;
column.formatter = Slick.Formatters.Checkmark;
}
}
});
Next step is to register an onClick event handler in your custom js page which you are developing.
grid.onClick.subscribe(function (e, args) {
var row = args.grid.getData().getItems()[args.row];
var column = args.grid.getColumns()[args.cell];
if (column.editable && column.type == "checkbox") {
row[column.field] = !row[column.field];
refreshGrid(grid);
}
});
Now a single click is suffice to change the value of your checkbox and persist it.
Register a handler for the "onClick" event and make the changes to the data there.
See http://mleibman.github.com/SlickGrid/examples/example7-events.html
grid.onClick.subscribe(function(e, args) {
var checkbox = $(e.target);
// do stuff
});
The only way I found solving it is by editing the slick.checkboxselectcolumn.js plugin. I liked the subscribe method, but it haven't attached to me any listener to the radio buttons.
So what I did is to edit the functions handleClick(e, args) & handleHeaderClick(e, args).
I added function calls, and in my js file I just did what I wanted with it.
function handleClick(e, args) {
if (_grid.getColumns()[args.cell].id === _options.columnId && $(e.target).is(":checkbox")) {
......
//my custom line
callCustonCheckboxListener();
......
}
}
function handleHeaderClick(e, args) {
if (args.column.id == _options.columnId && $(e.target).is(":checkbox")) {
...
var isETargetChecked = $(e.target).is(":checked");
if (isETargetChecked) {
...
callCustonHeaderToggler(isETargetChecked);
} else {
...
callCustonHeaderToggler(isETargetChecked);
}
...
}
}
Code
pastebin.com/22snHdrw
Search for my username in the comments
I used the onBeforeEditCell event to achieve this for my boolean field 'can_transmit'
Basically capture an edit cell click on the column you want, make the change yourself, then return false to stop the cell edit event.
grid.onBeforeEditCell.subscribe(function(row, cell) {
if (grid.getColumns()[cell.cell].id == 'can_transmit') {
if (data[cell.row].can_transmit) {
data[cell.row].can_transmit = false;
}
else {
data[cell.row].can_transmit = true;
}
grid.updateRow(cell.row);
grid.invalidate();
return false;
}
This works for me. However, if you're using the DataView feature (e.g. filtering), there's additional work to update the dataview with this change. I haven't figured out how to do that yet...
I managed to get a single click editor working rather hackishly with DataView by calling
setTimeout(function(){ $("theCheckBox").click(); },0);
in my CheckBoxCellEditor function, and calling Slick.GlobalEditorLock.commitCurrentEdit(); when the CheckBoxCellEditor created checkbox is clicked (by that setTimeout).
The problem is that the CheckBoxCellFormatter checkbox is clicked, then that event spawns the CheckBoxCellEditor code, which replaces the checkbox with a new one. If you simply call jquery's .click() on that selector, you'll fire the CheckBoxCellEditor event again due because slickgrid hasn't unbound the handler that got you there in the first place. The setTimeout fires the click after that handler is removed (I was worried about timing issues, but I was unable to produce any in any browser).
Sorry I couldn't provide any example code, the code I have is to implementation specific to be useful as a general solution.

Resources