Want to become a Vibe Coder? Join Vibe Coding Training here
x
C# Corner
Tech
News
Videos
Forums
Jobs
Books
Events
More
Interviews
Live
Learn
Training
Career
Members
Blogs
Challenges
Certification
Contribute
Article
Blog
Video
Ebook
Interview Question
.NET
.NET Assemblies
.NET Core
.NET Standard
Active Directory
ADO.NET
Agile Development
AJAX
Alexa Skills
Algorithms in C#
Android
Angular
Architecture
ArcObject
Artificial Intelligence
ASP.NET
ASP.NET Core
Augmented Reality
Aurelia
AWS
Azure
Backbonejs
Big Data
BizTalk Server
Blockchain
Bootstrap
Bot Framework
Business
C#
C# Corner
C, C++, MFC
Career Advice
Chapters
CIO
Cloud
COBOL.NET
Coding Best Practices
Cognitive Services
COM Interop
Compact Framework
Cortana Development
Cryptocurrency
Cryptography
Crystal Reports
Current Affairs
Custom Controls
Cyber Security
Data Mining
Databases & DBA
Design Patterns & Practices
DevOps
DirectX
Dynamics CRM
Enterprise Development
Entity Framework
Error Zone
Exception Handling
Expression Studio
F#
Files, Directory, IO
Games Programming
GDI+
General
Generative Engine Optimization (GEO)
Google Cloud
Google Development
Graphics Design
Hardware
Hiring and Recruitment
HoloLens
How do I
HTML 5
Internet & Web
Internet of Things
Ionic
iOS
Java
Java and .NET
JavaScript
JQuery
JSON
JSP
Knockout
kotlin
Leadership
Learn .NET
LightSwitch
LINQ
Machine Learning
Microsoft 365
Microsoft Office
Microsoft Phone
Mobile Development
Multithreading
Nano Banana
NetBeans
Networking
Node.js
Office Development
OOP/OOD
Open Source
Operating Systems
Oracle
Outsourcing
Philosophy
PHP
Power BI
Printing in C#
Products
Progressive Web Apps
Project Management
Python
Q#
QlikView
R
React
Reports using C#
Robotics & Hardware
Ruby on Rails
Salesforce
Security
Servers
SharePoint
SignalR
Silverlight
Smart Devices
Software Testing
SQL Language
SQL Server
Startups
String in C#
Swift
TypeScript
Unity
UWP
Visual Basic .NET
Visual Studio
WCF
Wearables
Web Development
Web Services
Web3
Windows 10
Windows Controls
Windows Forms
Windows PowerShell
Windows Services
Workflow Foundation
WPF
Xamarin
XAML Standard
XML
XNA
XSharp
Register
Login
2
Answers
MVC - Related Data - Postback
Pinpoint Solutions
10y
774
0
1
Others
Reply
Hi all,
I have an MVC 5 generated "Create" page. Now for the related data I have made a table, which looks like this:
When clicking on the green add button, the following modal is shown:
In this design, the user is able to add/remove sub-items to the list before submitting the form.
In this example, the row in the screenshot I add initially. All works well, except when I remove this initial row in my Create action (which shouldn't be there anyway, it should start with an empty table) no rows added are available on the server. Somehow, the Model Binder only works when there's initially 1 row rendered from the create action.
Data Model:
Controller actions:
(
OrganisatieController.cs
)
public
ActionResult
Create()
{
Organisatie
myOrganisatie =
new
Organisatie
();
//-- Test Data --
AccountType_Organisatie
myAccTypeOrg =
new
AccountType_Organisatie
();
myAccTypeOrg.Accounttype_GUID = csContext.AccountTypes.First().AccountType_GUID;
myAccTypeOrg.AccountType = csContext.AccountTypes.First();
myAccTypeOrg.Omschrijving =
"Test1234"
;
myOrganisatie.AccountType_Organisaties.Add(myAccTypeOrg);
//-- End Test Data –
//-- Load Dropdown Data --
ViewBag.slAccountTypes =
new
SelectList
(csContext.AccountTypes,
"AccountType_GUID"
,
Omschrijving"
);
return
View(myOrganisatie);
}
[
HttpPost
]
[
ValidateAntiForgeryToken
]
public
ActionResult
Create(
[
Bind
(Include =
"Organisatie_GUID,OrganisatieID,OrganisatieNaam,Startdatum,Einddatum,Afkorting,Manager_GUID,AanleverendePartij,BovenliggendeOrganisatie_GUID,AccountType_Organisaties"
)]
Organisatie
myOrg)
{
try
{
int
x = 0;
foreach
(
AccountType_Organisatie
myAccType_Org
in
myOrg.AccountType_Organisaties)
{
myAccType_Org.AccountType_Organisatie_GUID =
Guid
.NewGuid();
myAccType_Org.AccountType = csContext.AccountTypes.Find(myAccType_Org.Accounttype_GUID);
//-- Remove Related Model Validation errors --
ModelState.Remove(
String
.Format(
"AccountType_Organisaties[{0}].AccountType.Omschrijving"
, x));
ModelState.Remove(
String
.Format(
"AccountType_Organisaties[{0}].AccountType.Domein"
, x));
ModelState.Remove(
String
.Format(
"AccountType_Organisaties[{0}].AccountType.UPN_DomainTag"
, x));
ModelState.Remove(
String
.Format(
"AccountType_Organisaties[{0}].AccountType.Graceperiod"
, x));
x++;
}
if
(ModelState.IsValid)
{
myOrg.Organisatie_GUID =
Guid
.NewGuid();
//-- Update related data with new GUID --
foreach
(
AccountType_Organisatie
myAccType_Org
in
myOrg.AccountType_Organisaties)
{
myAccType_Org.Organisatie_GUID = myOrg.Organisatie_GUID;
}
csContext.Organisaties.Add(myOrg);
csContext.SaveChanges();
return
RedirectToAction(
"Index"
);
}
}
catch
(System.Data.
DataException
ex)
{
ModelState.AddModelError(
""
,
"Could not create the Organisation. [Reason: "
+ ex.Message +
"]"
);
}
//-- Load Dropdown Data --
ViewBag.slAccountTypes =
new
SelectList
(csContext.AccountTypes,
"AccountType_GUID"
,
Omschrijving"
);
return
View(myOrg);
}
ViewPage
: (
Create.shtml
)
@model
ConfiguratorWeb.Models.
Organisatie
@section Styles {
@
Styles
.Render(
"~/bundles/data-input-css"
)
}
@{
ViewBag.Title =
"Nieuwe Organisatie"
;
Layout =
"~/Views/Shared/_Layout.cshtml"
;
}
@
using
(Html.BeginForm())
{
@
Html.AntiForgeryToken()
<
div
class
="form-horizontal">
@
Html.ValidationSummary(
true
)
@
Html.HiddenFor(model => model.Organisatie_GUID)
<
div
class
="form-group">
@
Html.LabelFor(model => model.OrganisatieID,
new
{ @class =
"control-label col-md-2"
})
<
div
class
="col-md-10">
@
Html.EditorFor(model => model.OrganisatieID)
@
Html.ValidationMessageFor(model => model.OrganisatieID)
</
div
>
</
div
>
<
div
class
="form-group">
@
Html.LabelFor(model => model.OrganisatieNaam,
new
{ @class =
"control-label col-md-2"
})
<
div
class
="col-md-10">
@
Html.EditorFor(model => model.OrganisatieNaam)
@
Html.ValidationMessageFor(model => model.OrganisatieNaam)
</
div
>
</
div
>
<
hr
/>
<
div
class
="h4">
Account Types
</
div
>
<
br
/>
<
table
id
="tblAccountTypes"
data-toggle
="table"
style
="
visibility
:
visible
;
">
<
thead
>
<
tr
>
<
th
>
GUID
</
th
>
<
th
>
Item Name
</
th
>
<
th
>
Omschrijving
</
th
>
<
th
></
th
>
</
tr
>
</
thead
>
<
tbody
>
@
Html.EditorFor(model => model.AccountType_Organisaties)
</
tbody
>
</
table
>
<
button
id
="btnAddAccountType"
type
="button"
class
="btn btn-success btn-xs btn-glyph-xs"
title
="Add AccountType"
onclick
="
showModal();
"
style
="
margin-top
:
10px
;
">
<
span
class
="glyphicon glyphicon-plus"></
span
>
</
button
>
<
hr
/>
@{
Html.RenderPartial(
"_ActionButtons"
,
new
ViewDataDictionary
{ {
"SubmitClientClick"
,
"return fixIndexing();"
} });
}
</
div
>
}
<
div
id
="modalAddAccountType"
class
="modal fade">
<
div
class
="modal-dialog">
<
div
class
="modal-content">
<
div
class
="modal-header">
<
button
type
="button"
class
="close"
data-dismiss
="modal"
aria-label
="Close"><
span
aria-hidden
="true">
×
</
span
></
button
>
<
h4
class
="modal-title">
AccountType toevoegen
</
h4
>
</
div
>
<
div
class
="modal-body">
<
p
>
Kies hieronder het AccountType dat u wilt toevoegen aan de Organisatie.
</
p
>
<
br
/>
<
div
class
="form-horizontal">
<
div
class
="form-group">
<
label
class
="control-label col-md-2">
Account Type
</
label
>
<
div
class
="col-md-10">
@
Html.DropDownList(
"ddlAccountType"
, (
IEnumerable
<
SelectListItem
>)ViewData[
"slAccountTypes"
],
""
,
new
{ @class =
"form-control dropdown"
})
<
label
id
="lblAccountType_Required"
class
="h6 control-label"
style
="
visibility
:
hidden
;
">
U dient een Account type te selecteren
</
label
>
</
div
>
</
div
>
<
div
class
="form-group">
<
label
class
="control-label col-md-2">
Omschrijving
</
label
>
<
div
class
="col-md-10">
@
Html.TextBox(
"txtOmschrijving"
,
null
,
new
{ @class =
"form-control"
})
<
label
id
="lblOmschrijving_Required"
class
="h6 control-label"
style
="
visibility
:
hidden
;
">
U dient een omschrijving in te voeren
</
label
>
</
div
>
</
div
>
</
div
>
</
div
>
<
div
class
="modal-footer">
<
button
type
="button"
class
="btn btn-default"
data-dismiss
="modal">
Sluiten
</
button
>
<
button
type
="button"
class
="btn btn-primary"
onclick
="
addAccountType();
">
Toevoegen
</
button
>
</
div
>
</
div
>
<!-- /.modal-content -->
</
div
>
<!-- /.modal-dialog -->
</
div
>
<!-- /.modal -->
@section Scripts {
@
Scripts
.Render(
"~/bundles/jqueryval"
)
@
Scripts
.Render(
"~/bundles/data-input-js"
)
<
script
>
$(document).ready(
function
() {
$(
'#tblAccountTypes'
).bootstrapTable(
'hideLoading'
,
null
);
//$('.no-records-found').remove();
//-- Add onclick handler to Delete button --
$(
'[id^="btnDelete_"]'
).on(
"click"
, deleteRow);
});
function
showModal() {
$(
'#modalAddAccountType'
).modal();
}
function
addAccountType() {
var
IsValid =
true
;
var
AccountType_GUID = $(
'#ddlAccountType option:selected'
).val();
var
AccountType_Naam = $(
'#ddlAccountType option:selected'
).text();
var
Omschrijving = $(
'#txtOmschrijving'
).val();
if
(IsValid) {
//-- Determine index to be used --
var
Index = 0;
//-- Add new row to table --
var
newRow =
"<tr data-index=\""
+ Index +
"\">"
;
newRow +=
"<td><input id=\"AccountType_Organisaties_"
+ Index +
"__Accounttype_GUID\" name=\"AccountType_Organisaties["
+ Index +
"].Accounttype_GUID\" type=\"hidden\" value=\""
+ AccountType_GUID +
"\">"
+ AccountType_GUID +
"</td>"
;
newRow +=
"<td><input id=\"AccountType_Organisaties_"
+ Index +
"__AccountType_Omschrijving\" name=\"AccountType_Organisaties["
+ Index +
"].AccountType.Omschrijving\" value=\""
+ AccountType_Naam +
"\" type=\"hidden\">"
+ AccountType_Naam +
"</td>"
;
newRow +=
"<td><input id=\"AccountType_Organisaties_"
+ Index +
"__Omschrijving\" name=\"AccountType_Organisaties["
+ Index +
"].Omschrijving\" type=\"hidden\" value=\""
+ Omschrijving +
"\">"
+ Omschrijving +
"</td>"
;
newRow +=
"<td><button id=\"btnDelete_"
+ AccountType_GUID +
"\" type=\"button\" class=\"btn btn-success btn-xs btn-glyph-xs\" title=\"Verwijderen\"><span class='glyphicon glyphicon-remove'></span></button></td></tr>"
;
$(
'#tblAccountTypes tbody:last'
).append(newRow);
//-- Add onclick handler to Delete button --
$(
'#btnDelete_'
+ AccountType_GUID).on(
"click"
, deleteRow);
//-- Remove Item from Dropdownlist in Modal --
$(
'#ddlAccountType'
).find(
'option[value='
+ AccountType_GUID +
']'
).remove();
//-- Close Modal --
$(
'#modalAddAccountType'
).modal(
'toggle'
);
}
}
function
fixIndexing() {
var
tableRows = $(
'#tblAccountTypes tbody tr'
);
for
(x = 0; x < tableRows.length; x++) {
tableRows.eq(x).attr(
'data-index'
, x);
tableRows.eq(x).children(
'td:nth-child(1)'
).children(
'input:first'
).attr(
'name'
,
'AccountType_Organisaties['
+ x +
"].Accounttype_GUID"
);
tableRows.eq(x).children(
'td:nth-child(2)'
).children(
'input:first'
).attr(
'name'
,
'AccountType_Organisaties['
+ x +
"].AccountType.Omschrijving"
);
tableRows.eq(x).children(
'td:nth-child(3)'
).children(
'input:first'
).attr(
'name'
,
'AccountType_Organisaties['
+ x +
"].Omschrijving"
);
}
return
true
;
//- Submit Form -
}
function
deleteRow() {
//-- Add Item to Dropdownlist in Modal --
var
row = $(
this
).parents(
'tr'
);
var
Account_GUID = row.children(
'td:nth-child(1)'
).text();
var
Account_Naam = row.children(
'td:nth-child(2)'
).text();
$(
'#ddlAccountType'
).append(
new
Option(Account_Naam, Account_GUID));
//-- Remove row from table --
row.remove();
}
</
script
>
}
And finally the
Editor Template
for the related data (
AccountType_Organisatie.cshtml
):
@model
ConfiguratorWeb.Models.
AccountType_Organisatie
<
tr
>
<
td
>
@
Html.HiddenFor(x => Model.Accounttype_GUID)
@
Model.Accounttype_GUID
</
td
>
<
td
>
@
Html.HiddenFor(x => Model.AccountType.Omschrijving,
new
{ data_val =
false
})
@
Model.AccountType.Omschrijving
</
td
>
<
td
>
@
Html.HiddenFor(x => Model.Omschrijving,
new
{ data_val =
false
})
@
Model.Omschrijving)
</
td
>
<
td
>
<
button
id
="btnDelete_
@
Model.Accounttype_GUID
"
type
="button"
class
="btn btn-success btn-xs btn-glyph-xs"
title
="Verwijderen"
onclick
="
deleteRow()
">
<
span
class
='glyphicon glyphicon-remove'></
span
>
</
button
>
</
td
>
</
tr
>
Post
Reset
Cancel
Answers (
2
)
Related Discussion