Custom Delete command does nor mark every row for deletion in MVC Kendo.Grid - kendo-grid

I have a Kendo.Grid() with a custom command and its Click event where I need to mark columns for deletion.
When clicking on the button, only odd rows are marked.
This is logic:
Grid's Custom column:
columns.Command(c => c.Custom("Delete").Click("DeleteRecord"));
DeleteRecord function:
function DeleteRecord(e) {
e.preventDefault(e);
var grid = $("#MyGrid").getKendoGrid();
var row = $(e.target).closest("tr"),
dataItem = grid.dataItem(row);
dataItem.deleted = true;
row.addClass("deleted");
}

I solved that by setting the background-color attribute to red:
row.css("background-color", "red");

Related

Control OnChangeAction default and revert to default when dynamically adding Widget to Google Add-on card

Starting a new question to extend Dynamically Add Widget on user click in Gmail Add-on using CardService Appscript (GAS)
I was able to get this to work on a fairly complex UI card I am designing.
There are two things that I can't seem to control:
The selector after OnChangeAction reverts to the default item, so the user looses the context of their selection. Is there a way to persist the selection when rebuilding the card?
There is no way to setup that the value of the default selected item to force an OnChangeAction event to push its value to the UI on the cards initial load.
Anyone able to use this method to accomplish the above?
I came up with a hack for this that seems to work.
I added a default item to the top of the item list with a label of item0
.addItem("Click here to select an existing item to edit","item0", true)
I also created a cache to cache this label. CacheService.getUserCache().put('itemSelected','item0')
When the item is selected from the dropdown I update the Cache with that items value, e.g. item(n).
I then set up two Widgets within a single function itemManagerCard(e, item) that takes the item I want to change as a parameter.
WidgetOne is the base state of the card where the parameters are undefined
if(item === undefined)
WidgetTwo responds when onModeChange(e) returns the target card with the item parameters I want to change
return itemManagerCard(e, item);
if(item != undefined)
I can then populate WidgetTwo with whatever UI data I want to collect through the function's parameters. Such as:
var editItemNumText = 'You are currently editing ${itemNum}'
function itemManagerCard(e, item) {
var selectItemBodyWidget = CardService.newSelectionInput()
.setType(CardService.SelectionInputType.DROPDOWN)
.setTitle('Which item do you want to edit?')
.setFieldName('editItem');
.setOnChangeAction(CardService.newAction().setFunctionName('onModeChange'))
.addItem("Click here to select an existing Item to edit","item0", true)
.addItem("Item 1","item1", false);
//
if (item != undefined)
let itemNum = CacheService.getUserCache().get('itemNum');
var itemText = `You are currently editing ${itemNum}`;
var itemWidget = CardService.newTextParagraph()
.setText(itemText);
}
function onModeChange(e) {
let itemNum = (e.formInput.editItem);
CacheService.getUserCache().put('itemNum', itemNum);
var item = itemArr[itemNum]
return itemManagerCard(e, item);
}
Major drawback is needing to build and maintain the two separate virtually identical Widgets, which can get messy the more complex it gets.

How to change the text of a tabPanel using GAS

Is it possible to change the text of a page of a tabPanel and/or to setVisible() in a UiApp using GAS?
EDIT-1
To clarify my question :
function doGet()
{
var app = UiApp.createApplication();
var tabPanel = app.createTabPanel().setId('AAA');
var horPanel = app.createHorizontalPanel().setId('XXX').setSize(500, 400);
tabPanel.add(horPanel, 'YYY');
app.add(tabPanel);
return app;
}
I want to change change the text 'YYY' into something else at any time after the user sees the panels.
The individual panels are not available as separate objects, you can't change their properties neither hide them individually so I'm afraid what you are trying won't be possible.
The only thing you can do is select one of them, that's about all.
To get the same functionality I use vertical panels and handlers like in this example... it is entirely composed of "normal" panels and I can do what I want with it...
EDIT : handlers to switch panels :
//Panel Handlers
var pHandler1 = app.createClientHandler()
.forEventSource().setStyleAttribute('color','blue')
.forTargets(mainPanel[0]).setVisible(true)
.forTargets(mainPanel[1],mainPanel[2],mainPanel[3]).setVisible(false)
.forTargets(button[1],button[2],button[3]).setStyleAttribute('color','white')
button[0].addClickHandler(pHandler1)
var pHandler2 = app.createClientHandler()
.forEventSource().setStyleAttribute('color','blue')
.forTargets(mainPanel[1]).setVisible(true)
.forTargets(mainPanel[0],mainPanel[2],mainPanel[3]).setVisible(false)
.forTargets(button[0],button[2],button[3]).setStyleAttribute('color','white')
button[1].addClickHandler(pHandler2)
var pHandler3 = app.createClientHandler()
.forEventSource().setStyleAttribute('color','blue')
.forTargets(mainPanel[2]).setVisible(true)
.forTargets(mainPanel[0],mainPanel[1],mainPanel[3]).setVisible(false)
.forTargets(button[0],button[1],button[3]).setStyleAttribute('color','white')
button[2].addClickHandler(pHandler3)
var pHandler4 = app.createClientHandler()
.forEventSource().setStyleAttribute('color','blue')
.forTargets(mainPanel[3]).setVisible(true)
.forTargets(mainPanel[0],mainPanel[1],mainPanel[2]).setVisible(false)
.forTargets(button[0],button[1],button[2]).setStyleAttribute('color','white')
button[3].addClickHandler(pHandler4)
image of another app using this feature :
I accomplished this not by adding strings to the tab, but used a Label instead. I could use the id of the label later to tweak the content.
var horPanel = app.createHorizontalPanel().setId('XXX').setSize(500, 400);
var horLabel = app.createLabel('YYY').setStyleAttributes({fontWeight: 'bold', color: 'red'}).setId('xxxLabel');
tabPanel.add(horPanel, horLabel);
In the call back:
var callBackHorLabel = app.getElementById('xxxLabel');
callBackHorLabel.setText('ZZZ').setStyleAttributes({color: 'inherit'});
There may be better ways to deal with the CSS of created label to make it match the default label, but I was too lazy to research it. Hence, the fontWeight.

How do I add new elements to a dropdown menu using ajax?

I would like to know how to add new elements to a dropdown menu without refreshing the html page. For example, if I have the drop down menu below:
<select>
<option>existing item 1<option>
<option>existing item 2<option>
<option>existing item 3<option>
<option>add new item<option>
</select>
Any time the user selects "add new item", a text box would pop-up asking the user for input. Then whatever string the user types in the text box, I want that to be saved to the drop down menu without refreshing the page. Of course, the "add new item" option will remain unchanged, so the user can repeat this process as many times as he/she wants.
Thanks for your help in advance.
you can do it using jquery..
$("select").append("<option>Another option</option>")
A non JQuery way is to use the standard JavaScript dom api like so:
This piece uses a prompt as a text popout input. If you want to make it pretty you will have to consider an UI framework.
JavaScript :
var select = document.getElementById('select');
var addNewOption = document.getElementById('addNew');
select.onclick= function(){
if (select.value === 'addNew'){
var text = prompt('New Value');
if (text){
var label = text;
var value = text;
var newOption = document.createElement('option');
newOption.innerHTML = label;
newOption.value = value;
select.insertBefore(newOption, addNewOption);
select.value = value;
}
}
};
Demo here:
http://jsbin.com/sufug/2/edit

Can't add new object to KendoUI grid if filter is applied to any column

I use KendoUI grid with popup edit mode. After applying filter to any column it is not possible to add new object correctly. Pressing Add button many times does not show edit popup. But after clearing the filter empty objects are shown in the grid.
Is there any workaround?
I found a workaround. Instead of standard Add button use toolbar template in which add link "Add" with custom handler triggering grid add. In that handler check if filtering is used on grid and if so store current filtering to a var and remove filtering. Also bind to grid "save" and "cancel" events handlers which will apply previous filtering after adding new object (or cancelling).
<kendo:grid-toolbarTemplate>
<div>
<a class="k-button k-button-icontext" onclick="addItemHandler()">Add</a>
...
var gridFilter;
function addItemHandler() {
var table = $("#myGrid").data("kendoGrid");
gridFilter = table.dataSource.filter();
if (gridFilter) {
table.dataSource.filter(null);
}
table.addRow();
}
function gridSavedHandler(e) {
restoreFilter(e.sender);
}
function gridEditCanceledHandler(e) {
e.preventDefault();
e.sender.cancelChanges();
restoreFilter(e.sender);
}
function restoreFilter(table) {
if (gridFilter) {
table.dataSource.filter(gridFilter);
gridFilter = null;
}
}
$(document).ready(pageInitHandler);
function pageInitHandler() {
var table = $("#myGrid").data("kendoGrid");
table.bind("save", gridSavedHandler);
table.bind("cancel", gridEditCanceledHandler);
}
Workaround is complicated one but really works.

How to make style of SubmitButton consistent with Button style in Google App Script UI?

I am building an UI form via code (not using the UI Builder) and I noticed that the SubmitButton class style is not consistent with the Button class look & feel.
Would you know any way to adjust the look & feel of either the Button class or the SubmitButton class to make them similar.
I noticed that the Button has a call setStylePrimaryName, setStyleName etc... but the documentation is vague - says: "This is useful for debugging"!!!
Any suggestion?
See below screenshoot, first button is of class Button, second button is SubmitButton. You can see they don't even align.
You can style (a button) the way you want with setStyleAttribute
var _btn= {
"background-color":"none",
"background":"none",
"width":"80px",
"height":"24px",
"border":"None",
"font-family":"hobo std",
"font-size":"0.9em",
"color":"3f3f3f",
"opacity":"1",
}
....
....
var closeb = app.createButton("Submit");
library.applyCSS(submit,_btn);
....
....
And in your library you have the function (credits to James Fereira)
function applyCSS(element, style){
for (var key in style){
element.setStyleAttribute(key, style[key]);
}
}
I resolved this cosmetic dilemma by using multiple submit buttons in the same form. I experimented with CSS sans success; the Submit & Reset buttons are two unique beasts in the world of button widgets.
Here is some working code
that demonstrates a multiple page form where each page uses three submitButton's to advance back and forth doing multiple doPost()'s.
// Muliple page form using Google Apps Script
function doGet(eventInfo) {return GUI(eventInfo)};
function doPost(eventInfo) {return GUI(eventInfo)};
function GUI (eventInfo) {
var n = (eventInfo.parameter.state == void(0) ? 0 : parseInt(eventInfo.parameter.state));
var ui = ((n == 0)? UiApp.createApplication() : UiApp.getActiveApplication());
var Form;
switch(n){
case 0: {
Form = getForm(eventInfo,n); // Use identical forms for demo purpose only
} break;
case 1: {
Form = getForm(eventInfo,n); // In reality, each form would differ but...
} break;
default: {
Form = getForm(eventInfo,n) // each form must abide by (implement) the hidden state variable
} break;
}
return ui.add(Form);
};
function getForm(eventInfo,n) {
var ui = UiApp.getActiveApplication();
// Increment the ID stored in a hidden text-box
var state = ui.createTextBox().setId('state').setName('state').setValue(1+n).setVisible(true).setEnabled(false);
var H1 = ui.createHTML("<H1>Form "+n+"</H1>");
var H2 = ui.createHTML(
"<h2>"+(eventInfo.parameter.formId==void(0)?"":"Created by submission of form "+eventInfo.parameter.formId)+"</h2>");
// Add three submit buttons to go forward, backward and to validate the form
var Next = ui.createSubmitButton("Next").setEnabled(true).setVisible(true);
var Back = ui.createSubmitButton("Back").setEnabled(n>1).setVisible(true);
var Validate = ui.createSubmitButton("Validate").setEnabled(n>0).setVisible(true);
var Buttons = ui.createHorizontalPanel().add(Back).add(Validate).add(Next);
var Body = ui.createVerticalPanel().add(H1).add(H2).add(state).add(Buttons).add(getParameters(eventInfo));
var Form = ui.createFormPanel().setId((n>0?'doPost[':'doGet[')+n+']').add(Body);
// Add client handlers using setText() to adjust state prior to form submission
// NB: Use of the .setValue(val) and .setValue(val,bool) methods give runtime errors!
var onClickValidateHandler = ui.createClientHandler().forTargets(state).setText(''+(parseInt(n)));
var onClickBackHandler = ui.createClientHandler().forTargets(state).setText(''+(parseInt(n)-1));
Validate.addClickHandler(onClickValidateHandler);
Back.addClickHandler(onClickBackHandler);
// Add a client handler executed prior to form submission
var onFormSubmit = ui.createClientHandler()
.forTargets(state).setEnabled(true) // Enable so value gets included in post parameters
.forTargets(Body).setStyleAttribute("backgroundColor","#EEE");
Form.addSubmitHandler(onFormSubmit);
return Form;
}
function getParameters(eventInfo) {
var ui = UiApp.getActiveApplication();
var panel = ui.createVerticalPanel().add(ui.createLabel("Parameters: "));
for( p in eventInfo.parameter)
panel.add(ui.createLabel(" - " + p + " = " + eventInfo.parameter[p]));
return panel;
}
The code uses a single "hidden" state (here visualized in a TextBox) and multiple SubmitButton's to allow the user to advance forward and backward through the form sequence, as well as to validate the contents of the form. The two extra SubmitButton's are "rewired" using ClientHandler's that simply modify the hidden state prior to form submission.
Notes
Note the use of the .setText(value) method in the client handler's. Using the Chrome browser I get weird runtime errors if I switch to either of the TextBox's .setValue(value) or .setValue(value, fireEvents) methods.
I tried (unsuccessfully) to implement this logic using a Script Property instead of the hidden TextBox. Instead of client handlers, this requires using server handlers. The behavior is erratic, suggesting to me that the asynchronous server-side events are occurring after the form submission event.