Problems with updating modal after transfer to area - modalviewcontroller

I use modal to include new terms in dropdownlist.
<div class="form-group">
#Html.LabelFor(model => model.NatureKindID, "Kind of nature", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div id="divDropNatureKinds">
#Html.Action("ReloadDropDownListNatureKinds", "Modals")
</div>
#Ajax.ActionLink(" ", "CreateModalNatureKinds", "Modals", null, new AjaxOptions { UpdateTargetId = "modaldropbody", OnComplete = "openModal" }, new { #class = "glyphicon glyphicon-plus" })
#Html.ValidationMessageFor(model => model.NatureKindID, "", new { #class = "text-danger" })
</div>
And Also in the main form has a div where modal is building:
<div class="modal fade" id="modaldrop" role="dialog">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div id="modaldropbody" class="modal-body">
</div>
</div>
</div>
And also an script:
#section scripts {
<script>
function openModal() {
$("#modaldrop").modal()
}
</script>
}
When user hit the Action Link the "CreateModalNatureKinds" modal is open. It is a simple form and works well.
New nature types are saved in the database and everything is fine at this point.
So from this form I'll just show the script triggered by the close button that closes the modal and triggers reloading of the dropdownlist div from the main screen
<script>
$("#btnClose").click(function () {
$("#divDropNatureKinds").load("/Modals/ReloadDropDownListNatureKinds");
$("#modal").close;
});
</script>
ReloadDropDownListNatureKinds have only:
#{
Layout = null;
}
#Html.DropDownList("NatureKindID", null, "Select one", htmlAttributes: new { #class = "form-control" })
And Controller ActionResult is:
public ActionResult ReloadDropDownListNatureKinds(int? idNatureKind)
{
if (idNatureKind == null)
ViewBag.NatureKindID = ListToDropDown();
else
{
ViewBag.NatureKindID = ListaToDropDown(idNatureKind);
}
return PartialView();
}
public SelectList ListToDropDown()
{
return ListToDropDown(null);
}
public SelectList ListaToDropDown(int? idNatureKind)
{
var list = db.NatureKinds
.Select(u => new
{
Text = u.NatureName,
Value = u.ID
}).ToList();
SelectList ret = new SelectList(list.OrderBy(x => x.Text), "Value", "Text", idNatureKind);
return ret;
}
And the structure was:
To be clear. ALL THIS WORKS PERFECTLY.
But, my project was getting very big. A mix of over 50 controllers and more than 250 views. So I decided to look for some way to organize and I found a post about Areas.
I created 5 areas and moved models, controllers and views for each of them.
And now the structure is:
I put in the main View the references of the area where the modal is:
<div class="form-group">
#Html.LabelFor(model => model.NatureKindID, "Kind of nature", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div id="divDropNatureKinds">
#Html.Action("ReloadDropDownListNatureKinds", "Modals", new { area = "Admin" })
</div>
#Ajax.ActionLink(" ", "CreateModalNatureKinds", "Modals", new { area = "Admin" }, new AjaxOptions { UpdateTargetId = "modaldropbody", OnComplete = "openModal" }, new { #class = "glyphicon glyphicon-plus" })
#Html.ValidationMessageFor(model => model.NatureKindID, "", new { #class = "text-danger" })
</div>
</div>
With this new structure, most features are working well. When I click ActionLink, the modal opens. In the modal, when registering a new type of nature, it is registered in the database.
When I click the modal close button, the ActionResult ReloadDropDownListNatureKinds is executed and the new list is loaded with the new Nature type that was created.
All of this has been tested.
But the list in the main View is not updated, it does not receive the new list.
It is as if the ViewBag.NatureKindID that receives the new list is not the same as that used in the Main View, it continues with the old list.
Any suggestion? Thanks in advance for any help.

Related

Using pagedlist with form parameters

I am using asp.net MVC 5 and Was wondering if there were any solutions out there that allowed me to use the PAGEDLIST library that can pass back input variables from the controller ALONG with passing back the .ToPagedList(pagenumber, pagesize) in the return view from the controller.
Here is the code i am working with:
In my Controller:
return View(tags.OrderBy(i => i.entry_no).ToPagedList(page ?? 1, 5));
In my View:
<div class="container-fluid">
<div class="row">
<div class="col-xs-4 input-group input-daterange" id="datepicker" style="margin-right: 30px">
#Html.EditorFor(model => model.startDate, new { #class = "form-control" })
<div class="input-group-addon">to</div>
#Html.EditorFor(model => model.endDate, new { #class = "form-control" })
</div>
<div class="col-xs-1 input-group">
<span class="input-group-addon">Desk:</span>
#Html.DropDownListFor(model => model.SelectedDesk,
new SelectList(Model.DeskOptions, "Text", "Value", Model.SelectedDesk), new { #class = "selectpicker" })
</div>
</div>
</div>
[...]
Page #(Model.Tag.PageCount < Model.Tag.PageNumber ? 0 : Model.Tag.PageNumber) of #Model.Tag.PageCount
#Html.PagedListPager(Model.Tag, page => Url.Action("Index", new { page, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter }))
So what i was hoping for was a way to update those editorfor/displayfor variables above along with passing back a pagedlist for table pagination.

Inputs inside Partialview takes value from main model

I render a PartialView inside my main View
View:
#model FullProductViewModel
...
<div class="send-container">
#Html.Partial("_CommentForm", new CommentViewModel { ProductId = Model.Id, Title = "" , Context="" })
</div>
...
I have a filed with name "Title" in Both my classes "FullProductViewModel" and "CommentViewModel".
_CommentForm PartialView:
#model CommentViewModel
<p class="page-title">#Resources.SendComment</p>
#using (Html.BeginForm("Comment", "Home", FormMethod.Post, new { #class = "form-comment form-submit" }))
{
#Html.AntiForgeryToken()
<div class="input-group">
#Html.LabelFor(model => model.Title)
#Html.ValidationMessageFor(model => model.Title, "", new { #class = "text-danger" })
#Html.EditorFor(model => model.Title, new { htmlAttributes = new { #class = "form-control" } })
</div>
<div class="input-group">
#Html.LabelFor(model => model.Context)
#Html.ValidationMessageFor(model => model.Context, "", new { #class = "text-danger" })
#Html.TextAreaFor(model => model.Context, htmlAttributes: new { #class = "form-control", rows = "8" })
</div>
<div class="input-group">
#Html.LabelFor(model => model.CaptchaCode)
#Html.ValidationMessageFor(model => model.CaptchaCode, "", new { #class = "text-danger" })
#Html.EditorFor(model => model.CaptchaCode, new { htmlAttributes = new { #class = "form-control" } })
</div>
<div class="captcha-wrapper">
<img alt="Captcha" id="imgcaptcha" src="#Url.Action("Captcha", "Captcha")" />
</div>
<button class="btn btn-submit" type="submit">#Resources.SendMessage</button>
}
The problem is "Title" inside PartialView take its value form "FullProductViewModel" model but not "CommentViewModel ". i can easily change the field name "Title" inside one of models to solve problem... but why this happened and how i can fix it without change field name?
Your Title property is conflicting with the #{ ViewBag.Title = ".. line of code in your view (the ViewBag code is used by the _Layout.cshtml file to set the global <title> attribute for the page).
All the HtmlHelper methods that generate form controls set the value by checking (in order)
ModelState
The ViewDataDictionary (ViewData or ViewBag)
The value of the models property
In your case, nothing has been added to ModelState. But because a value for Title has been added to the ViewDataDictionary, its that value which is used for the value of your textbox. The method never gets to read the actual value you have set in your model.
The only realistic option (unless you want to modify the code in the _Layout and all views that use it) is to change the name of the property.

Load partial view after button click

I have this issue, have search a lot but with now correct answer.
I have a contact form in the footer, on my _Layout page, but when I clicked the button the partial view is open in a new page.
I have remember to include the jquery.unobtrusive-ajax.js. Here is what I have.
Controller :
[HttpGet]
public ActionResult Call()
{
return PartialView("_PartialFooter");
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Call(CallMe callMe)
{
if(ModelState.IsValid)
{
}
return PartialView("_PartialFooter");
}
_Layout the scripts is above the Body tag in the bottom
#using (Ajax.BeginForm("Call", "Home", new AjaxOptions { UpdateTargetId = "result" }))
{
<div id="result" class="margin-bottom-5">
#Html.Action("Call", "Home")
</div>
<button class="btn btn-common-small margin-bottom-10 pull-right" type="submit">Send</button>
}
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/bootstrap")
#Scripts.Render("~/bundles/myscripts")
#RenderSection("scripts", required: false)
#section Scripts {
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
}
_PartialFooter (the partial view)
#model servicemadsen.Models.CallMe
#Html.AntiForgeryToken()
<div class="row">
<div id="result" class="margin-bottom-5">
<div class="col-md-6">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control", #placeholder = "Navn" } })
</div>
<div class="col-md-6">
#Html.EditorFor(model => model.Phone, new { htmlAttributes = new { #class = "form-control", #placeholder = "Telefon" } })
</div>
<div class="col-md-12">
#Html.TextAreaFor(model => model.CallMeMessage, new { #class = "form-control", #placeholder = "Besked", #cols = 80, #rows = 7 })
</div>
<div class="col-md-12">
#Html.ValidationMessageFor(model => model.Name, string.Empty, new { #class = "field-validation-error" })
#Html.ValidationMessageFor(model => model.Phone, string.Empty, new { #class = "field-validation-error" })
#Html.ValidationMessageFor(model => model.CallMeMessage, string.Empty, new { #class = "field-validation-error" })
</div>
</div>
</div>
Hope someone could help, its probaly some dummy thing that I need
have you installed the microsoft jquery unobstrusive ajax? if not try with that. i do some tests with your code and works.
EDIT : i also change some code for the tests
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Call(CallMe callMe)
{
if (ModelState.IsValid)
{
ModelState.Clear();
callMe.CallMeMessage = callMe.CallMeMessage + " i was on the server";
}
return PartialView("_PartialFooter", callMe);
}
and
#using (Ajax.BeginForm("Call", "Home", new AjaxOptions { UpdateTargetId = "result", InsertionMode = InsertionMode.Replace}))
{
<div id="result" class="margin-bottom-5">
#Html.Action("Call", "Home")
</div>
<button class="btn btn-common-small margin-bottom-10 pull-right" type="submit">Send</button>
}
so you can see the changes.

MVC Saving field data from a view

I am using MVC and on my Index view I have placed a 'EditorFor' and a 'DropDownFor' fields on it for data entry. I would like a user to enter values and then 'Save' the record from the view. However I am having problems retrieving the data entered. I have tried creating an ActionResult and binding the data however nothing comes across. I have tried giving the fields id names and passing them in as parameters and again nothing is passed.
This is what I have in my View -
<h3>Sensitive Areas</h3>
#Html.HiddenFor(model => model.BurnSitesID, new { #id = "burnSitesID"})
<div class="form-group">
#Html.LabelFor(model => model.SensitiveTypesID, "Sensitive Area", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("SensitiveTypesID", string.Empty)
#Html.ValidationMessageFor(model => model.SensitiveTypesID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.DistSensitiveArea, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.DistSensitiveArea, new { #id = "distSensitiveArea" })
#Html.ValidationMessageFor(model => model.DistSensitiveArea, "", new { #class = "text-danger" })
</div>
<input type="submit" id="CreateArea" value="Save"/>
How would you take the values entered and pass them to the controller? I have tried a button however if my button is not named the exact same thing as the view it does not do anything.
Please use Html.BeginForm("ActionName","ControllerName", FormMethod.Post) .
Button should be Submit type .
If you are use textbox .
#Html.TextBoxFor("txtName", "", new { #class = "form-control", #maxlength = "50" })
<input type="submit" id="CreateArea" value="Save"/>
[HttpPost]
public ActionResult ActionName(FormCollection form)
{
string Name=form["txtName"].ToString();
}
Where Name is a name/ID of field name .
Thanks .

How do I post varied length list to controller?

MVC4. I have a dynamic list on a view, a new textbox is added with button click (which adds a partialView) so user can enter a list of stuff. That is contained in a form element with a submit button.
In the controller I have tried three different types:
[HttpPost]
public ActionResult Index(IEnumerable<AccessoryVM> form)
{
-- form is NULL
[HttpPost]
public ActionResult Index(AccessoryVM form)
{
-- form has only the first item in the list
[HttpPost]
public ActionResult Index(FormCollection form)
{
-- seems to receive the list, but having trouble getting the values
All the examples I have seen are using a for list to add an index to each item, but they aren't using a dynamic list (it has a fixed length).
What should the Controller receiving type be?
EDIT to add more detail:
Button click appends partial view:
$("#add-item").on("click", function () {
$.ajax({
url: '/Accessory/AddItem',
cache: false,
success: function (html) {
$("#form-body").append(html);
}
})
return false;
})
Partial View:
#model EmployeeHardwareRequest.Models.ViewModels.AccessoryVM
<div class="form-group col-md-3">
#Html.LabelFor(model => model.ItemDescription, htmlAttributes: new { #class = "control-label" })
<div>
#Html.DropDownListFor(model => model.AccessoryId, Model.AccessoryDdl, new { #class = "form-control" })
</div>
</div>
<div class="form-group col-md-9">
#Html.LabelFor(model => model.ProductLink, htmlAttributes: new { #class = "control-label" })
<div>
#Html.EditorFor(model => model.ProductLink, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ProductLink, "", new { #class = "text-danger" })
</div>
</div>
Main View - partial is appended to the #form-body:
#using (Html.BeginForm("Index", "Accessory", FormMethod.Post, new { #id="accessory-form", #class = "form-horizontal" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div id="form-body">
<div class="form-group col-md-3">
#Html.LabelFor(model => model.ItemDescription, htmlAttributes: new { #class = "control-label" })
<div>
#Html.DropDownListFor(model => model.SelectedAccessory, Model.AccessoryDdl, new { #class = "form-control" })
</div>
</div>
<div class="form-group col-md-9">
#Html.LabelFor(model => model.ProductLink, htmlAttributes: new { #class = "control-label" })
<div>
#Html.EditorFor(model => model.ProductLink, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ProductLink, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<button id="add-item" class="btn btn-primary">Add Another Item</button>
</div>
<div class="col-md-6">
<input type="submit" value="Select Software" class="btn btn-default pull-right" />
</div>
</div>
}
Most likely, you have a binding issue. Assuming all you're posting is a collection of AccessoryVM, then the parameter should be List<AccessoryVM> form. However, in order for the modelbinder properly bind the posted values, your input names must be in a specific format, namely either form[N].Foo or just [N].Foo.
You haven't given any detail about what's going on in your view, but since these are dynamically added, you must be using JavaScript to add additional inputs to the page. If you're doing it via AJAX (returning a partial view), you'll need to pass the index to your endpoint so that it can be utilized to generate the right input names. If you're using something like Knockout, Angular, etc., you should ensure that whatever template is being used to generate the inputs takes an index into account.

Resources