SAPUI5 Table Cell Custom Control Binding - binding

I was wondering if someone could shed some light on the issue I am having. I can't seem to get the data model updated when I use my custom input control in a cell. When using the standard sap.m.Input, updates to the data model are performed properly.
Here is the Plunker: https://plnkr.co/edit/GxE6F8DbW9DHqWjpfdO0
I have overrriden the getter for the 'value' properly to get the data from the entry field. Debugging in Chrome shows that this function is not called which I believe is the reason the data model is not updated.
getValue: function() {
var me = this;
var ef = sap.ui.getCore().byId(me.sId + '-ef');
return ef.getProperty('value');
}
Basically, there is a table with two rows and four columns. The first column uses my custom input. The second column has a custom button with an aggregation (additionalParameters) containing the bound data used in the first column. The third column uses a standard sap.m.Input and lastly the fourth column is again a custom button with the 'additionalParameters' aggregation bound to the data in the third column. When any of the buttons are pressed it fires an event which in turn updates the 'Sample' input field.
So, when I type something in the first column, tab out and press the respective 'PB1' button, only the original data from the model appears in the 'Sample' input field. If I type something in the third column, tab out of the field and press the respective 'PB2' button, the 'Sample' input field is properly set by the newly entered data implying the data model has been updated.
Edit
I can get the value from the Input no problem. Maybe I can clarify. The 'MyCustomInput' in cell 1 has 'value' bound to 'list>colOne'. The 'MyCustomButton' in cell 2 has the 'text' of the first item in aggregation 'additionalParameters' bound to the same 'list>colOne'. Any text entered into MyCustomInput does not update the model and thus does not update the 'additionalParameters' item. If I do the exact same thing but use a standard Input instead of MyCustomInput it works. As can be seen with the Input in Cell 3 and the button in Cell 4.
Thank you

May be you can provide more information. We have a simple example here
http://jsbin.com/yukujag/edit?html,js,output and it works on with getValue and setValue
sap.ui.define(['sap/m/Input', 'sap/m/Button', 'sap/m/VBox'],
function(Input, Button, VBox) {
Input.extend('MyInput', {
value: 'abc',
renderer: {},
getValue: function() {
return this.value;
},
setValue: function(v) {
this.value = v;
},
});
var oInput = new MyInput();
var oBox = new VBox({
items: [
oInput,
new Button({
text: 'Test',
press: function() {
alert(oInput.getValue());
}
})
]
})
oBox.placeAt('content');
});
Thanks
-D

Related

How to set different select items in Vaadin Grid Pro's editComponent based on row item

I have Grid Pro displaying Products. A single column is configured as an EditColumn of type 'select' (dropdown/combobox). I'm trying to set the items for this component based on the Product of that row. Is this possible using the 'select' editColumn?
I tried to achieve what I want using the grid's 'addCellEditStartedListener' event, but I can't seems to access the editComponent from CellEditStartedEvent..
thx!
Yes, the this is missing feature in CellEditStartedEvent. As an alternative you can use custom editor in your edit column, as then you have reference to the field you are using, see example
// Use custom editor
EmailField emailField = new EmailField();
emailField.setWidth("100%");
emailField.addThemeName("grid-pro-editor");
grid.addEditColumn(Person::getEmail)
.custom(emailField, (item, newValue) -> {
item.setEmail(newValue);
}).setHeader("E-mail ");
// Use edit started listener to set the field conditionally enabled
grid.addCellEditStartedListener(event -> {
if (!event.getItem().isSubscriber()) {
emailField.setReadOnly(true);
} else {
emailField.setReadOnly(false);
}
});
Full code here: https://cookbook.vaadin.com/grid-pro-conditional-edit

Sorting data in a sheet with added information Google Sheets

My work has a Google Form where different information is inputted. All this information is then automatically put into a Google Sheet. We will call it "All data sheet".
"All data sheet" has multiple sheets in it, one with all of the data and then one for each type of data which needs to be given to different people. One of those is called 'Caretaker'.
I then have a second Google Sheet (example called 'Sorting') that pulls everything from the 'Caretaker' sheet onto 'Import_range'.
This allows the caretaker to see everything that needs fixing with the oldest thing at the top and the newest at the bottom.
The caretaker would like the newest at the top.
I can easily make another sheet (see 'Sorted') that uses the sort function to put the newest at the top.
However, he would also like another column where he can either check a box to show it's done or write an x.
When new data appears, the checked box does not move down.
Is there any way to sort the data but also have an input column which stays with the sorted data?
Link to example.
You have to use Google Apps Script.
Try this:
To start, go to Tools and click Script editor.
Delete the code in Code.gs
Paste the code provided below and save
Refresh your Spreadsheet and Custom Menu will pop up in the Menu
Go To Custom Menu and Click Update Sorted Sheet
First execution will require user's authorization. Once you authorized the script, make sure to rerun the Custom Menu.
The code below will create a Custom Menu in your Spreadsheet. Clicking the custom menu will execute a function that will update the Sorted Sheet and retain its checkbox values.
I also added comments to explain the function of each line in the code.
Code:
function updateSorted() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName("Import_range");
var sortedSh = ss.getSheetByName("Sorted");
/* Use this if the Import_range is from different spreadsheet
var iSS = SpreadsheetApp.openById("Insert Sheet ID here");
var sh = iSS.getSheetByName("Insert Sheet name here");
and comment the var sh = ss.getSheetByName("Import_range"); above*/
/*
Check if the Sorted Sheet has data.
If true, compare Sorted Sheet and Import_range data
else, copy Import_range data to Sorted Sheet.
*/
if(sortedSh.getLastRow() > 1){
var sData = sortedSh.getRange(2, 1, sortedSh.getLastRow()-1, 5).getValues(); //remove unnecessary data
var sDataFiltered = sData.filter(e => e[4]); //get Date column of Sorted sheet
var sDates = sortedSh.getRange(2, 5, sortedSh.getLastRow()-1, 1).getValues().flat();
var sDatesFiltered = sDates.filter((a) => a); //remove unnecessary data
var importDates = sh.getRange(2, 4, sh.getLastRow()-1, 1).getValues().flat(); //get Date column of Import_range
//convert dates to String format
var arr1 = sDatesFiltered.map( dateString => String(dateString))
var arr2 = importDates.map( dateString => String(dateString))
var difference = arr2.filter(x => !arr1.includes(x)); //get the difference between arr1 and arr2
difference.forEach(dates => {
var index = arr2.indexOf(dates); //get new entry position in Import_range
var newEntry = sh.getRange(index+2, 1, 1, 4).getValues().flat(); //get row data of new entry from Import_range
newEntry.unshift(false); //append false in the beggining of the array
sDataFiltered.push(newEntry); //append new entry to sDataFiltered array
})
var range = sortedSh.getRange(2, 1, sDataFiltered.length, 5);
range.setValues(sDataFiltered); //set the values of Sorted sheet using the sDataFiltered array as data
sortedSh.getRange(2, 1, sDataFiltered.length, 1).insertCheckboxes(); //get the checkbox range and insert checkbox
range.sort({column: 5, ascending: false}); //sort the data by Date column
}else{
var range = sh.getRange(2, 1, sh.getLastRow()-1, 4);
var data = range.getValues();
data.forEach(row => {
row.unshift(false)
})
var sortedRange = sortedSh.getRange(2, 1, data.length, 5);
sortedRange.setValues(data);
sortedSh.getRange(2, 1, data.length, 1).insertCheckboxes();
sortedRange.sort({column: 5, ascending: false});
}
}
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Custom Menu')
.addItem('Update Sorted Sheet', 'updateSorted')
.addToUi();
}
Examples:
Populating Empty Sorted Sheet:
Updating Import_range sheet, clicking checkboxes and updating Sorted Sheet:
Implementing Time Driven Triggers:
Open your Apps Script project.
At the left, click Triggers alarm.
At the bottom right, click Add Trigger.
Select and configure the type of trigger you want to create.
Click Save.
For time driven, your trigger setup should somehow look like this:
The example trigger above will update the sheet every minute. The down side of using time driven trigger is the quota limit. Gmail accounts are limited to 90 minutes of total runtime. Exceeding quotas will result to errors. See Quotas for Google Services.
Using Buttons: Alternative to Custom Menu
To create a user friendly button in your Sheet
Go to Insert -> Drawing
Draw the desired button shape and style.
Click Save and Close
Move the button to your desired position
Right click, click the 3 vertical dots and select Assign script
Type updateSorted and click OK
Click the button to run
Note: If you decided to use buttons and want to remove the Custom Menu in your sheet, just remove the onOpen function in your Apps Script.
References:
Google Apps Script on Sheets
Custom Menu
Simple Triggers
Class Sheet
Class Range
Class Spreadsheet
Installable Trigger

Highcharts: how to remove selected annotation (which was dynamically created)?

I have this code https://jsfiddle.net/delux123/62Lmskbx/11/ where user can draw circle, segment and arrow-segment. When each annotation is selected, there is a "delete" button available, which should normally delete the selected annotation.
But this does not works! I tried the following ways for removing them:
1 ) using thischart.currentAnnotation.destroy() will delete the annotation (works for all three types) but then all the further actions stops from working
document
.querySelectorAll('.highcharts-popup-annotations .deletebutton')[0]
.addEventListener(
'click',
function() {
thischart.currentAnnotation.destroy(); //this stops further drawing
thischart.annotationsPopupContainer.style.display = 'none';
}
);
2 ) using deletion by ID thischart.removeAnnotation(thischart.currentAnnotation.options.id) does not works, since the annotations are created dynamically and they do not have IDs assigned to them.
document
.querySelectorAll('.highcharts-popup-annotations .deletebutton')[0]
.addEventListener(
'click',
thischart.removeAnnotation(thischart.currentAnnotation.options.id); //this requires elements to have IDs (which they do not have)
thischart.annotationsPopupContainer.style.display = 'none';
}
);
For the second approach, I even tried to intersect the drawing and to assign a random string as an ID (since the reason that deletion by id does not works, is because the ID is undefined). So under navigation -> bindings I added the object:
circleAnnotation: {
start: function(e) {
var navigation = this.chart.options.navigation;
return this.chart.addAnnotation(
Highcharts.merge({
id: randomStr() //this is a method that generates random string
},
navigation
.annotationsOptions,
navigation
.bindings
.circleAnnotation
.annotationsOptions
)
);
}
}
The both approaches are not working.
You can pass a direct annotation object to the removeAnnotation method:
thischart.removeAnnotation(thischart.currentAnnotation);
Live demo: https://jsfiddle.net/BlackLabel/5ycf3s4o/
API Reference: https://api.highcharts.com/class-reference/Highcharts.Chart#removeAnnotation

Vaadin grid - change component column in one row only

I have a grid with several columns. For three columns i used the column renderer. Each of the columns contains one button.
If i click one of those buttons, i want to replace the three buttons in that specific row with two other buttons. All the other rows should not be affected. Is this possible in a Vaadin grid?
Components in different columns don't know each other, as they are all defined in a separate scope (in the componentRenderer of their own column. You cannot define the Button outside of the componentRenderer as you found out in another question today). So the "obvious" solution won't work, where you add a clickListener on the Button to directly change the other buttons.
If you had one column with 3 Buttons inside then this would be much easier.
There is a way, but I see this more as a hack than as a solution. Because you need some extra implementation in the item class for this to work.
In the ComponentRenderer, you can add an if-statement where you look at some value of the item. In one case, you'll render button 1, in the other case you'll render the other button. And in the click listeners of the button you change that value in the item and refresh the dataprovider, so the componentRenderer is invoked again. It will now see the value on the item has changed, therefore displaying some other Button.
Here is some code to show what I mean:
// grid item class
public class Foo {
private boolean buttonPressed = false;
public Foo(){
}
public isButtonPressed(){
return buttonPressed;
}
public setButtonPressed(boolean buttonPressed){
this.buttonPressed = buttonPressed;
}
}
// adding of button columns
// do this 3 times for a test of your scenario.
grid.addComponentColumn(item -> {
if(!item.isButtonPressed()){
return new Button("Before Button was Pressed", click -> {
item.setButtonPressed(true);
grid.getDataProvider().refresh(item);
});
} else {
return new Button("Button was Pressed", click -> {
item.setButtonPressed(false);
grid.getDataProvider().refresh(item);
})
}
})

JQGrid ContextMenu - Dynamic Menus

I have a page, which is used for building queries and running them against different entities (Kind of a query builder/generic search).
The results are displayed in JQGrid, so effectively the same grid will be used for rendering results from different entities.
This results grid has to support context menus, which will differ for each entity. So I need a way to change the context menu as per the entity. Each entity may have different number of menu items in context menu and each item may respond in a different manner (sometimes an alert, sometimes an action spawning in a different tab).
Rendering different menus (through li) is not an issue but attaching the methods to the li is proving to be a challenge. Any pointers will be highly appreciated.
I am using jquery.contextmenu-ui.js .
Following is from a sample that I picked from their (JQGrid) site
function initGrid() {
$("#EntityGrid").contextMenu('cMenu'
,{
bindings: { /* I would like to avoid this and pass all the actions to one method*/
'edit': function (t) {
editRow();
},
'add': function (t) {
addRow();
},
'del': function (t) {
delRow();
}
},
onContextMenu: function (event, menu) {
var rowId = $(event.target).parent("tr").attr("id")
var grid = $("#EntityGrid");
grid.setSelection(rowId);
return true;
}
}
);
}
Thanks,
Avinash
You can use onShowMenu callback of contextMenu instead of static binding using bindings. In the same way the menuId used as the first parameter of contextMenu could be the id of dynamically created div with empty <ul>. The onShowMenu has the form
onShowMenu: function (e, $menu) {
// here one can clear `<ul>` child of $menu
// and append it with "<li>" items
return $menu;
}
In the answer you will find an example of the code which build menu dynamically.

Resources