-
Data Grids / Data Management
-
Data Grid
- Overview
-
Data Binding
-
Filtering
- Sorting
-
Editing
-
Grouping
-
Selection
- Focused Row
- Paging
-
Scrolling
-
Columns
-
Master-Detail
-
Data Summaries
-
Drag & Drop
-
Export to PDF
-
Export to Excel
- Appearance
-
Customization
- State Persistence
-
Adaptability
-
Keyboard Navigation
- Right-To-Left Support
-
Tree List
- Overview
-
Data Binding
-
Filtering
- Sorting
-
Editing
-
Selection
- Focused Row
- Paging
-
Columns
- Drag & Drop
- State Persistence
- Adaptability
-
Keyboard Navigation
-
Card View
-
Pivot Grid
- Overview
-
Data Binding
-
Field Management
-
Data Summaries
- Drill Down
- Filtering
-
Scrolling
-
Export to Excel
- Chart Integration
- Customization
- State Persistence
-
Filter Builder
-
-
Data Visualization
-
Charts
- Overview
-
Data Binding
-
Common Concepts
-
Axis
-
Aggregation
-
Tooltips
-
Selection
-
Customization
-
Zooming
-
Export
-
-
Area Charts
-
Bar Charts
- Bullet Charts
-
Doughnut Charts
-
Financial Charts
-
Funnel and Pyramid Charts
-
Line Charts
- Pareto Chart
-
Pie Charts
-
Point Charts
-
Polar and Radar Charts
-
Range Charts
- Sankey Chart
-
Sparkline Charts
-
Tree Map
-
Gauges
- Overview
-
Runtime update
-
Bar Gauge
-
Circular Gauge
-
Linear Gauge
-
Diagram
- Overview
-
Data Binding
-
Featured Shapes
-
Custom Shapes
-
Document Capabilities
-
User Interaction
- UI Customization
- Adaptability
-
-
Scheduling / Planning
-
Scheduler
- Overview
-
Data Binding
-
Views
-
Appointments
-
Timetable
- Editing
-
Grouping
- Virtual Scrolling
- Drag & Drop
-
Customization
- Adaptability
-
Gantt
- Overview
- Data Binding
-
Filtering
- Sorting
- Strip Lines
- Export to PDF
- Validation
-
Customization
-
-
Reporting
-
AI-powered Extensions
-
Interaction
-
Report Types
-
Data binding
-
Real-life Reports
-
Layout Features
-
Report Controls
-
Web-specific Features
-
-
Rich Text Editor
- Overview
- Load/Save
- Document Protection
-
Templates
- Autocorrect
-
Customization
- Simple View
-
Spreadsheet
- Overview
-
Open a Document
- Export And Printing
-
Features
-
UI Customization
-
Messaging
-
WYSIWYG Editor
-
Forms
-
Data Editors
- Overview
-
Common Concepts
-
Calendar
- Check Box
- Color Box
- Date Box
-
Date Range Box
-
Number Box
- Radio Group
-
Range Selector
- Range Slider
- Slider
- Speech To Text
- Switch
- Text Area
- Text Box
-
Drop-Downs
- Autocomplete
-
Drop Down Box
-
Select Box
-
Tag Box
-
Lookup
-
Buttons
-
File Upload / File Management
-
File Manager
- Overview
-
File System Types
-
Customization
-
File Uploader
-
-
Popup and Notifications
-
Navigation
- Overview
- Accordion
-
Context Menu
-
Menu
- Multi View
-
Drawer
-
Tab Panel
-
Tabs
-
Toolbar
-
Stepper
- Pagination
-
List
-
Tree View
- Right-to-Left Support
-
Layout
-
Tile View
- Splitter
-
Gallery
- Scroll View
-
-
Interactive Wrappers
-
Sortable
- Resizable
-
-
Progress Indicators
-
Maps
- Overview
-
Map
-
Vector Map
-
Data Binding
- Multiple Layers
-
Markers
- Legend
-
Zooming and Panning
-
Customization
-
-
Localization
Chat - Edit and Delete Messages
The DevExtreme Chat UI component allows users to edit and delete messages as needs dictate.
Use a data source to allow users to edit and delete messages. DevExtreme Chat does not update the data source automatically. Implement a CustomStore with CRUD operations to handle updates. Once you configured these operations, enable editing.
@model DevExtreme.NETCore.Demos.ViewModels.ChatViewModel@{ var editingOptions = new[] { new { Text = "Enabled", Value = "enabled" }, new { Text = "Disabled", Value = "disabled" }, new { Text = "Only the last message (custom)", Value = "custom" } };}<div class="chat-container"> @(Html.DevExtreme().Chat() .ID("chat") .Height(600) .User(user => user .Id(Model.CurrentUser.Id) .Name(Model.CurrentUser.Name) ) .DataSource(new JS("dataSource")) .ReloadOnChange(false) .Editing(e => e.AllowUpdating(true).AllowDeleting(true)) .OnInitialized("chat_onInitialized") .OnMessageEntered("chat_onMessageEntered") .OnMessageDeleted("chat_onMessageDeleted") .OnMessageUpdated("chat_onMessageUpdated") )</div><div class="options"> <div class="caption">Options</div> <div class="option"> <span>Allow Editing:</span> @(Html.DevExtreme().SelectBox() .DataSource(editingOptions) .DisplayExpr("Text") .ValueExpr("Value") .InputAttr("aria-label", "Allow Editing") .Value(editingOptions[0].Value) .OnValueChanged("selectBox_allowUpdating_onValueChanged") ) </div> <div class="option"> <span>Allow Deleting:</span> @(Html.DevExtreme().SelectBox() .DataSource(editingOptions) .DisplayExpr("Text") .ValueExpr("Value") .InputAttr("aria-label", "Allow Deleting") .Value(editingOptions[0].Value) .OnValueChanged("selectBox_allowDeleting_onValueChanged") ) </div></div><script> let chat = null; let lastUserMessageId = null; const user = @Html.Raw(System.Text.Json.JsonSerializer.Serialize(Model.CurrentUser)); const store = @Html.Raw(System.Text.Json.JsonSerializer.Serialize(Model.Messages)); const customStore = new DevExpress.data.CustomStore({ key: "id", load: async () => [...store], insert: async (message) => { store.push(message); return message; }, }); const dataSource = new DevExpress.data.DataSource({ store: customStore, paginate: false, }); const editingStrategy = { enabled: true, disabled: false, custom: ({ component, message }) => { const { items, user } = component.option(); const userId = user.id; const lastNotDeletedMessage = items.findLast((item) => { return item.author?.id === userId && !item.isDeleted; }); return message.id === lastNotDeletedMessage?.id; }, }; function chat_onInitialized({ component }) { chat = component; } function chat_onMessageEntered({ message }) { dataSource.store().push([{ type: "insert", data: { ...message, id: new DevExpress.data.Guid(), }, }]); } function chat_onMessageDeleted({ message }) { dataSource.store().push([{ type: "update", key: message.id, data: { isDeleted: true }, }]); } function chat_onMessageUpdated({ message, text }) { dataSource.store().push([{ type: "update", key: message.id, data: { text, isEdited: true }, }]); } function selectBox_allowUpdating_onValueChanged({ value }) { chat.option("editing.allowUpdating", editingStrategy[value]); } function selectBox_allowDeleting_onValueChanged({ value }) { chat.option("editing.allowDeleting", editingStrategy[value]); }</script>xxxxxxxxxxusing System;using System.Linq;using System.Collections.Generic;using Microsoft.AspNetCore.Mvc;using DevExtreme.NETCore.Demos.Models.Chat;using DevExtreme.NETCore.Demos.Models.SampleData;using DevExtreme.NETCore.Demos.ViewModels;namespace DevExtreme.NETCore.Demos.Controllers { public class ChatController : Controller { private List<Message> GetPreparedMessages() { var initialMessages = SampleData.Messages.ToList(); var messages = initialMessages .Select(message => new Message { Id = Guid.NewGuid().ToString(), Timestamp = message.Timestamp, Author = message.Author, Text = message.Text, IsDeleted = message.IsDeleted, IsEdited = message.IsEdited }) .Take(initialMessages.Count - 2) .ToList(); messages.Insert(3, new Message { Id = Guid.NewGuid().ToString(), Timestamp = initialMessages[1].Timestamp, Author = SampleData.CurrentUser, IsDeleted = true }); messages[4].IsEdited = true; return messages; } public ActionResult MessageEditing() { return View(new ChatViewModel { CurrentUser = SampleData.CurrentUser, Messages = GetPreparedMessages(), }); } }}xxxxxxxxxxusing DevExtreme.NETCore.Demos.Models.Chat;using System;using System.Collections.Generic;namespace DevExtreme.NETCore.Demos.Models.SampleData { public partial class SampleData { private static readonly DateTime todayDate = DateTime.Now.Date; private static DateTime GetTimestamp(DateTime date, int offsetMinutes = 0) { DateTime adjustedDate = date.AddMinutes(offsetMinutes); return adjustedDate; } public static ChatUser CurrentUser = new ChatUser { Id = "c94c0e76-fb49-4b9b-8f07-9f93ed93b4f3", Name = "John Doe" }; public static ChatUser SupportAgent = new ChatUser { Id = "d16d1a4c-5c67-4e20-b70e-2991c22747c3", Name = "Support Agent", AvatarUrl = "../../images/petersmith.png" }; public static readonly IEnumerable<Message> Messages = new[] { new Message { Timestamp = GetTimestamp(todayDate, -9), Author = SupportAgent, Text = "Hello, John!\nHow can I assist you today?", }, new Message { Timestamp = GetTimestamp(todayDate, -7), Author = CurrentUser, Text = "Hi, I'm having trouble accessing my account.", }, new Message { Timestamp = GetTimestamp(todayDate, -7), Author = CurrentUser, Text = "It says my password is incorrect." }, new Message { Timestamp = GetTimestamp(todayDate, -7), Author = SupportAgent, Text = "I can help you with that. Can you please confirm your UserID for security purposes?" }, new Message { Timestamp = GetTimestamp(todayDate, 1), Author = CurrentUser, Text = "john.doe1357" }, new Message { Timestamp = GetTimestamp(todayDate, 1), Author = SupportAgent, Text = "✅ Instructions to restore access have been sent to the email address associated with your account." } }; }}xxxxxxxxxxusing DevExtreme.NETCore.Demos.Models.Chat;using System.Collections.Generic;namespace DevExtreme.NETCore.Demos.ViewModels { public class ChatViewModel { public IEnumerable<Message> Messages { get; set; } public ChatUser CurrentUser { get; set; } public ChatUser SupportAgent { get; set; } }}xxxxxxxxxxusing System;using System.Text.Json.Serialization;namespace DevExtreme.NETCore.Demos.Models.Chat{ public class Message { [JsonPropertyName("id")] public string Id { get; set; } [JsonPropertyName("timestamp")] public DateTime Timestamp { get; set; } [JsonPropertyName("author")] public ChatUser Author { get; set; } [JsonPropertyName("text")] public string Text { get; set; } [JsonPropertyName("isDeleted")] public Boolean IsDeleted { get; set; } [JsonPropertyName("isEdited")] public Boolean IsEdited { get; set; } }}xxxxxxxxxxusing System.Text.Json.Serialization;namespace DevExtreme.NETCore.Demos.Models.Chat{ public class ChatUser { [JsonPropertyName("id")] public string Id { get; set; } [JsonPropertyName("name")] public string Name { get; set; } [JsonPropertyName("avatarUrl")] public string AvatarUrl { get; set; } }}xxxxxxxxxx.demo-container { min-width: 720px; display: flex; gap: 20px;}.chat-container { display: flex; flex-grow: 1; align-items: center; justify-content: center;}.options { padding: 20px; display: flex; flex-direction: column; min-width: 280px; background-color: rgba(191, 191, 191, 0.15); gap: 16px;}.dx-chat { max-width: 480px;}.caption { font-size: var(--dx-font-size-sm); font-weight: 500;}.dx-avatar { border: 1px solid var(--dx-color-border);}The editing object includes allowUpdating and allowDeleting properties. These Boolean options are initially set to false. To edit and delete messages, set these Boolean options to true or assign functions with custom logic.
Review this demo and learn how to delete/edit chat messages. First, ensure that "Options" are active in the panel next to the Chat component. Right-click (Control+Click on MacOS) or long-tap a message to open the context menu. Select "Delete" to remove the message; a marker is then displayed in place of the deleted message within the feed. Choose "Edit" to view the original message and update its content. Click "Send" to save changes; this will mark the message as edited.