├── .gitattributes ├── .github └── workflows │ └── vale.yml ├── .gitignore ├── ASP.NET Core ├── ASP.NET Core.csproj ├── ASP.NET Core.sln ├── Controllers │ ├── HomeController.cs │ └── SampleDataController.cs ├── Extensions │ └── Extensions.cs ├── Models │ ├── Employee.cs │ └── EmployeeStore.cs ├── Program.cs ├── Readme.md ├── Startup.cs ├── Views │ ├── Home │ │ └── Index.cshtml │ ├── Shared │ │ ├── Error.cshtml │ │ └── _Layout.cshtml │ ├── _ViewImports.cshtml │ └── _ViewStart.cshtml ├── appsettings.Development.json ├── appsettings.json ├── gulpfile.js ├── package-lock.json ├── package.json └── wwwroot │ └── css │ └── Site.css ├── Angular ├── .browserslistrc ├── .editorconfig ├── .gitignore ├── .vscode │ ├── extensions.json │ ├── launch.json │ └── tasks.json ├── README.md ├── angular.json ├── karma.conf.js ├── package-lock.json ├── package.json ├── src │ ├── app │ │ ├── app-routing.module.ts │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ └── app.service.ts │ ├── assets │ │ └── .gitkeep │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ └── test.ts ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.spec.json └── yarn.lock ├── CODEOWNERS ├── LICENSE ├── README.md ├── React ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ ├── robots.txt │ └── style.css ├── src │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── LabelNotesTemplate.js │ ├── LabelTemplate.js │ ├── ValidationRulesAndEditorOptions.js │ ├── data.js │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── reportWebVitals.js │ └── setupTests.js └── yarn.lock ├── Vue ├── .gitignore ├── README.md ├── babel.config.js ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── App.vue │ ├── LabelNotesTemplate.vue │ ├── LabelTemplate.vue │ ├── assets │ │ └── logo.png │ ├── data.js │ └── main.js └── yarn.lock ├── dx-datagrid-custom-editing-form.png ├── jQuery ├── README.md ├── bs-config.json ├── favicon.ico ├── package-lock.json ├── package.json ├── src │ ├── data.js │ ├── index.css │ ├── index.html │ └── index.js └── yarn.lock └── test-example.ps1 /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | VB/* linguist-vendored 4 | scripts linguist-vendored 5 | *.css linguist-detectable=false 6 | *.aff linguist-detectable=false 7 | -------------------------------------------------------------------------------- /.github/workflows/vale.yml: -------------------------------------------------------------------------------- 1 | name: vale-validation 2 | on: 3 | pull_request: 4 | paths: 5 | - README.md 6 | - readme.md 7 | - Readme.md 8 | 9 | jobs: 10 | vale: 11 | name: runner / vale 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: clone repo 15 | uses: actions/checkout@v4 16 | - name: clone vale-styles repo 17 | uses: actions/checkout@v4 18 | with: 19 | repository: DevExpress/vale-styles 20 | path: vale-styles 21 | ssh-key: ${{ secrets.VALE_STYLES_ACCESS_KEY }} 22 | - name: copy vale rules to the root repo 23 | run: shopt -s dotglob && cp -r ./vale-styles/vale/* . 24 | - name: vale linter check 25 | uses: DevExpress/vale-action@reviewdog 26 | with: 27 | files: '["README.md", "readme.md", "Readme.md"]' 28 | fail_on_error: true 29 | filter_mode: nofilter 30 | reporter: github-check 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | ASP.NET/SampleApp/obj/SampleApp.csproj.nuget.g.targets 3 | ASP.NET/SampleApp/obj/SampleApp.csproj.nuget.g.props 4 | ASP.NET/SampleApp/obj/SampleApp.csproj.nuget.dgspec.json 5 | ASP.NET/SampleApp/obj/project.nuget.cache 6 | ASP.NET/SampleApp/obj/project.assets.json 7 | ASP.NET/SampleApp/obj/Debug/netcoreapp3.1/SampleApp.RazorAssemblyInfo.cs 8 | ASP.NET/SampleApp/obj/Debug/netcoreapp3.1/SampleApp.RazorAssemblyInfo.cache 9 | ASP.NET/SampleApp/obj/Debug/netcoreapp3.1/SampleApp.csprojAssemblyReference.cache 10 | ASP.NET/SampleApp/obj/Debug/netcoreapp3.1/SampleApp.assets.cache 11 | ASP.NET/SampleApp/obj/Debug/netcoreapp3.1/SampleApp.AssemblyInfoInputs.cache 12 | ASP.NET/SampleApp/obj/Debug/netcoreapp3.1/SampleApp.AssemblyInfo.cs 13 | ASP.NET/SampleApp/obj/Debug/netcoreapp3.1/project.razor.json 14 | ASP.NET/SampleApp/obj/Debug/netcoreapp3.1/.NETCoreApp,Version=v3.1.AssemblyAttributes.cs 15 | ASP.NET/.vs/SampleApp/v16/.suo 16 | ASP.NET/.vs/SampleApp/DesignTimeBuild/.dtbcache.v2 17 | ASP.NET/.vs/SampleApp/config/applicationhost.config 18 | node_modules/ 19 | -------------------------------------------------------------------------------- /ASP.NET Core/ASP.NET Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /ASP.NET Core/ASP.NET Core.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30330.147 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ASP.NET Core", "ASP.NET Core.csproj", "{435CB7A8-3168-4BD2-815F-E54F708AF968}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {435CB7A8-3168-4BD2-815F-E54F708AF968}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {435CB7A8-3168-4BD2-815F-E54F708AF968}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {435CB7A8-3168-4BD2-815F-E54F708AF968}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {435CB7A8-3168-4BD2-815F-E54F708AF968}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {08AFB133-D1F6-4FE9-A66A-586B96B002D0} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /ASP.NET Core/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | 7 | namespace ASP_NET_Core.Controllers 8 | { 9 | public class HomeController : Controller 10 | { 11 | public IActionResult Index() 12 | { 13 | return View(); 14 | } 15 | 16 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 17 | public IActionResult Error() { 18 | return View(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ASP.NET Core/Controllers/SampleDataController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Net.Http; 6 | using System.Xml.Linq; 7 | using ASP.NET_Core.Models; 8 | using ASP_NET_Core.Models; 9 | using DevExtreme.AspNet.Data; 10 | using DevExtreme.AspNet.Mvc; 11 | using Microsoft.AspNetCore.Mvc; 12 | using Newtonsoft.Json; 13 | using ASP_NET_Core.Extensions; 14 | 15 | namespace ASP_NET_Core.Controllers { 16 | 17 | [Route("api/[controller]")] 18 | public class SampleDataController : Controller { 19 | 20 | [HttpGet] 21 | public object Get(DataSourceLoadOptions loadOptions) { 22 | return DataSourceLoader.Load(EmployeeStore.Employees, loadOptions); 23 | } 24 | [HttpPost] 25 | public IActionResult Add(string values) { 26 | var newEmployee = new Employee(); 27 | JsonConvert.PopulateObject(values, newEmployee); 28 | 29 | if (!TryValidateModel(newEmployee)) 30 | return BadRequest(ModelState.GetFullErrorMessage()); 31 | 32 | EmployeeStore.Employees.Add(newEmployee); 33 | 34 | return Ok(); 35 | } 36 | 37 | [HttpPut] 38 | public IActionResult Update(int key, string values) { 39 | var employee = EmployeeStore.Employees.First(a => a.ID == key); 40 | JsonConvert.PopulateObject(values, employee); 41 | 42 | if (!TryValidateModel(employee)) 43 | return BadRequest(ModelState.GetFullErrorMessage()); 44 | 45 | return Ok(); 46 | } 47 | 48 | [HttpDelete] 49 | public void Delete(int key) { 50 | var employee = EmployeeStore.Employees.First(a => a.ID == key); 51 | EmployeeStore.Employees.Remove(employee); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /ASP.NET Core/Extensions/Extensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc.ModelBinding; 2 | using System.Collections.Generic; 3 | using System; 4 | 5 | namespace ASP_NET_Core.Extensions 6 | { 7 | static class Extensions { 8 | public static string GetFullErrorMessage(this ModelStateDictionary modelState) { 9 | var messages = new List(); 10 | 11 | foreach (var entry in modelState) { 12 | foreach (var error in entry.Value.Errors) 13 | messages.Add(error.ErrorMessage); 14 | } 15 | 16 | return String.Join(" ", messages); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ASP.NET Core/Models/Employee.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Xml.Linq; 5 | using System; 6 | 7 | namespace ASP_NET_Core.Models { 8 | public class Employee 9 | { 10 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "ID")] 11 | public int ID { get; set; } 12 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "FirstName")] 13 | [Required(ErrorMessage = "First Name is required.")] 14 | public string FirstName { get; set; } 15 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "LastName")] 16 | [Required(ErrorMessage = "Last Name is required.")] 17 | public string LastName { get; set; } 18 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "Prefix")] 19 | public string Prefix { get; set; } 20 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "Position")] 21 | public string Position { get; set; } 22 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "BirthDate")] 23 | [Required(ErrorMessage = "Birth Date is required.")] 24 | public DateTime? BirthDate { get; set; } 25 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "HireDate")] 26 | public DateTime? HireDate { get; set; } 27 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "Notes")] 28 | public string Notes { get; set; } 29 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "Address")] 30 | public string Address { get; set; } 31 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "Phone")] 32 | [Required(ErrorMessage = "Phone Number is required.")] 33 | public string Phone { get; set; } 34 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "Email")] 35 | [EmailAddress(ErrorMessage = "Email is incorrect.")] 36 | public string Email { get; set; } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ASP.NET Core/Models/EmployeeStore.cs: -------------------------------------------------------------------------------- 1 | using ASP_NET_Core.Models; 2 | using DevExtreme.AspNet.Mvc; 3 | using System.Collections.Generic; 4 | using System.Net; 5 | using System.Numerics; 6 | 7 | namespace ASP.NET_Core.Models 8 | { 9 | static class EmployeeStore { 10 | public static List Employees = new List() { 11 | new Employee() { 12 | ID = 1, 13 | FirstName = "John", 14 | LastName = "Heart", 15 | Prefix = "Mr.", 16 | Position = "CEO", 17 | BirthDate = System.DateTime.Parse("1964/03/16"), 18 | HireDate = System.DateTime.Parse("1995/01/15"), 19 | Notes = "John has been in the Audio/Video industry since 1990. He has led DevAv as its CEO since 2003.\r\n\r\nWhen not working hard as the CEO, John loves to golf and bowl. He once bowled a perfect game of 300.", 20 | Address = "351 S Hill St.", 21 | Phone = "16102458448", 22 | Email = "rohitm@hotmail.com", 23 | }, new Employee() { 24 | ID = 2, 25 | FirstName = "Olivia", 26 | LastName = "Peyton", 27 | Prefix = "Mrs.", 28 | Position = "Sales Assistant", 29 | BirthDate = System.DateTime.Parse("1981/06/03"), 30 | HireDate = System.DateTime.Parse("2012/05/14"), 31 | Notes = "Olivia loves to sell. She has been selling DevAV products since 2012. \r\n\r\nOlivia was homecoming queen in high school. She is expecting her first child in 6 months. Good Luck Olivia.", 32 | Address = "807 W Paseo Del Mar", 33 | Phone = "16102347905", 34 | Email = "spadkins@optonline.net", 35 | }, new Employee() { 36 | ID = 3, 37 | FirstName = "Robert", 38 | LastName = "Reagan", 39 | Prefix = "Mr.", 40 | Position = "CMO", 41 | BirthDate = System.DateTime.Parse("1974/09/07"), 42 | HireDate = System.DateTime.Parse("2002/11/08"), 43 | Notes = "Robert was recently voted the CMO of the year by CMO Magazine. He is a proud member of the DevAV Management Team.\r\n\r\nRobert is a championship BBQ chef, so when you get the chance ask him for his secret recipe.", 44 | Address = "4 Westmoreland Pl.", 45 | Phone = "14845219762", 46 | Email = "naoya@comcast.net", 47 | }, new Employee() { 48 | ID = 4, 49 | FirstName = "Greta", 50 | LastName = "Sims", 51 | Prefix = "Ms.", 52 | Position = "HR Manager", 53 | BirthDate = System.DateTime.Parse("1977/11/22"), 54 | HireDate = System.DateTime.Parse("1998/04/23"), 55 | Notes = "Greta has been DevAV's HR Manager since 2003. She joined DevAV from Sonee Corp.\r\n\r\nGreta is currently training for the NYC marathon. Her best marathon time is 4 hours. Go Greta.", 56 | Address = "1700 S Grandview Dr.", 57 | Phone = "14844578858", 58 | Email = "tattooman@optonline.net", 59 | }, new Employee() { 60 | ID = 5, 61 | FirstName = "Brett", 62 | LastName = "Wade", 63 | Prefix = "Mr.", 64 | Position = "IT Manager", 65 | BirthDate = System.DateTime.Parse("1968/12/01"), 66 | HireDate = System.DateTime.Parse("2009/03/06"), 67 | Notes = "Brett came to DevAv from Microsoft and has led our IT department since 2012.\r\n\r\nWhen he is not working hard for DevAV, he coaches Little League (he was a high school pitcher).", 68 | Address = "1120 Old Mill Rd.", 69 | Phone = "18143008837", 70 | Email = "haddawy@mac.com", 71 | }, new Employee() { 72 | ID = 6, 73 | FirstName = "Sandra", 74 | LastName = "Johnson", 75 | Prefix = "Mrs.", 76 | Position = "Controller", 77 | BirthDate = System.DateTime.Parse("1974/11/15"), 78 | HireDate = System.DateTime.Parse("2005/05/11"), 79 | Notes = "Sandra is a CPA and has been our controller since 2008. She loves to interact with staff so if you've not met her, be certain to say hi.\r\n\r\nSandra has 2 daughters both of whom are accomplished gymnasts.", 80 | Address = "4600 N Virginia Rd.", 81 | Phone = "15852826538", 82 | Email = "gordonjcp@gmail.com", 83 | }, new Employee() { 84 | ID = 7, 85 | FirstName = "Kevin", 86 | LastName = "Carter", 87 | Prefix = "Mr.", 88 | Position = "Shipping Manager", 89 | BirthDate = System.DateTime.Parse("1978/01/09"), 90 | HireDate = System.DateTime.Parse("2009/08/11"), 91 | Notes = "Kevin is our hard-working shipping manager and has been helping that department work like clockwork for 18 months.\r\n\r\nWhen not in the office, he is usually on the basketball court playing pick-up games.", 92 | Address = "424 N Main St.", 93 | Phone = "14844760152", 94 | Email = "chance@verizon.net", 95 | }, new Employee() { 96 | ID = 8, 97 | FirstName = "Cynthia", 98 | LastName = "Stanwick", 99 | Prefix = "Ms.", 100 | Position = "HR Manager", 101 | BirthDate = System.DateTime.Parse("1985/06/05"), 102 | HireDate = System.DateTime.Parse("2008/03/24"), 103 | Notes = "Cindy joined us in 2008 and has been in the HR department for 2 years. \r\n\r\nShe was recently awarded employee of the month. Way to go Cindy!", 104 | Address = "2211 Bonita Dr.", 105 | Phone = "14842989304", 106 | Email = "kevinm@verizon.net", 107 | }, new Employee() { 108 | ID = 9, 109 | FirstName = "Kent", 110 | LastName = "Samuelson", 111 | Prefix = "Dr.", 112 | Position = "Support Manager", 113 | BirthDate = System.DateTime.Parse("1972/09/11"), 114 | HireDate = System.DateTime.Parse("2009/04/22"), 115 | Notes = "As our ombudsman, Kent is on the front-lines solving customer problems and helping our partners address issues out in the field. He is a classically trained musician and is a member of the Chamber Orchestra.", 116 | Address = "12100 Mora Dr", 117 | Phone = "14844731660", 118 | Email = "arebenti@outlook.com", 119 | }, new Employee() { 120 | ID = 10, 121 | FirstName = "Taylor", 122 | LastName = "Riley", 123 | Prefix = "Mr.", 124 | Position = "Sales Manager", 125 | BirthDate = System.DateTime.Parse("1982/08/14"), 126 | HireDate = System.DateTime.Parse("2012/04/14"), 127 | Notes = "If you are like the rest of us at DevAV, then you've probably reached out for help from Taylor. He does a great job as a member of our IT department.", 128 | Address = "7776 Torreyson Dr", 129 | Phone = "14842989306", 130 | Email = "amichalo@live.com", 131 | } 132 | }; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /ASP.NET Core/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Hosting; 6 | using Microsoft.Extensions.Configuration; 7 | using Microsoft.Extensions.Hosting; 8 | using Microsoft.Extensions.Logging; 9 | 10 | namespace ASP_NET_Core 11 | { 12 | public class Program 13 | { 14 | public static void Main(string[] args) 15 | { 16 | CreateHostBuilder(args).Build().Run(); 17 | } 18 | 19 | public static IHostBuilder CreateHostBuilder(string[] args) => 20 | Host.CreateDefaultBuilder(args) 21 | .ConfigureWebHostDefaults(webBuilder => { 22 | webBuilder.UseStartup(); 23 | }); 24 | } 25 | } -------------------------------------------------------------------------------- /ASP.NET Core/Readme.md: -------------------------------------------------------------------------------- 1 | # ASP.NET Core 2 | 3 | ## Installation 4 | 5 | Download the example and use Visual Studio 2019 to open the project. 6 | 7 | ## Client-side resources and bundling 8 | 9 | This project uses [NPM](https://www.npmjs.com/) and [Gulp.js](https://gulpjs.com/) to install client-side libraries. The project restores NPM packages before the first build. Then, Gulp bundles required scripts and CSS files into the resulting package during the first and every next build. 10 | 11 | The resulted bundles will be located in the `wwwroot` folder: 12 | * `css/vendor.css` - a file with all CSS styles. 13 | * `css/icons` and `css/fonts` - folders that contain fonts and icons for DevExtreme themes. 14 | * `js/vendor.js` - a file that contains all scripts. 15 | 16 | The default bundle includes jQuery, Bootstrap, and DevExtreme. 17 | 18 | ### Add more 3rd-party libraries for additional features/components 19 | 20 | The main logic is located in the the `gulpfile.js` file at the root application level. The file contains two tasks: 21 | 22 | * the `add-resouces` task 23 | 24 | * copies JavaScript files located in the `scripts` array and adds them to `vendor.js`. The script bundle is moved to `wwwroot\scripts`. 25 | * copies CSS styles located in the `styles` array and merges them into the `styles.css` bundle. Then, this bundle is moved to `wwwroot\styles` 26 | * copies DevExtreme `fonts` and `icons` folders from NPM to `wwwroot\styles` 27 | 28 | * the `clean` task removes all previously created files (`vendor.js` and `vendor.css`) and folders (`icons` and `fonts`) 29 | 30 | If you need to include more features, you can uncomment one of the following sections: 31 | 32 | * Gantt - scripts and styles for [dxGantt](https://js.devexpress.com/DevExtreme/Guide/UI_Components/Gantt/Getting_Started_with_Gantt/). 33 | * Diagram - scripts and styles for [dxDiagram](https://js.devexpress.com/DevExtreme/Guide/UI_Components/Diagram/Getting_Started_with_Diagram/). 34 | * Export - scripts and styles for the exporting feature: [Export Data to Excel](https://js.devexpress.com/DevExtreme/Guide/UI_Components/DataGrid/Getting_Started_with_DataGrid/#Export_Data). 35 | * HtmlEditor - scripts and styles for [dxHtmlEditor](https://js.devexpress.com/DevExtreme/Guide/UI_Components/HtmlEditor/Overview/). 36 | * Full Bundle - scripts and styles for all above mentioned features/components. 37 | 38 | ## Code 39 | 40 | Take a look at the following files of this example to see the required code: 41 | 42 | A list of files goes here 43 | 44 | ## Development server 45 | 46 | Use the Visual Studio `Run (F5)` command to run the project. 47 | 48 | ## Further help 49 | 50 | You can learn more about the ASP.NET Core components' syntax in our documentation: [Concepts](https://docs.devexpress.com/AspNetCore/400574/devextreme-based-controls/concepts/razor-syntax) 51 | The client-side API is based on jQuery [jQuery documentation](https://api.jquery.com/) and described in the following topics: 52 | * [Get and Set Properties](https://js.devexpress.com/DevExtreme/Guide/jQuery_Components/Component_Configuration_Syntax/#Get_and_Set_Properties) 53 | * [Call Methods](https://js.devexpress.com/DevExtreme/Guide/jQuery_Components/Component_Configuration_Syntax/#Call_Methods) 54 | * [Get a UI Component Instance](https://js.devexpress.com/DevExtreme/Guide/jQuery_Components/Component_Configuration_Syntax/#Get_a_UI_Component_Instance) 55 | 56 | To get more help on DevExtreme submit an issue in the [Support Center](https://www.devexpress.com/Support/Center/Question/Create) 57 | 58 | 59 | -------------------------------------------------------------------------------- /ASP.NET Core/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Builder; 6 | using Microsoft.AspNetCore.Hosting; 7 | using Microsoft.Extensions.Configuration; 8 | using Microsoft.Extensions.DependencyInjection; 9 | using Microsoft.Extensions.Hosting; 10 | 11 | namespace ASP_NET_Core 12 | { 13 | public class Startup 14 | { 15 | public Startup(IConfiguration configuration) 16 | { 17 | Configuration = configuration; 18 | } 19 | 20 | public IConfiguration Configuration { get; } 21 | 22 | // This method gets called by the runtime. Use this method to add services to the container. 23 | public void ConfigureServices(IServiceCollection services) 24 | { 25 | // Add framework services. 26 | services 27 | .AddControllersWithViews() 28 | .AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null); 29 | } 30 | 31 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 32 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 33 | { 34 | if (env.IsDevelopment()) 35 | { 36 | app.UseDeveloperExceptionPage(); 37 | } 38 | else 39 | { 40 | app.UseExceptionHandler("/Home/Error"); 41 | } 42 | app.UseStaticFiles(); 43 | 44 | app.UseRouting(); 45 | 46 | app.UseAuthorization(); 47 | 48 | app.UseEndpoints(endpoints => { 49 | endpoints.MapControllerRoute( 50 | name: "default", 51 | pattern: "{controller=Home}/{action=Index}/{id?}"); 52 | }); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /ASP.NET Core/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using ASP_NET_Core.Models 2 | @{ 3 | string[] positions = new string[] {"HR Manager", "IT Manager", "CEO", "Controller", 4 | "Sales Manager", "Support Manager", "Shipping Manager", "Sales Assistant", "CMO" 5 | }; 6 | } 7 |

Custom Edit Form

8 | 9 | @( 10 | Html.DevExtreme().DataGrid() 11 | .ID("grid") 12 | .ShowBorders(true) 13 | .DataSource(d => d.Mvc().Controller("SampleData").Key("ID") 14 | .LoadAction("Get") 15 | .DeleteAction("Delete") 16 | .UpdateAction("Update") 17 | .InsertAction("Add") 18 | ) 19 | .ShowColumnLines(true) 20 | .ShowRowLines(true) 21 | .RepaintChangesOnly(true) 22 | .Editing(editing => editing 23 | .Mode(GridEditMode.Popup) 24 | .AllowAdding(true) 25 | .AllowDeleting(true) 26 | .AllowUpdating(true) 27 | .UseIcons(true) 28 | ) 29 | .Columns(columns => { 30 | columns.AddFor(m => m.FirstName); 31 | columns.AddFor(m => m.LastName); 32 | columns.AddFor(m => m.BirthDate); 33 | columns.AddFor(m => m.Position).Width(170); 34 | columns.AddFor(m => m.HireDate); 35 | columns.AddFor(m => m.Address); 36 | columns.Add().Type(GridCommandColumnType.Buttons).Buttons(buttons => { 37 | buttons.Add().Name(GridColumnButtonName.Edit).OnClick("editClick"); 38 | buttons.Add().Name(GridColumnButtonName.Delete); 39 | }); 40 | }) 41 | .Toolbar(toolbar => toolbar.Items(items => { 42 | items.Add().Widget(w => w.Button().Icon("plus").OnClick("addClick")); 43 | })) 44 | ) 45 | 46 | @(Html.DevExtreme().Popup() 47 | .ID("popup") 48 | .DeferRendering(false) 49 | .HideOnOutsideClick(true) 50 | .Height("auto") 51 | .ContentTemplate(new TemplateName("popup-template")) 52 | .ToolbarItems(toolbar => { 53 | toolbar.Add() 54 | .Location(ToolbarItemLocation.After) 55 | .Toolbar(Toolbar.Bottom) 56 | .Widget(w => w.Button() 57 | .Text("Confirm") 58 | .Type(ButtonType.Success) 59 | .OnClick("confirmClick") 60 | ); 61 | toolbar.Add() 62 | .Location(ToolbarItemLocation.After) 63 | .Toolbar(Toolbar.Bottom) 64 | .Widget(w => w.Button() 65 | .Text("Cancel") 66 | .Type(ButtonType.Success) 67 | .OnClick("cancelClick") 68 | ); 69 | }) 70 | ) 71 | @using (Html.DevExtreme().NamedTemplate("popup-template")) { 72 | @( 73 | Html.DevExtreme().Form() 74 | .ID("form") 75 | .ShowColonAfterLabel(true) 76 | .ValidationGroup(new JS("validationGroupName")) 77 | .Items(items => { 78 | items.AddGroup().ColCount(2).Items(group => { 79 | group.AddSimpleFor(m => m.FirstName) 80 | .Label(label => label.Template(new JS("(data) => labelTemplate(data, 'user')"))); 81 | group.AddSimpleFor(m => m.Position) 82 | .Editor(editor => editor.SelectBox().SearchEnabled(true).Items(positions)) 83 | .Label(label => label.Template(new JS("(data) => labelTemplate(data, 'info')"))); 84 | group.AddSimpleFor(m => m.LastName) 85 | .Label(label => label.Template(new JS("(data) => labelTemplate(data, 'user')"))); 86 | group.AddSimpleFor(m => m.Address) 87 | .Label(label => label.Template(new JS("(data) => labelTemplate(data, 'home')"))); 88 | group.AddSimpleFor(m => m.BirthDate) 89 | .Label(label => label.Template(new JS("(data) => labelTemplate(data, 'event')"))); 90 | group.AddSimpleFor(m => m.HireDate) 91 | .Label(label => label.Template(new JS("(data) => labelTemplate(data, 'event')"))); 92 | group.AddSimpleFor(m => m.Notes) 93 | .ColSpan(2) 94 | .Editor(editor => editor.TextArea().MaxLength(200).Height(90)) 95 | .Label(label => label.Template(new TemplateName("notes-label-template"))); 96 | group.AddSimpleFor(m => m.Phone) 97 | .Editor(editor => editor.TextBox() 98 | .Mask("+1 (X00) 000-0000") 99 | .MaskRules(new JS("{ X: /[02-9]/ }")) 100 | .MaskInvalidMessage("The phone must have a correct USA phone format") 101 | ) 102 | .Label(label => label.Template(new JS("(data) => labelTemplate(data, 'tel')"))); 103 | group.AddSimpleFor(m => m.Email) 104 | .Label(label => label.Template(new JS("(data) => labelTemplate(data, 'email')"))); 105 | }); 106 | }) 107 | ); 108 | } 109 | @using (Html.DevExtreme().NamedTemplate("notes-label-template")) { 110 |
111 | 112 | Additional
<%- text %> 113 |
114 | @(Html.DevExtreme().Tooltip() 115 | .ShowEvent("mouseenter") 116 | .HideEvent("mouseleave") 117 | .Target("#helpedInfo") 118 | .ContentTemplate(@ 119 |
This field must not exceed 200 characters
120 |
) 121 | ) 122 | } 123 | -------------------------------------------------------------------------------- /ASP.NET Core/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 |

An error occurred while the server was processing your request.

2 | 3 |

4 | To display detailed information about the error, set the ASPNETCORE_ENVIRONMENT environment variable to Development and restart the app. 5 |

6 |

7 | The Development environment should not be enabled for deployed applications because it provides users access to exceptions that can contain sensitive information. 8 |

-------------------------------------------------------------------------------- /ASP.NET Core/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | ASP_NET_Core 12 | 13 | 14 | @* Uncomment to use the HtmlEditor control *@ 15 | @* *@ 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | @RenderBody() 25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /ASP.NET Core/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using ASP_NET_Core 2 | @namespace ASP_NET_Core.Models 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | @using DevExtreme.AspNet.Mvc 5 | -------------------------------------------------------------------------------- /ASP.NET Core/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /ASP.NET Core/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ASP.NET Core/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*" 10 | } 11 | -------------------------------------------------------------------------------- /ASP.NET Core/gulpfile.js: -------------------------------------------------------------------------------- 1 | /// 2 | const gulp = require("gulp"), 3 | rimraf = require("rimraf"), 4 | concat = require("gulp-concat"); 5 | 6 | 7 | const paths = { 8 | webroot: "./wwwroot/" 9 | }; 10 | 11 | paths.concatJsDest = paths.webroot + "js/vendor.js"; 12 | paths.concatCssDest = paths.webroot + "css/vendor.css"; 13 | paths.fonts = paths.webroot + "css/fonts"; 14 | paths.icons = paths.webroot + "css/icons"; 15 | 16 | let defaultScripts = [ 17 | "node_modules/jquery/dist/jquery.min.js", 18 | "node_modules/bootstrap/dist/js/bootstrap.min.js"], 19 | exportScripts = [ 20 | "node_modules/jszip/dist/jszip.min.js", 21 | "node_modules/exceljs/dist/exceljs.min.js", 22 | "node_modules/file-saver/FileSaver.min.js" 23 | ], 24 | quillScripts = ["node_modules/devextreme-quill/dist/dx-quill.min.js", 25 | "node_modules/turndown/dist/turndown.js", 26 | "node_modules/showdown/dist/showdown.js" 27 | ], 28 | diagramScript = ["node_modules/devexpress-diagram/dist/dx-diagram.min.js"], 29 | ganttScript = ["node_modules/devexpress-gantt/dist/dx-gantt.min.js"], 30 | dxtScripts = [ 31 | "node_modules/devextreme/dist/js/dx.all.js", 32 | "node_modules/devextreme/dist/js/dx.aspnet.mvc.js", 33 | "node_modules/devextreme-aspnet-data/js/dx.aspnet.data.js"]; 34 | 35 | 36 | let dxtStyles = [ 37 | "node_modules/bootstrap/dist/css/bootstrap.css", 38 | "node_modules/devextreme/dist/css/dx.common.css", 39 | "node_modules/devextreme/dist/css/dx.light.css"], 40 | ganttStyles = ["node_modules/devexpress-gantt/dist/dx-gantt.min.css"], 41 | diagramStyles = ["node_modules/devexpress-diagram/dist/dx-diagram.min.css"]; 42 | 43 | 44 | /* default configuration */ 45 | 46 | let styles = dxtStyles; 47 | let scripts = [...defaultScripts, ...dxtScripts]; 48 | 49 | /* // Gantt 50 | scripts = [...defaultScripts, ...ganttScript, ...dxtScripts]; 51 | styles = [...styles, ...ganttStyles]; 52 | */ 53 | 54 | /* // Diagram 55 | scripts = [...defaultScripts, ...diagramScript, ...dxtScripts]; 56 | styles = [...styles, ...diagramStyles]; 57 | */ 58 | 59 | /* // HtmlEditor 60 | scripts = [...defaultScripts, ...quillScripts, dxtScripts]; 61 | */ 62 | 63 | /* // Export 64 | scripts = [...exportScripts, ...scripts]; 65 | */ 66 | 67 | /* // Full bundle 68 | 69 | scripts = [...exportScripts, ...defaultScripts, ...ganttScript, ...diagramScript, ...quillScripts, ...dxtScripts]; 70 | styles = [...dxtStyles, ...diagramStyles, ...ganttStyles]; 71 | 72 | */ 73 | 74 | 75 | gulp.task("clean:js", function (cb) { 76 | rimraf(paths.concatJsDest, cb); 77 | }); 78 | 79 | gulp.task("clean:css", function (cb) { 80 | rimraf(paths.concatCssDest, cb); 81 | }); 82 | gulp.task("clean:icons", function (cb) { 83 | rimraf(paths.icons, cb); 84 | }); 85 | gulp.task("clean:fonts", function (cb) { 86 | rimraf(paths.fonts, cb); 87 | }); 88 | 89 | gulp.task("clean", gulp.series(["clean:js", "clean:css", "clean:icons", "clean:fonts"])); 90 | 91 | 92 | gulp.task("add:js", function () { 93 | 94 | return gulp.src(scripts, { base: "." }) 95 | .pipe(concat(paths.concatJsDest)) 96 | .pipe(gulp.dest(".")); 97 | }); 98 | 99 | gulp.task("add:css", function () { 100 | return gulp.src(styles) 101 | .pipe(concat(paths.concatCssDest)) 102 | .pipe(gulp.dest(".")); 103 | }); 104 | 105 | gulp.task("add:icons", function () { 106 | return gulp.src(["node_modules/devextreme/dist/css/icons/*"]).pipe(gulp.dest(paths.icons)); 107 | }) 108 | gulp.task("add:fonts", function () { 109 | return gulp.src(["node_modules/devextreme/dist/css/fonts/*"]).pipe(gulp.dest(paths.fonts)); 110 | }) 111 | 112 | gulp.task("add-resources", gulp.series(["add:js", "add:css", "add:icons", "add:fonts"])); -------------------------------------------------------------------------------- /ASP.NET Core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0", 3 | "name": "asp.net", 4 | "private": true, 5 | "dependencies": { 6 | "jquery": "3.5.1", 7 | "devextreme": "^22.2.3", 8 | "devextreme-aspnet-data": "^2.9.1", 9 | "bootstrap": "^4.6.0" 10 | }, 11 | "devDependencies": { 12 | "gulp": "4.0.2", 13 | "gulp-concat": "2.6.1", 14 | "rimraf": "3.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ASP.NET Core/wwwroot/css/Site.css: -------------------------------------------------------------------------------- 1 | .demo-container { 2 | margin: 50px 50px; 3 | width: 90vh; 4 | } 5 | body { 6 | margin: 8px; 7 | } 8 | 9 | #helpedInfo { 10 | color: #42a5f5; 11 | } 12 | 13 | #tooltip-content { 14 | font-size: 14px; 15 | font-weight: bold; 16 | } 17 | 18 | #template-content { 19 | display: inline-flex; 20 | } -------------------------------------------------------------------------------- /Angular/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | -------------------------------------------------------------------------------- /Angular/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /Angular/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # Compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | /bazel-out 8 | 9 | # Node 10 | /node_modules 11 | npm-debug.log 12 | yarn-error.log 13 | 14 | # IDEs and editors 15 | .idea/ 16 | .project 17 | .classpath 18 | .c9/ 19 | *.launch 20 | .settings/ 21 | *.sublime-workspace 22 | 23 | # Visual Studio Code 24 | .vscode/* 25 | !.vscode/settings.json 26 | !.vscode/tasks.json 27 | !.vscode/launch.json 28 | !.vscode/extensions.json 29 | .history/* 30 | 31 | # Miscellaneous 32 | /.angular/cache 33 | .sass-cache/ 34 | /connect.lock 35 | /coverage 36 | /libpeerconnection.log 37 | testem.log 38 | /typings 39 | 40 | # System files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /Angular/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 3 | "recommendations": ["angular.ng-template"] 4 | } 5 | -------------------------------------------------------------------------------- /Angular/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 3 | "version": "0.2.0", 4 | "configurations": [ 5 | { 6 | "name": "ng serve", 7 | "type": "pwa-chrome", 8 | "request": "launch", 9 | "preLaunchTask": "npm: start", 10 | "url": "http://localhost:4200/" 11 | }, 12 | { 13 | "name": "ng test", 14 | "type": "chrome", 15 | "request": "launch", 16 | "preLaunchTask": "npm: test", 17 | "url": "http://localhost:9876/debug.html" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /Angular/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 3 | "version": "2.0.0", 4 | "tasks": [ 5 | { 6 | "type": "npm", 7 | "script": "start", 8 | "isBackground": true, 9 | "problemMatcher": { 10 | "owner": "typescript", 11 | "pattern": "$tsc", 12 | "background": { 13 | "activeOnStart": true, 14 | "beginsPattern": { 15 | "regexp": "(.*?)" 16 | }, 17 | "endsPattern": { 18 | "regexp": "bundle generation complete" 19 | } 20 | } 21 | } 22 | }, 23 | { 24 | "type": "npm", 25 | "script": "test", 26 | "isBackground": true, 27 | "problemMatcher": { 28 | "owner": "typescript", 29 | "pattern": "$tsc", 30 | "background": { 31 | "activeOnStart": true, 32 | "beginsPattern": { 33 | "regexp": "(.*?)" 34 | }, 35 | "endsPattern": { 36 | "regexp": "bundle generation complete" 37 | } 38 | } 39 | } 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /Angular/README.md: -------------------------------------------------------------------------------- 1 | # Angular App 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 14.2.8. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://v17.angular.io/cli) page. 28 | -------------------------------------------------------------------------------- /Angular/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "DxAngularApp": { 7 | "projectType": "application", 8 | "schematics": {}, 9 | "root": "", 10 | "sourceRoot": "src", 11 | "prefix": "app", 12 | "architect": { 13 | "build": { 14 | "builder": "@angular-devkit/build-angular:browser", 15 | "options": { 16 | "outputPath": "dist/dx-angular-app", 17 | "index": "src/index.html", 18 | "main": "src/main.ts", 19 | "polyfills": "src/polyfills.ts", 20 | "tsConfig": "tsconfig.app.json", 21 | "assets": [ 22 | "src/favicon.ico", 23 | "src/assets" 24 | ], 25 | "styles": [ 26 | "node_modules/devextreme/dist/css/dx.light.css", 27 | "src/styles.css" 28 | ], 29 | "scripts": [] 30 | }, 31 | "configurations": { 32 | "production": { 33 | "budgets": [ 34 | { 35 | "type": "initial", 36 | "maximumWarning": "500kb", 37 | "maximumError": "1mb" 38 | }, 39 | { 40 | "type": "anyComponentStyle", 41 | "maximumWarning": "2kb", 42 | "maximumError": "4kb" 43 | } 44 | ], 45 | "fileReplacements": [ 46 | { 47 | "replace": "src/environments/environment.ts", 48 | "with": "src/environments/environment.prod.ts" 49 | } 50 | ], 51 | "outputHashing": "all" 52 | }, 53 | "development": { 54 | "buildOptimizer": false, 55 | "optimization": false, 56 | "vendorChunk": true, 57 | "extractLicenses": false, 58 | "sourceMap": true, 59 | "namedChunks": true 60 | } 61 | }, 62 | "defaultConfiguration": "production" 63 | }, 64 | "serve": { 65 | "builder": "@angular-devkit/build-angular:dev-server", 66 | "configurations": { 67 | "production": { 68 | "browserTarget": "DxAngularApp:build:production" 69 | }, 70 | "development": { 71 | "browserTarget": "DxAngularApp:build:development" 72 | } 73 | }, 74 | "defaultConfiguration": "development" 75 | }, 76 | "extract-i18n": { 77 | "builder": "@angular-devkit/build-angular:extract-i18n", 78 | "options": { 79 | "browserTarget": "DxAngularApp:build" 80 | } 81 | }, 82 | "test": { 83 | "builder": "@angular-devkit/build-angular:karma", 84 | "options": { 85 | "main": "src/test.ts", 86 | "polyfills": "src/polyfills.ts", 87 | "tsConfig": "tsconfig.spec.json", 88 | "karmaConfig": "karma.conf.js", 89 | "assets": [ 90 | "src/favicon.ico", 91 | "src/assets" 92 | ], 93 | "styles": [ 94 | "src/styles.css" 95 | ], 96 | "scripts": [] 97 | } 98 | } 99 | } 100 | } 101 | }, 102 | "cli": { 103 | "analytics": "c8091f85-53d5-4c2b-8fab-454320d20670" 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /Angular/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | jasmine: { 17 | // you can add configuration options for Jasmine here 18 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html 19 | // for example, you can disable the random execution with `random: false` 20 | // or set a specific seed with `seed: 4321` 21 | }, 22 | clearContext: false // leave Jasmine Spec Runner output visible in browser 23 | }, 24 | jasmineHtmlReporter: { 25 | suppressAll: true // removes the duplicated traces 26 | }, 27 | coverageReporter: { 28 | dir: require('path').join(__dirname, './coverage/dx-angular-app'), 29 | subdir: '.', 30 | reporters: [ 31 | { type: 'html' }, 32 | { type: 'text-summary' } 33 | ] 34 | }, 35 | reporters: ['progress', 'kjhtml'], 36 | port: 9876, 37 | colors: true, 38 | logLevel: config.LOG_INFO, 39 | autoWatch: true, 40 | browsers: ['Chrome'], 41 | singleRun: false, 42 | restartOnFileChange: true 43 | }); 44 | }; 45 | -------------------------------------------------------------------------------- /Angular/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-app", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "watch": "ng build --watch --configuration development", 9 | "test": "ng test" 10 | }, 11 | "private": true, 12 | "dependencies": { 13 | "@angular/animations": "^18.0.3", 14 | "@angular/common": "^18.0.3", 15 | "@angular/compiler": "^18.0.3", 16 | "@angular/core": "^18.0.3", 17 | "@angular/forms": "^18.0.3", 18 | "@angular/platform-browser": "^18.0.3", 19 | "@angular/platform-browser-dynamic": "^18.0.3", 20 | "@angular/router": "^18.0.3", 21 | "devextreme": "^24.1.3", 22 | "devextreme-angular": "^24.1.3", 23 | "rxjs": "~7.8.0", 24 | "tslib": "^2.3.0", 25 | "zone.js": "~0.14.7" 26 | }, 27 | "devDependencies": { 28 | "@angular-devkit/build-angular": "^18.0.4", 29 | "@angular/cli": "~18.0.4", 30 | "@angular/compiler-cli": "^18.0.3", 31 | "@types/jasmine": "~4.3.0", 32 | "eslint": "^8.39.0", 33 | "eslint-config-devextreme": "^1.1.4", 34 | "eslint-plugin-no-only-tests": "^3.1.0", 35 | "jasmine-core": "~4.5.0", 36 | "karma": "~6.4.0", 37 | "karma-chrome-launcher": "~3.1.0", 38 | "karma-coverage": "~2.2.0", 39 | "karma-jasmine": "~5.1.0", 40 | "karma-jasmine-html-reporter": "~2.0.0", 41 | "npm-run-all": "^4.1.5", 42 | "prettier": "2.8.8", 43 | "stylelint": "^15.6.1", 44 | "stylelint-config-standard": "^33.0.0", 45 | "stylelint-config-standard-scss": "^9.0.0", 46 | "stylelint-scss": "^5.0.0", 47 | "typescript": "~5.4.5" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Angular/src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | 4 | const routes: Routes = []; 5 | 6 | @NgModule({ 7 | imports: [RouterModule.forRoot(routes)], 8 | exports: [RouterModule] 9 | }) 10 | 11 | export class AppRoutingModule { } 12 | -------------------------------------------------------------------------------- /Angular/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | ::ng-deep .dx-scrollview-bottom-pocket { 2 | display: none; 3 | } 4 | -------------------------------------------------------------------------------- /Angular/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 7 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 |
29 |
30 |
31 |
32 | 33 | 41 | 51 | 60 | 61 |
62 | 66 | 67 | 68 | 72 | 73 | 74 | 79 | 80 | 81 | 82 | 86 | 87 | 88 | 89 | 90 | 91 | 95 | 100 | 101 | 102 | 106 | 107 | 108 | 114 | 115 | 116 | 117 | 121 | 122 | 123 | 124 | 128 | 129 | 130 | 131 | 132 | 133 |
134 |
{{ data.text }}
135 |
136 |
137 | 138 |
139 |
140 | 141 | Additional 142 |
143 | {{ data.text }} 144 |
145 | 146 | 151 |
152 |
153 | This field must not exceed 200 characters 154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 | 162 | -------------------------------------------------------------------------------- /Angular/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async () => { 7 | await TestBed.configureTestingModule({ 8 | imports: [ 9 | RouterTestingModule 10 | ], 11 | declarations: [ 12 | AppComponent 13 | ], 14 | }).compileComponents(); 15 | }); 16 | 17 | it('should create the app', () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.componentInstance; 20 | expect(app).toBeTruthy(); 21 | }); 22 | 23 | it(`should have as title 'DxAngularApp'`, () => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | const app = fixture.componentInstance; 26 | expect(app.title).toEqual('DxAngularApp'); 27 | }); 28 | 29 | it('should render title', () => { 30 | const fixture = TestBed.createComponent(AppComponent); 31 | fixture.detectChanges(); 32 | const compiled = fixture.nativeElement as HTMLElement; 33 | expect(compiled.querySelector('.content span')?.textContent).toContain('DxAngularApp app is running!'); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /Angular/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, ViewChild } from '@angular/core'; 2 | import { DxDataGridComponent } from 'devextreme-angular'; 3 | 4 | import validationEngine from 'devextreme/ui/validation_engine'; 5 | 6 | import ArrayStore from 'devextreme/data/array_store'; 7 | import { Employee, Service } from './app.service'; 8 | 9 | type PositionEditorOptions = { 10 | items: string[], 11 | searchEnabled: boolean 12 | } 13 | 14 | @Component({ 15 | selector: 'app-root', 16 | templateUrl: './app.component.html', 17 | styleUrls: ['./app.component.css'], 18 | providers: [Employee, Service] 19 | }) 20 | 21 | export class AppComponent { 22 | @ViewChild("grid", {static: false}) grid: DxDataGridComponent; 23 | 24 | employees: Employee[]; 25 | employeeStore: ArrayStore; 26 | 27 | formData: Employee[]; 28 | isNewRecord = true; 29 | visible = false; 30 | 31 | positionEditorOptions: PositionEditorOptions; 32 | notesEditorOptions = { height: 90, maxLength: 200 }; 33 | phoneEditorOptions = { 34 | mask: "+1 (X00) 000-0000", 35 | maskRules: { X: /[02-9]/ }, 36 | maskInvalidMessage: "The phone must have a correct USA phone format", 37 | }; 38 | 39 | labelTemplates = [ 40 | { name: "name", icon: "dx-icon-user" }, 41 | { name: "position", icon: "dx-icon-info" }, 42 | { name: "date", icon: "dx-icon-event" }, 43 | { name: "address", icon: "dx-icon-home" }, 44 | { name: "phone", icon: "dx-icon-tel" }, 45 | { name: "email", icon: "dx-icon-email" }, 46 | ]; 47 | 48 | get validationGroupName() { 49 | return "gridForm"; 50 | } 51 | 52 | showPopup = (isNewRecord, formData) => { 53 | this.formData = formData; 54 | this.isNewRecord = isNewRecord; 55 | this.visible = true; 56 | }; 57 | 58 | hidePopup = () => { 59 | this.visible = false; 60 | }; 61 | 62 | confirmChanges = () => { 63 | const result = validationEngine.validateGroup(this.validationGroupName); 64 | 65 | if (!result.isValid) 66 | return; 67 | 68 | if (this.isNewRecord) 69 | this.employeeStore.insert(this.formData); 70 | else 71 | this.employeeStore.update(this.formData["ID"], this.formData); 72 | 73 | this.grid.instance.refresh(true); 74 | this.hidePopup(); 75 | }; 76 | 77 | addRow = () => { 78 | this.showPopup(true, {}); 79 | }; 80 | 81 | editRow = (e) => { 82 | this.showPopup(false, {...e.row.data}); 83 | }; 84 | 85 | constructor(service: Service) { 86 | this.employees = service.getEmployees(); 87 | 88 | this.employeeStore = new ArrayStore({ 89 | data: this.employees, 90 | key: "ID", 91 | }); 92 | 93 | this.positionEditorOptions = { items: service.getPositions(), searchEnabled: true }; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Angular/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { DxPopupModule } from "devextreme-angular/ui/popup"; 4 | 5 | import { 6 | DxDataGridModule, 7 | DxTemplateModule, 8 | DxButtonModule, 9 | } from 'devextreme-angular'; 10 | 11 | import { 12 | DxSelectBoxModule, 13 | DxTextAreaModule, 14 | DxFormModule, 15 | DxTooltipModule, 16 | } from 'devextreme-angular'; 17 | 18 | import { AppComponent } from './app.component'; 19 | 20 | @NgModule({ 21 | declarations: [ 22 | AppComponent 23 | ], 24 | imports: [ 25 | BrowserModule, 26 | DxPopupModule, 27 | DxSelectBoxModule, 28 | DxTextAreaModule, 29 | DxFormModule, 30 | DxTooltipModule, 31 | DxDataGridModule, 32 | DxTemplateModule, 33 | DxButtonModule 34 | ], 35 | providers: [], 36 | bootstrap: [AppComponent] 37 | }) 38 | 39 | export class AppModule { } 40 | -------------------------------------------------------------------------------- /Angular/src/app/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | export class Employee { 4 | ID: number; 5 | FirstName: string; 6 | LastName: string; 7 | Prefix: string; 8 | Position: string; 9 | BirthDate: string; 10 | HireDate: string; 11 | Notes: string; 12 | Address: string; 13 | Phone: string; 14 | Email: string; 15 | } 16 | 17 | const employees: Employee[] = [{ 18 | ID: 1, 19 | FirstName: 'John', 20 | LastName: 'Heart', 21 | Prefix: 'Mr.', 22 | Position: 'CEO', 23 | BirthDate: '1964/03/16', 24 | HireDate: '1995/01/15', 25 | Notes: 'John has been in the Audio/Video industry since 1990. He has led DevAv as its CEO since 2003.\r\n\r\nWhen not working hard as the CEO, John loves to golf and bowl. He once bowled a perfect game of 300.', 26 | Address: '351 S Hill St.', 27 | Phone: '16102458448', 28 | Email: 'rohitm@hotmail.com', 29 | }, { 30 | ID: 2, 31 | FirstName: 'Olivia', 32 | LastName: 'Peyton', 33 | Prefix: 'Mrs.', 34 | Position: 'Sales Assistant', 35 | BirthDate: '1981/06/03', 36 | HireDate: '2012/05/14', 37 | Notes: 'Olivia loves to sell. She has been selling DevAV products since 2012. \r\n\r\nOlivia was homecoming queen in high school. She is expecting her first child in 6 months. Good Luck Olivia.', 38 | Address: '807 W Paseo Del Mar', 39 | Phone: '16102347905', 40 | Email: 'spadkins@optonline.net', 41 | }, { 42 | ID: 3, 43 | FirstName: 'Robert', 44 | LastName: 'Reagan', 45 | Prefix: 'Mr.', 46 | Position: 'CMO', 47 | BirthDate: '1974/09/07', 48 | HireDate: '2002/11/08', 49 | Notes: 'Robert was recently voted the CMO of the year by CMO Magazine. He is a proud member of the DevAV Management Team.\r\n\r\nRobert is a championship BBQ chef, so when you get the chance ask him for his secret recipe.', 50 | Address: '4 Westmoreland Pl.', 51 | Phone: '14845219762', 52 | Email: 'naoya@comcast.net', 53 | }, { 54 | ID: 4, 55 | FirstName: 'Greta', 56 | LastName: 'Sims', 57 | Prefix: 'Ms.', 58 | Position: 'HR Manager', 59 | BirthDate: '1977/11/22', 60 | HireDate: '1998/04/23', 61 | Notes: "Greta has been DevAV's HR Manager since 2003. She joined DevAV from Sonee Corp.\r\n\r\nGreta is currently training for the NYC marathon. Her best marathon time is 4 hours. Go Greta.", 62 | Address: '1700 S Grandview Dr.', 63 | Phone: '14844578858', 64 | Email: 'tattooman@optonline.net', 65 | }, { 66 | ID: 5, 67 | FirstName: 'Brett', 68 | LastName: 'Wade', 69 | Prefix: 'Mr.', 70 | Position: 'IT Manager', 71 | BirthDate: '1968/12/01', 72 | HireDate: '2009/03/06', 73 | Notes: 'Brett came to DevAv from Microsoft and has led our IT department since 2012.\r\n\r\nWhen he is not working hard for DevAV, he coaches Little League (he was a high school pitcher).', 74 | Address: '1120 Old Mill Rd.', 75 | Phone: '18143008837', 76 | Email: 'haddawy@mac.com', 77 | }, { 78 | ID: 6, 79 | FirstName: 'Sandra', 80 | LastName: 'Johnson', 81 | Prefix: 'Mrs.', 82 | Position: 'Controller', 83 | BirthDate: '1974/11/15', 84 | HireDate: '2005/05/11', 85 | Notes: "Sandra is a CPA and has been our controller since 2008. She loves to interact with staff so if you've not met her, be certain to say hi.\r\n\r\nSandra has 2 daughters both of whom are accomplished gymnasts.", 86 | Address: '4600 N Virginia Rd.', 87 | Phone: '15852826538', 88 | Email: 'gordonjcp@gmail.com', 89 | }, { 90 | ID: 7, 91 | FirstName: 'Kevin', 92 | LastName: 'Carter', 93 | Prefix: 'Mr.', 94 | Position: 'Shipping Manager', 95 | BirthDate: '1978/01/09', 96 | HireDate: '2009/08/11', 97 | Notes: 'Kevin is our hard-working shipping manager and has been helping that department work like clockwork for 18 months.\r\n\r\nWhen not in the office, he is usually on the basketball court playing pick-up games.', 98 | Address: '424 N Main St.', 99 | Phone: '14844760152', 100 | Email: 'chance@verizon.net', 101 | }, { 102 | ID: 8, 103 | FirstName: 'Cynthia', 104 | LastName: 'Stanwick', 105 | Prefix: 'Ms.', 106 | Position: 'HR Manager', 107 | BirthDate: '1985/06/05', 108 | HireDate: '2008/03/24', 109 | Notes: 'Cindy joined us in 2008 and has been in the HR department for 2 years. \r\n\r\nShe was recently awarded employee of the month. Way to go Cindy!', 110 | Address: '2211 Bonita Dr.', 111 | Phone: '14842989304', 112 | Email: 'kevinm@verizon.net', 113 | }, { 114 | ID: 9, 115 | FirstName: 'Kent', 116 | LastName: 'Samuelson', 117 | Prefix: 'Dr.', 118 | Position: 'Support Manager', 119 | BirthDate: '1972/09/11', 120 | HireDate: '2009/04/22', 121 | Notes: 'As our ombudsman, Kent is on the front-lines solving customer problems and helping our partners address issues out in the field. He is a classically trained musician and is a member of the Chamber Orchestra.', 122 | Address: '12100 Mora Dr', 123 | Phone: '14844731660', 124 | Email: 'arebenti@outlook.com', 125 | }, { 126 | ID: 10, 127 | FirstName: 'Taylor', 128 | LastName: 'Riley', 129 | Prefix: 'Mr.', 130 | Position: 'Sales Manager', 131 | BirthDate: '1982/08/14', 132 | HireDate: '2012/04/14', 133 | Notes: "If you are like the rest of us at DevAV, then you've probably reached out for help from Taylor. He does a great job as a member of our IT department.", 134 | Address: '7776 Torreyson Dr', 135 | Phone: '14842989306', 136 | Email: 'amichalo@live.com', 137 | }]; 138 | 139 | 140 | 141 | const positions: string[] = [ 142 | 'HR Manager', 143 | 'IT Manager', 144 | 'CEO', 145 | 'Controller', 146 | 'Sales Manager', 147 | 'Support Manager', 148 | 'Shipping Manager', 149 | 'Sales Assistant', 150 | 'CMO', 151 | ]; 152 | 153 | @Injectable() 154 | export class Service { 155 | getEmployees(): Employee[] { 156 | return employees; 157 | } 158 | 159 | getPositions(): string[] { 160 | return positions; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /Angular/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/devextreme-datagrid-custom-editing-form/fa6530f5a32db0e612d7d83db7320e0bff0c1072/Angular/src/assets/.gitkeep -------------------------------------------------------------------------------- /Angular/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /Angular/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /Angular/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/devextreme-datagrid-custom-editing-form/fa6530f5a32db0e612d7d83db7320e0bff0c1072/Angular/src/favicon.ico -------------------------------------------------------------------------------- /Angular/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Angular App 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Angular/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /Angular/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes recent versions of Safari, Chrome (including 12 | * Opera), Edge on the desktop, and iOS and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** 22 | * By default, zone.js will patch all possible macroTask and DomEvents 23 | * user can disable parts of macroTask/DomEvents patch by setting following flags 24 | * because those flags need to be set before `zone.js` being loaded, and webpack 25 | * will put import in the top of bundle, so user need to create a separate file 26 | * in this directory (for example: zone-flags.ts), and put the following flags 27 | * into that file, and then add the following code before importing zone.js. 28 | * import './zone-flags'; 29 | * 30 | * The flags allowed in zone-flags.ts are listed here. 31 | * 32 | * The following flags will work for all browsers. 33 | * 34 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 35 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 36 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 37 | * 38 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 39 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 40 | * 41 | * (window as any).__Zone_enable_cross_context_check = true; 42 | * 43 | */ 44 | 45 | /*************************************************************************************************** 46 | * Zone JS is required by default for Angular itself. 47 | */ 48 | import 'zone.js'; // Included with Angular CLI. 49 | 50 | 51 | /*************************************************************************************************** 52 | * APPLICATION IMPORTS 53 | */ 54 | -------------------------------------------------------------------------------- /Angular/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /Angular/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: { 11 | context(path: string, deep?: boolean, filter?: RegExp): { 12 | (id: string): T; 13 | keys(): string[]; 14 | }; 15 | }; 16 | 17 | // First, initialize the Angular testing environment. 18 | getTestBed().initTestEnvironment( 19 | BrowserDynamicTestingModule, 20 | platformBrowserDynamicTesting(), 21 | ); 22 | 23 | // Then we find all the tests. 24 | const context = require.context('./', true, /\.spec\.ts$/); 25 | // And load the modules. 26 | context.keys().forEach(context); 27 | -------------------------------------------------------------------------------- /Angular/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts", 10 | "src/polyfills.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /Angular/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "experimentalDecorators": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "target": "es2015", 14 | "paths": { 15 | "jszip": [ 16 | "node_modules/jszip/dist/jszip.min.js" 17 | ], 18 | "globalize": [ 19 | "node_modules/globalize/dist/globalize" 20 | ], 21 | "globalize/*": [ 22 | "node_modules/globalize/dist/globalize/*" 23 | ], 24 | "cldr": [ 25 | "node_modules/cldrjs/dist/cldr" 26 | ], 27 | "cldr/*": [ 28 | "node_modules/cldrjs/dist/cldr/*" 29 | ] 30 | }, 31 | "typeRoots": [ 32 | "node_modules/@types" 33 | ], 34 | "lib": [ 35 | "es2018", 36 | "dom" 37 | ] 38 | }, 39 | "angularCompilerOptions": { 40 | "enableIvy": true, 41 | "fullTemplateTypeCheck": true, 42 | "strictInjectionParameters": true 43 | } 44 | } -------------------------------------------------------------------------------- /Angular/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @DevExpressExampleBot -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This code example is provided "as is" without warranty of any kind. Developer Express Inc ("DevExpress") disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. 2 | 3 | For licensing terms and conditions of DevExpress product(s) required for, or associated with the use of this code example, please refer to the applicable End-User License Agreement at https://www.devexpress.com/Support/licensingfaq.xml -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ![](https://img.shields.io/endpoint?url=https://codecentral.devexpress.com/api/v1/VersionRange/263296064/24.1.3%2B) 3 | [![](https://img.shields.io/badge/Open_in_DevExpress_Support_Center-FF7200?style=flat-square&logo=DevExpress&logoColor=white)](https://supportcenter.devexpress.com/ticket/details/T888862) 4 | [![](https://img.shields.io/badge/📖_How_to_use_DevExpress_Examples-e9f6fc?style=flat-square)](https://docs.devexpress.com/GeneralInformation/403183) 5 | [![](https://img.shields.io/badge/💬_Leave_Feedback-feecdd?style=flat-square)](#does-this-example-address-your-development-requirementsobjectives) 6 | 7 | 8 | # DevExtreme DataGrid – Create a custom Pop-up Edit Form using Popup and Form components 9 | 10 | Our DataGrid component ships with a built-in Pop-up Edit Form (for data editing purposes). To create a custom pop-up form, simply use our [Popup](https://js.devexpress.com/Documentation/ApiReference/UI_Components/dxPopup/) and [Form](https://js.devexpress.com/Documentation/ApiReference/UI_Components/dxForm/) UI components as follows: 11 | 12 | Implement a DataGrid callback function that displays the Popup when a user clicks the built-in "Add row" button. Add a Form to the Popup [contentTemplate](https://js.devexpress.com/Documentation/ApiReference/UI_Components/dxPopup/Configuration/#contentTemplate) and specify desired Popup [toolbar buttons](https://js.devexpress.com/Documentation/ApiReference/UI_Components/dxPopup/Configuration/toolbarItems/). Next, call a function that updates the DataGrid data source once users enter/modify Form values and submit changes (by pressing the "Confirm" button). 13 | 14 |
DataGrid for DevExtreme - How to implement a custom editing form using the Popup and Form components
15 | 16 | ## Files to Review 17 | 18 | - **jQuery** 19 | - [index.html](jQuery/src/index.html) 20 | - [index.js](jQuery/src/index.js) 21 | - **Angular** 22 | - [app.component.html](Angular/src/app/app.component.html) 23 | - [app.component.ts](Angular/src/app/app.component.ts) 24 | - **Vue** 25 | - [App.vue](Vue/src/App.vue) 26 | - **React** 27 | - [App.js](React/src/App.js) 28 | - **ASP.NET Core** 29 | - [Index.cshtml](ASP.NET%20Core/Views/Home/Index.cshtml) 30 | 31 | ## Documentation 32 | 33 | - [Getting Started with DataGrid](https://js.devexpress.com/Documentation/Guide/UI_Components/DataGrid/Getting_Started_with_DataGrid/) 34 | - [DataGrid Popup Mode](https://js.devexpress.com/Documentation/Guide/UI_Components/DataGrid/Editing/#User_Interaction/Popup_Mode) 35 | - [DataGrid - API Reference](https://js.devexpress.com/Documentation/ApiReference/UI_Components/dxDataGrid/) 36 | - [Popup - API Reference](https://js.devexpress.com/Documentation/ApiReference/UI_Components/dxPopup/) 37 | - [Form - API Reference](https://js.devexpress.com/Documentation/ApiReference/UI_Components/dxForm/) 38 | 39 | ## Does this example address your development requirements/objectives? 40 | 41 | [](https://www.devexpress.com/support/examples/survey.xml?utm_source=github&utm_campaign=devextreme-datagrid-custom-editing-form&~~~was_helpful=yes) [](https://www.devexpress.com/support/examples/survey.xml?utm_source=github&utm_campaign=devextreme-datagrid-custom-editing-form&~~~was_helpful=no) 42 | 43 | (you will be redirected to DevExpress.com to submit your response) 44 | 45 | -------------------------------------------------------------------------------- /React/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /React/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `npm start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser. 13 | 14 | The page will reload when you make changes.\ 15 | You may also see any lint errors in the console. 16 | 17 | ### `npm test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://create-react-app.dev/docs/running-tests/) for more information. 21 | 22 | ### `npm run build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://create-react-app.dev/docs/deployment//) for more information. 31 | 32 | ### `npm run eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can't go back!** 35 | 36 | If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. 39 | 40 | You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://create-react-app.dev/docs/getting-started/). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://create-react-app.dev/docs/code-splitting/](https://create-react-app.dev/docs/code-splitting/) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://create-react-app.dev/docs/analyzing-the-bundle-size/](https://create-react-app.dev/docs/analyzing-the-bundle-size/) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://create-react-app.dev/docs/making-a-progressive-web-app/](https://create-react-app.dev/docs/making-a-progressive-web-app/) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://create-react-app.dev/docs/advanced-configuration/](https://create-react-app.dev/docs/advanced-configuration/) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://create-react-app.dev/docs/deployment//](https://create-react-app.dev/docs/deployment//) 67 | 68 | ### `npm run build` fails to minify 69 | 70 | This section has moved here: [https://create-react-app.dev/docs/troubleshooting/](https://create-react-app.dev/docs/troubleshooting/) 71 | -------------------------------------------------------------------------------- /React/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.5", 7 | "@testing-library/react": "^13.4.0", 8 | "@testing-library/user-event": "^13.5.0", 9 | "devextreme": "22.2.5", 10 | "devextreme-react": "22.2.5", 11 | "react": "^18.2.0", 12 | "react-dom": "^18.2.0", 13 | "react-scripts": "5.0.1", 14 | "web-vitals": "^2.1.4" 15 | }, 16 | "scripts": { 17 | "start": "react-scripts start", 18 | "build": "react-scripts build", 19 | "test": "react-scripts test", 20 | "eject": "react-scripts eject" 21 | }, 22 | "eslintConfig": { 23 | "extends": [ 24 | "react-app", 25 | "react-app/jest" 26 | ] 27 | }, 28 | "browserslist": { 29 | "production": [ 30 | ">0.2%", 31 | "not dead", 32 | "not op_mini all" 33 | ], 34 | "development": [ 35 | "last 1 chrome version", 36 | "last 1 firefox version", 37 | "last 1 safari version" 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /React/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/devextreme-datagrid-custom-editing-form/fa6530f5a32db0e612d7d83db7320e0bff0c1072/React/public/favicon.ico -------------------------------------------------------------------------------- /React/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 18 | 19 | 28 | React App 29 | 30 | 31 | 32 |
33 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /React/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/devextreme-datagrid-custom-editing-form/fa6530f5a32db0e612d7d83db7320e0bff0c1072/React/public/logo192.png -------------------------------------------------------------------------------- /React/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevExpress-Examples/devextreme-datagrid-custom-editing-form/fa6530f5a32db0e612d7d83db7320e0bff0c1072/React/public/logo512.png -------------------------------------------------------------------------------- /React/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /React/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /React/public/style.css: -------------------------------------------------------------------------------- 1 | 2 | #helpedInfo { 3 | color: #42a5f5; 4 | } 5 | 6 | #tooltip-content { 7 | font-size: 14px; 8 | font-weight: bold; 9 | } 10 | 11 | #template-content { 12 | display: inline-flex; 13 | } 14 | -------------------------------------------------------------------------------- /React/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /React/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { useCallback, useState, useMemo, useRef } from 'react'; 2 | 3 | import 'devextreme/dist/css/dx.light.css'; 4 | import './App.css'; 5 | 6 | import DataGrid, { Column, Editing, Button, Toolbar } from 'devextreme-react/data-grid'; 7 | import Popup, { ToolbarItem } from 'devextreme-react/popup'; 8 | import Form, { Item, GroupItem, Label } from 'devextreme-react/form'; 9 | import validationEngine from 'devextreme/ui/validation_engine'; 10 | import AddRowButton from 'devextreme-react/button'; 11 | import LabelTemplate from './LabelTemplate.js'; 12 | import LabelNotesTemplate from './LabelNotesTemplate.js'; 13 | import 'devextreme-react/text-area'; 14 | 15 | import ArrayStore from 'devextreme/data/array_store'; 16 | 17 | import { employees } from './data.js'; 18 | 19 | import { 20 | validationRules, 21 | positionEditorOptions, 22 | notesEditorOptions, 23 | phoneEditorOptions 24 | } from './ValidationRulesAndEditorOptions.js'; 25 | 26 | const employeeStore = new ArrayStore({ 27 | data: employees, 28 | key: "ID", 29 | }); 30 | 31 | const validationGroupName = "gridForm"; 32 | const App = () => { 33 | const gridRef = useRef(null); 34 | const [{isNewRecord, formData, visible}, setPopupState] = useState({}); 35 | 36 | const showPopup = useCallback((isNewRecord, formData) => { 37 | setPopupState({isNewRecord, formData, visible: true}); 38 | }, []); 39 | 40 | const hidePopup = useCallback(() => { 41 | setPopupState({visible: false}); 42 | }, []); 43 | 44 | const confirmChanges = useCallback(() => { 45 | const result = validationEngine.validateGroup(validationGroupName); 46 | 47 | if (!result.isValid) 48 | return; 49 | 50 | if (isNewRecord) 51 | employeeStore.insert(formData); 52 | else 53 | employeeStore.update(formData["ID"], formData); 54 | 55 | gridRef.current.instance.refresh(true); 56 | hidePopup(); 57 | 58 | }, [isNewRecord, formData, hidePopup]); 59 | 60 | const confirmBtnOptions = useMemo(() => { 61 | return { 62 | text: "Confirm", 63 | type: "success", 64 | onClick: confirmChanges 65 | } 66 | }, [confirmChanges]); 67 | 68 | const cancelBtnOptions = useMemo(() => { 69 | return { 70 | text: "Cancel", 71 | onClick: hidePopup 72 | } 73 | }, [hidePopup]); 74 | 75 | const editRow = useCallback((e) => { 76 | showPopup(false, {...e.row.data}); 77 | }, [showPopup]); 78 | 79 | const addRow = useCallback(() => { 80 | showPopup(true, {}); 81 | }, [showPopup]); 82 | 83 | return ( 84 | 85 | 91 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 |