Hello @Dennis, and thanks for the test case!
First I will point each issue you had with a possible way to address it, then I will post a suggestion of how your example could look like with these implemented.
Originally Posted by
Dennis
1. loop through all the records in the grid (or preferrably all the dirty records) to save data in the db. I could only find how to loop through the selected ones by using selection model. but in my case users may edit data in several rows and not necessarily have them selected.
You want the grid store's
dirty records. There are several examples which shows some ways you can sync stores to the server. Here are some:
-
GridPanel > Saving_Variations > HttpHandler
-
GridPanel > Saving_Variations > StoreCustomLogic
-
GridPanel > Saving_Variations > StoreEvents
-
GridPanel > Saving_Variations > WebService
-
GridPanel > Update > SqlDataSource
-
GridPanel > Update > AutoSave
One particular approach to saving the grid data would be highlighted in this example:
-
GridPanel > Update > Batch
That is, just submitting the changed data. If you are not interested in
new rows (if your grid won't allow adding new records), you may want just
getUpdatedRecords()
instead of
getChangedData()
in the direct event parameter.
Originally Posted by
Dennis
2. I could not make the buttons disappear, I was only able to disable them. Setting .Visible="false" seems to not do anything.
What you're missing here is that you are just setting properties/configs to already rendered components. They are already rendered, they won't re-read those until you re-render the component at all. What you want here is to call their respective setter methods. So change
this.btnSaveChanges.Hidden = true;
to
this.btnSaveChanges.Hide();
and you should get what you want.
You may notice just setting the config in some situations just works, and that would be true. But that's not always true and it may be confuse to guess which components get or not the "auto-call-setter" feature. So best rule of thumb would be to try to call the setter itself when there's one available.
.Hide(), .Show(), .Disable(), .Enable()
, or when there's client-side setter but not server-side, say, for a
Html setting, you could
this.MyComponent.Call("setHtml", "my inner content");
. true/false and integer numbers are valid second arguments you can pass to the
.Call()
method.
Originally Posted by
Dennis
3. Not sure how to apply different style to editable/read-only fields
One way through this is to give the editable cells (or the read-only ones) a CSS class. Just to "mark" them. Then you can draw a javascript function to loop throughout them and apply another CSS class with the effect you want (or just set the desired CSS styling). Likewise, another single "dim" method could step thru the elements with that "marker class" and de-apply the effect class or styles.
Adapted sample
The sample below should comply to your requirements, with some remarks:
- When you click 'save' we are just getting and showing back the submitted value, you should parse them back accordingly (the
batch save example should help with other details like clearing the 'dirty' state if desired and mapping it to an actual C# structure).
- The "save" button is initially disabled. The grid store will enable and disable it as changes are triggered -- so that it is always disabled if there's nothing to submit.
- The visual effects on editable cells are toggled by the save button's show/hide event.
- The "editability" of cells in turn, are defined by the save button's hidden state. Technically the editable cells will always trigger edit when clicked, but they will just be denied until the "save" button is displayed -- "signalling" the page it is in "edit mode".
- The "cancel" handler just calls again the data binding method, so the store is replaced (actually refreshed with whatever data is in the server at the moment it is called) with a whole new set of data. You can alternatively cycle thru the store data records and
discard()
the changes to every
dirty
record, but then new or removed records would need additional specific logic (but no server round-trip would be required when cancelling changes).
- I have merged the two code blocks into a single block, with embedded code-behind, should be easier to copy-paste, and namespace-agnostic.
<%@ Page Language="C#" %>
<!DOCTYPE html>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (!X.IsAjaxRequest)
{
this.BindData();
}
}
private void BindData()
{
this.StoreCombo.DataSource = TransferStatus.GetAll();
this.StoreCombo.DataBind();
this.Store1.DataSource = Client.GetAll();
this.Store1.DataBind();
}
public class TransferStatus
{
public int ID { get; set; }
public string Name { get; set; }
public static List<TransferStatus> GetAll()
{
return new List<TransferStatus>
{
new TransferStatus {ID = 1, Name = "Pending"},
new TransferStatus {ID = 4, Name = "Accepted"},
new TransferStatus {ID = 7, Name = "Rejected"}
};
}
}
protected void SaveChangesButton_Click(object sender, DirectEventArgs e)
{
var changes = e.ExtraParams["data_changes"];
if (changes != null)
{
X.Toast("Got these records to update in database: " + changes);
}
else
{
X.Toast("No records to update.");
}
this.btnEditGrid.Enable();
this.btnSaveChanges.Hide();
}
protected void EditGridButton_Click(object sender, DirectEventArgs e)
{
this.btnEditGrid.Hide();
this.btnSaveChanges.Show();
this.btnCancelEdit.Show();
}
protected void CancelEditButton_Click(object sender, DirectEventArgs e)
{
BindData();
this.btnEditGrid.Show();
this.btnSaveChanges.Hide();
this.btnCancelEdit.Hide();
}
public class Client
{
public int ID { get; set; }
public string Name { get; set; }
public string Number { get; set; }
public string Name_Overlay { get; set; }
public string Number_Overlay { get; set; }
public int TransferStatus_ID { get; set; }
public string Note { get; set; }
public static List<Client> GetAll()
{
List<Client> clntList = new List<Client>();
clntList.Add(new Client() { ID = 10, Name = "Client1", Number = "01", Note = "Client 1 Note", Number_Overlay = "01", Name_Overlay = "Client1", TransferStatus_ID = 1 });
clntList.Add(new Client() { ID = 11, Name = "Client2", Number = "02", Note = "Client 2 Note", Number_Overlay = "02", Name_Overlay = "Client2", TransferStatus_ID = 7 });
return clntList;
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<script type="text/javascript">
var template = 'color:{0};';
var change = function (value, meta) {
meta.style = Ext.String.format(template, (value > 0) ? "green" : "red");
return value;
};
var pctChange = function (value, meta) {
meta.style = Ext.String.format(template, (value > 0) ? "green" : "red");
return value + "%";
};
var statusRenderer = function (value) {
var r = App.StoreCombo.getById(value);
if (Ext.isEmpty(r)) {
return "";
}
return r.data.Name;
};
var highlightEditable = function () {
document.querySelectorAll(".editable-cell").forEach(function (el) {
el.classList.add("editable-cell-highlight");
});
}
var dimEditable = function () {
document.querySelectorAll(".editable-cell").forEach(function (el) {
el.classList.remove("editable-cell-highlight");
});
}
</script>
<style type="text/css">
.editable-cell { }
.editable-cell-highlight {
background-color: #f9ffd77f;
}
</style>
<title>62941 - Disable Grid Cell Editing & more</title>
</head>
<body>
<form id="form1" runat="server">
<ext:ResourceManager runat="server" />
<ext:Store ID="StoreCombo" runat="server">
<Model>
<ext:Model runat="server" IDProperty="ID">
<Fields>
<ext:ModelField Name="ID" />
<ext:ModelField Name="Name" />
</Fields>
</ext:Model>
</Model>
</ext:Store>
<ext:GridPanel
ID="GridPanel1"
runat="server"
Title="Editable GridPanel"
Width="1000">
<CustomConfig>
<ext:ConfigItem Name="editingDisabled" Value="true" Mode="Raw" />
</CustomConfig>
<Store>
<ext:Store ID="Store1" runat="server">
<Model>
<ext:Model runat="server" IDProperty="ID">
<Fields>
<ext:ModelField Name="ID" Type="Int" />
<ext:ModelField Name="Name" />
<ext:ModelField Name="Number" />
<ext:ModelField Name="NumberNew" />
<ext:ModelField Name="NameNew" />
<ext:ModelField Name="Note" />
<ext:ModelField Name="TransferStatus_ID" Type="Int" />
</Fields>
</ext:Model>
</Model>
<Listeners>
<DataChanged Handler="if (App.btnSaveChanges) App.btnSaveChanges.setDisabled(!this.isDirty())" />
</Listeners>
</ext:Store>
</Store>
<ColumnModel runat="server">
<Columns>
<ext:Column runat="server" Text="Name" DataIndex="Name" Flex="1">
</ext:Column>
<ext:Column runat="server" Text="Number" DataIndex="Number" Flex="1">
</ext:Column>
<ext:Column runat="server" Text="Name New" DataIndex="NameNew" Flex="1">
<Editor>
<ext:TextField runat="server" />
</Editor>
</ext:Column>
<ext:Column
runat="server"
Text="Number New"
DataIndex="NumberNew"
Flex="1"
TdCls="editable-cell">
<Editor>
<ext:TextField runat="server" />
</Editor>
</ext:Column>
<ext:Column
runat="server"
Text="Note"
DataIndex="Note"
Flex="1"
TdCls="editable-cell">
<Editor>
<ext:TextField runat="server" />
</Editor>
</ext:Column>
<ext:Column
runat="server"
DataIndex="TransferStatus_ID"
Text="Status"
Width="200"
TdCls="editable-cell">
<Renderer Fn="statusRenderer"></Renderer>
<Editor>
<ext:ComboBox ID="cbStatuses" StoreID="StoreCombo" DisplayField="Name" ValueField="ID" runat="server" />
</Editor>
</ext:Column>
</Columns>
</ColumnModel>
<TopBar>
<ext:Toolbar runat="server">
<Items>
<ext:Button
ID="btnEditGrid"
runat="server"
Text="Edit Grid"
OnDirectClick="EditGridButton_Click" />
<ext:Button
ID="btnSaveChanges"
runat="server"
Text="Save Changes"
AutoLoadingState="true"
Disabled="true"
Hidden="true">
<DirectEvents>
<Click OnEvent="SaveChangesButton_Click">
<ExtraParams>
<ext:Parameter name="data_changes" Value="function() { return App.Store1.getChangedData(); }" Mode="Raw" />
</ExtraParams>
</Click>
</DirectEvents>
<Listeners>
<Hide Fn="dimEditable" />
<Show Fn="highlightEditable" />
</Listeners>
</ext:Button>
<ext:Button
ID="btnCancelEdit"
runat="server"
Text="Cancel"
AutoLoadingState="true"
OnDirectClick="CancelEditButton_Click"
Hidden="true" />
</Items>
</ext:Toolbar>
</TopBar>
<Listeners>
<BeforeEdit Handler="if (App.btnSaveChanges.hidden === true) return false" />
</Listeners>
<SelectionModel>
<ext:CheckboxSelectionModel runat="server" Mode="Multi" />
</SelectionModel>
<View>
<ext:GridView runat="server"></ext:GridView>
</View>
<Plugins>
<ext:CellEditing runat="server" ClicksToEdit="1" />
</Plugins>
</ext:GridPanel>
</form>
</body>
</html>
Hope this helps!