At the moment, the focus remains on the cell. It should be in the input so the user does not have to perform an extra action (say, click with the mouse) in order to edit data.
This also applies to inserting a new row - the first cell should be focused.
Hello Eric,
For that, please Follow the other request you opened: https://feedback.telerik.com/blazor/1454022-incell-editing-keyboard-navigation-to-be-closer-to-excel-more-flexibility-on-opening-cells-for-editing-and-moving-between-them-with-fewer-actions
You could try using a Template for every cell and handling the keydown/keypress event to store the current text and open another cell for editing through the grid state, although I don't imagine it will be an easy implementation.
Regards,
Marin Bratanov
Progress Telerik
Hi Marin,
This seems like a good start but I don't think it's enough. How do you then move from one cell to another in edit mode? Say you edit the first cell then when you press tab it should save that value and move on to the next cell. There should be some sort of key listener, I think.
Can you elaborate further?
A workaround can be a small JS function that finds the first (or any desired) input and focuses it, that you can call from the grid events when needed - e.g., in the OnEdit, or from OnClick of the Add button, or when you alter the grid state.
<script>
function focusInputInEditableCell() {
setTimeout(function () {
// you may want to tweak this logic to look more carefully at inserted items, especially when editing
// of if you have unediable columns at the start of the grid - then there will be more than one editable cell
var currCell = document.querySelector(".k-grid-edit-cell");
if (currCell) {
var firstInput = currCell.querySelector("input");
if (firstInput && firstInput.focus) {
firstInput.focus();
}
}
}, 100); // you may need to increase this timeout if you have a laggy server connection, but then you may have other issues too
}
</script>
@inject IJSRuntime _js
<TelerikButton OnClick="@EditItemFour">Put item 4 in Edit mode</TelerikButton>
<TelerikGrid @ref="@GridRef" Data=@MyData EditMode="@GridEditMode.Incell" Pageable="true" Height="500px"
OnUpdate="@UpdateHandler" OnEdit="@EditHandler" OnDelete="@DeleteHandler" OnCreate="@CreateHandler">
<GridToolBar>
<GridCommandButton Command="Add" Icon="add" OnClick="@FocusFirstInput">Add Employee</GridCommandButton>
</GridToolBar>
<GridColumns>
<GridColumn Field=@nameof(SampleData.ID) Title="ID" />
<GridColumn Field=@nameof(SampleData.Name) Title="Name" />
<GridCommandColumn>
<GridCommandButton Command="Save" Icon="save" ShowInEdit="true">Update</GridCommandButton>
<GridCommandButton Command="Delete" Icon="delete">Delete</GridCommandButton>
</GridCommandColumn>
</GridColumns>
</TelerikGrid>
@code {
//workaround start
async Task FocusFirstInput()
{
//workaround for focusing
await _js.InvokeVoidAsync("focusInputInEditableCell");
}
async Task EditHandler(GridCommandEventArgs args)
{
SampleData item = (SampleData)args.Item;
await FocusFirstInput();
}
async Task EditItemFour()
{
var currState = GridRef.GetState();
// reset any current insertion and any old edited items. Not mandatory.
currState.InsertedItem = null;
// add item you want to edit to the state, then set it to the grid
SampleData itemToEdit = SampleData.GetClonedInstance(MyData.Where(itm => itm.ID == 4).FirstOrDefault());
// you can alter values here as well (not mandatory)
//itemToEdit.Name = "Changed from code";
currState.OriginalEditItem = itemToEdit;
currState.EditField = "Name";
// for InCell editing, you can use the EditField property instead
await GridRef.SetState(currState);
//workaround for focusing
await FocusFirstInput();
}
//workaround end
TelerikGrid<SampleData> GridRef { get; set; }
async Task UpdateHandler(GridCommandEventArgs args)
{
string fieldName = args.Field;
object newVal = args.Value; // you can cast this, if necessary, according to your model
SampleData item = (SampleData)args.Item; // you can also use the entire model
// perform actual data source operation here through your service
// if the grid Data is not tied to the service, you may need to update the local view data too
var index = MyData.FindIndex(i => i.ID == item.ID);
if (index != -1)
{
MyData[index] = item;
// this copies the entire item, consider altering only the needed field
}
}
async Task CreateHandler(GridCommandEventArgs args)
{
SampleData item = (SampleData)args.Item;
// perform actual data source operation here through your service
// if the grid Data is not tied to the service, you may need to update the local view data too
item.ID = MyData.Count + 1;
MyData.Insert(0, item);
}
async Task DeleteHandler(GridCommandEventArgs args)
{
SampleData item = (SampleData)args.Item;
// perform actual data source operation here through your service
// if the grid Data is not tied to the service, you may need to update the local view data too
MyData.Remove(item);
}
// in a real case, keep the models in dedicated locations, this is just an easy to copy and see example
public class SampleData
{
public int ID { get; set; }
public string Name { get; set; }
// example of comparing stored items (from editing or selection)
// with items from the current data source - IDs are used instead of the default references
public override bool Equals(object obj)
{
if (obj is SampleData)
{
return this.ID == (obj as SampleData).ID;
}
return false;
}
// define constructors and a static method so we can deep clone instances
// we use that to define the edited item - otherwise the references will point
// to the item in the grid data sources and all changes will happen immediately on
// the Data collection, and we don't want that - so we need a deep clone with its own reference
// this is just one way to implement this, you can do it in a different way
public SampleData()
{
}
public SampleData(SampleData itmToClone)
{
this.ID = itmToClone.ID;
this.Name = itmToClone.Name;
}
public static SampleData GetClonedInstance(SampleData itmToClone)
{
return new SampleData(itmToClone);
}
}
public List<SampleData> MyData { get; set; }
protected override void OnInitialized()
{
MyData = new List<SampleData>();
for (int i = 0; i < 50; i++)
{
MyData.Add(new SampleData()
{
ID = i,
Name = "Name " + i.ToString()
});
}
}
}
Regards,
Marin Bratanov
Progress Telerik