I’m new to MVC and I’m having a lot of trouble with Partial Views. Hopefully someone can give me some guidance.
We’re trying to port our ASP.Net webforms app to MVC. I’ve created a little test app to try to mimic what we’re doing on many of our pages. Based on sample code I found here, I have a View and a Partial view and a Model that contains the Partial model. The view has a drop down list that hides/shows the partial view.
When the user selects Hidden, I have a javascript method that hides the partial view. If they select Visible, the javascript makes a call to an action where I want to be able to modify the model and send it back to the view. I will also need to be able to hide or show other partial views on the page. In another scenario, I will need to be able to modify TestModel and PartialModel within the javascript function itself and re-render (have the changes reflected to the user).
I currently have two things I can't figure out:
How to access the model in the javascript function
How to pass the model back and forth to the action called from the model
The code, as it stands now, calls the action in which I create a new PartialModel and pass it back to the view. That works but when I click on the save button, the "old" PartialModel is passed to the HTTPPost action. However, I need to modify the existing model and not create a new one.
I've posted the code below. Any help would be greatly appreciated.
Controller
namespace WebApplication1.Controllers
{
public class TestController : Controller
{
// GET: Test
public ActionResult Index()
{
TestModel tm = new TestModel();
tm.Vis = Visibility.Visible;
return View(tm);
}
[HttpPost]
public ActionResult Index(TestModel tm)
{
return View(tm);
}
public ActionResult DDLChangedAction(int id)
{
// I need access to TestModel including TestModel.PartialModel
var pvm = new PartialModel();
pvm.PartialInt = 100;
pvm.PartialString = id.ToString(); ;
pvm.PartialString2 = "asdf";
////return PartialView("_PartialTest", pvm,
//// new ViewDataDictionary(System.Web.Mvc.Html.HtmlHelper.ViewData)
//// {
//// TemplateInfo = new TemplateInfo { HtmlFieldPrefix = HtmlHelper.NameFor(m => m.Partial).ToString() }
//// });
return PartialView("_PartialTest", pvm);
}
private ActionResult PartialView(string v, PartialModel pvm, ViewDataDictionary viewDataDictionary)
{
throw new NotImplementedException();
}
}
}
Model
namespace WebApplication1.Models
{
public class TestModel
{
public TestModel()
{
Partial = new PartialModel();
Partial.PartialInt = 42;
Partial.PartialString = "partialString text";
Partial.PartialString2 = "partialString2 text";
}
public int SelectedItem { get; set; }
public Visibility Vis { get; set; }
public PartialModel Partial { get; set; }
}
public class PartialModel
{
public int PartialInt { get; set; }
public string PartialString { get; set; }
public string PartialString2 { get; set; }
}
public enum Visibility
{
Visible = 1,
Hidden
}
}
View
<h2>Index</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>TestModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.Label("Visibility", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("Vis", new SelectList(Enum.GetValues(typeof(Visibility))),
"Select",
new {
#id = "ddlVis",
#class = "form-control"
//onchange = #"ddlChanged();"
})
</div>
<br />
#Html.LabelFor(model => model.SelectedItem, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.SelectedItem, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.SelectedItem, "", new { #class = "text-danger" })
</div>
</div>
<div id="partialPlaceHolder">
#Html.Partial("_PartialTest", Model.Partial,
new ViewDataDictionary(Html.ViewData)
{
TemplateInfo = new TemplateInfo { HtmlFieldPrefix = Html.NameFor(m => m.Partial).ToString() }
})
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript">
$('#ddlVis').change(function () {
/* Get the selected value of dropdownlist */
var selectedID = $(this).val();
if (selectedID == 1) {
// access and modify the model and partial model
}
if ($('#ddlVis').val() == "Visible") {
// I can pass an integer here, but how do I pass in the model to the action?
$.get('/Test/DDLChangedAction/' + 123, function (data) {
/* data is the pure html returned from action method, load it to your page */
$('#partialPlaceHolder').html(data);
$('#partialPlaceHolder').show();
});
} else if ($('#ddlVis').val() == "Hidden") {
$('#partialPlaceHolder').hide();
}
});
function ddlChanged() {
alert("projectPtIndChanged")
if ($('#ddlVis').val() == "Hidden") {
alert("in hide");
//debugger;
$("#divHideTest").hide();
// now let's show the partial
var newString = "Ickle";
$.get('/Test/DDLChangedAction' + newString, function (data) {
$('#partialPlaceHolder').html(data);
});
} else {
alert("in show");
$("#divHideTest").show();
}
}
</script>
}
Partial View
#model WebApplication1.Models.PartialModel
<div>
<fieldset>
<legend>PartialTest</legend>
<dl class="dl-horizontal">
<dt>#Html.DisplayNameFor(model => model.PartialInt)</dt>
<dd>#Html.EditorFor(model => model.PartialInt)</dd>
<dt>#Html.DisplayNameFor(model => model.PartialString)</dt>
<dd>#Html.EditorFor(model => model.PartialString)</dd>
<dt>#Html.DisplayNameFor(model => model.PartialString2)</dt>
<dd>#Html.EditorFor(model => model.PartialString2)</dd>
</dl>
</fieldset>
</div>
Related
I am currently trying to populate the values for a car's model based on the selected make in a dropdownlist. I am new to coding so I am not sure what my mistake is. The project doesn't give me any errors but no values are displayed when I selected the make.
This is my Partial View that I am adding into my Create View.
#model IgnitionHubPractice.Models.MakeModelDorpdownView
<div class="form-horizontal">
<div class="form-group">
#if (ViewBag.MakeList != null)
{
#Html.DropDownListFor(m => m.MakeID, ViewBag.MakeList as SelectList, "--Select Make--", new { #class = "form-control" })
}
</div>
<div class="form-group">
#Html.DropDownListFor(m => m.ModelID, new SelectList(" "), "--Select Model--", new { #class = "form-control" })
</div>
</div>
<script>
$(document).ready(function () {
$("#MakeID").change(function () {
$.get("/Cars/GetModelList",{ MakeID: $("MakeID").val() }, function (data) {
$("#ModelID").empty();
$.each(data, function (index, row) {
$("#ModelID").append("<option value ='" + row.ModelID + "' >" + row.Name + </option>")
});
});
})
});
</script>
This is my controller
public ActionResult Create([Bind(Include = "CarID,Year,Color,Mileage,Cost,MarketValue,BodyType,Drive,Notes,Available,VinNumber,CarLotID,ModelID")] Car car, [Bind(Include ="MakeID,Name")] Make make)
{
if (ModelState.IsValid)
{
db.Cars.Add(car);
db.SaveChanges();
return RedirectToAction("Index");
}
List<Make> MakeList = db.Makes.ToList();
ViewBag.MakeList = new SelectList(db.Makes, "MakeID", "Name", make.MakeID);
ViewBag.ModelID = new SelectList(db.Models, "ModelID", "Name", car.ModelID);
ViewBag.CarLotID = new SelectList(db.CarLots, "CarLotID", "LotName", car.CarLotID);
return View(car);
}
public JsonResult GetModelList(int MakeID)
{
db.Configuration.ProxyCreationEnabled = false;
List<Model> ModelList = db.Models.Where(x => x.MakeID == MakeID).ToList();
return Json(ModelList, JsonRequestBehavior.AllowGet);
}
Please help, thanks in advance.
In MVC you try to create a cascading drop down. So for easy understanding you can check the below link. It contanin detailed information for controller and View with Jquery part.
Please visit this link: Cascading Drop down List With MVC And AJAX
I am trying to Get ACE editor for javaScript purpose but i am not able to post my Editor data when i am clicking Save button its show NULL value in DB.
but when i am using normal Textarea without ACE my data is saving properly.
This is My CSHTML code.
<div class="form-group row">
<div class="col-lg-11" id="JavaScriptEditor">
#Html.Label("JavaScript", new { #class = "control-label" })
#Html.TextAreaFor(x=>x.JavaScript,new {#class="JavaScript"})
#Html.ValidationMessageFor(model => model.JavaScript, "", new { #class = "text-danger" })
</div>
</div>
This is my JS Code:-
<script>
var editor = ace.edit("JavaScript");
editor.setTheme("ace/theme/terminal");
editor.getSession().setMode("ace/mode/javascript");
window.onload = function () {
$("form").submit(function () {
$(".JavaScript").val().editor.getSession().getValue();
})
};
</script>
This is My Controller Code:-
[HttpPost]
[ValidateInput(false)]
public ActionResult AddEdit(Article article, FormCollection formCollection)
{
article.CompanyId = OperatingUser.CompanyId;
if(string.IsNullOrWhiteSpace(article.Slug))
article.Slug = article.Name.GenerateSlug();
if (string.IsNullOrWhiteSpace(article.SlugKey))
article.SlugKey = SlugKey();
//bool isUnique = _articleService.IsSlugUnique(slug: article.Slug, articleId: article.Id);
//if (!isUnique)
// article.Slug = $"{article.Slug}-1";
article.CreatedById = OperatingUser.Id;
article.ModifiedById = OperatingUser.Id;
if (article.Tags != null && article.Tags.Any())
article.Tag = string.Join(",", article.Tags);
if (formCollection.GetValue("SubmitButton").AttemptedValue
.Equals("Save and Publish", StringComparison.OrdinalIgnoreCase))
article.IsPublished = true;
article.RoleIds = formCollection.GetValue("selectedRoles").AttemptedValue;
if (article.Id > 0)
{
article.ModifiedById = OperatingUser.Id;
_articleService.Update(article);
}
else
{
article = _articleService.Add(article);
}
return Json(new { RedirectUrl = Url.Action("Edit", "Content", new { area="cms", id = article.Id }) });
}
I am trying to Save This Property data in Db but i am not able to Save this Please Help me.
snippet of my cshtml:
#model Models.ClockingInformationViewModel
<form id="clocking-form">
<div class="row">
<div class="col-md-4">
<div class="form-group">
<label class="control-label">Time in</label>
<div class="input-group date form_datetime">
#Html.TextBoxFor(m => m.Attendance.Time01In, new { #class = "form-control", #readonly = "readonly", size = "16" })
</div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label class="control-label">Job code</label>
#Html.TextBoxFor(m => m.Attendance.Time01InJob, new { #class = "form-control" })
Controller:
[HttpPost]
public JsonResult ClockingInformation(ClockingInformationViewModel model)
{
return null;
}
ViewModel:
public class ClockingInformationViewModel
{
public Attendance Attendance { get; set; }
public List<Clock> ClockingLocations { get; set; }
}
In my javascript, I have this:
function saveClockingInformation() {
var data = $("#clocking-form").serialize();
$.post($("#clocking-info-url").val(), { model: data });
}
When I set a break point in my controller, ClockingInformationViewModel model property is null.
When I did serializeArray() instead of serialize(), ClockingInformationViewModel model isn't null, but the property Attendance is.
I'm sure it's some silly mistake that I've over looked.
Any insights?
Your var data = $("#clocking-form").serialize(); line of code is already serializing your form to an object, so the code needs to be
function saveClockingInformation() {
var data = $("#clocking-form").serialize();
$.post($("#clocking-info-url").val(), data);
}
Which sends the form data as
Attendance.Time01In=someValue&Attendance.Time01InJob=anotherValue
whereas your current implementation using { model: data } sends the form data as
model[Attendance.Time01In]=someValue&model[Attendance.Time01InJob]=anotherValue
which has no relationship to your model, hence binding fails.
Side note: Your use of $("#clocking-info-url").val() suggests you putting the url in to a hidden input. Instead, use
var url = '#Url.Action("yourAction", "yourController")',
$.post($(url, data);
or if you have generated the form using Html.BeginForm(), then use
var form = $("#clocking-form");
var url = form.attr('action');
$.post($(url, data);
I am working in MVC5 and using a combination of client and server validation. For this particular issue I am using remote validation.
The Razorview:
<div id="studentStatus" name="studentStatus">
#using (Html.BeginForm("StudentStatus", "StudentStatus", FormMethod.Post, new { id = "studentStatusForm", data_timer = 240000 }))
{
#Html.HiddenFor(x => x.CurrentStudentSepId, new { #class = "hideMe" })
<div class="row">
<h2 class="col-md-12 topSectionHeader">
#StaffPortalResources.Section_StudentStatus
<span class="savedStatus"></span>
</h2>
</div>
<span class="errorNotification"></span>
<div class="questionGroup form-group">
<div class="row margin-btm-sm">
<div class="col-md-4">
#Html.LabelFor(x => x.StudentStatusId)
#if (Model.IsReadOnly)
{
<div>#Html.DisplayFor(x => x.StudentStatusId)</div>
#Html.HiddenFor(x => x.StudentStatusId)
}
else
{
#Html.CustomComboBoxFor(x => x.StudentStatusId, (new { #class = "statusChangeValidationHandler", data_action = "GetStudentEditableStatuses", data_controller = "Lookup" }))
}
#Html.ValidationMessageFor(x => x.StudentStatusId)
</div>
}
The model:
public sealed class StudentStatusSectionViewModel : SectionViewModel
{
[Display(Name = "Status", ResourceType = typeof(StaffPortalResources))]
[SelectMustExist(true, ErrorMessageResourceType = typeof (StaffPortalResources), ErrorMessageResourceName = "StudentStatus_InvalidSelection")]
[Remote("ValidateStudentStatus", "StudentStatus", AdditionalFields = "CurrentStudentSepId")]
public string StudentStatusId { get; set; }
public bool DoNotReenroll { get; set; }
}
The controller:
public JsonResult ValidateStudentStatus(StudentStatusSectionViewModel model)
{
var errors = _studentStatusSectionAdapter.ValidateStudentStatus(model.CurrentStudentSepId, model.StudentStatusId);
if (errors != null && errors.Any())
{
var currentStatus = _studentStatusSectionAdapter.Get(model.CurrentStudentSepId).StudentStatusId;
Response.AddHeader("status", currentStatus);
return Json(string.Join("</br>", errors), JsonRequestBehavior.AllowGet);
}
return Json(true, JsonRequestBehavior.AllowGet);
}
The remote validation .complete() function:
scope.initializeStudentStatusDropdown = function() {
var $element = $('#studentStatusForm').find('input.statusChangeValidationHandler[data-role="combobox"]');
$element.rules().remote.complete = function (xhr) {
if (xhr.responseText !== 'true')
window.Registration.StudentStatus.fixStudentStatusDropdown($element, xhr.getResponseHeader);
}
}
scope.fixStudentStatusDropdown = function($element,responseHeader) {
$element.kVal(responseHeader('status'));
}
The jquery used to wire validation on change event:
scope.initializeAutoSave = function (form, callBack) {
var $form = $(form);
$form.on("change", "input:not(.ignoreAutoSave)", queueForm);
$form.on("change", "textarea:not(.ignoreAutoSave)", queueForm);
window.Validation.initializeValidator($form);
callBacks[$form.attr('id')] = callBack || function() {};
}
The queueForm method:
function queueForm(e) {
if ($(e.target).valid()) {
var $form = $(e.target).closest("form");
var timer = $form.data("timer");
autoSaveQueue[$form.attr("id")] = { $form: $form, timer: timer, attempt: 0 };
}
}
When tracing through the code after changing the value in the dropdown, the change event fires and calls the queueForm function. the valid() call evaluates to true before the remote validation happens.
It is not until after I step over 'if ($(e.target).valid())' line, and it evaluates to true and steps into the if block. Then it jumps into the remote ValidateStudentStatus function in my controller.
Have I done something wrong here? Am I misunderstanding how the remote validation works?
Any insight or help would be greatly appreciated!
How does one use jQuery to reference the field(s) of a Model serving as a variable of a parent Model, then retrieve those fields for different entries of that inner Model?
For example, there's a AccountOwnerModel and a AccountModel, the latter containing an variable of AccountOwnerModel type.
AccountOwner Model:
public class AccountOwnerModel
{
public int AccountOwnerID {get; set;}
public string AccountOwnerName {get; set;}
public string AccountOwnerEmail {get; set;}
public string AccountOwnerPhoneNumber {get; set;}
}
Account Model:
public class AccountModel
{
public int AccountID {get; set;}
public int AccountOwnerID {get; set;}
public AccountOwnerModel AccountOwner {get; set;}
}
In the Controller, there is an Action to retrieve the AccountOwner fields should a different AccountOwner be selected:
[HttpPost]
public ActionResult GetAccountOwnerInfo(string ownerID)
{
Int64 accountOwnerID = 0;
Int64.TryParse(ownerID, out accountOwnerID);
DbEntities projectDB = new DbEntities();
var owner = projectDB.uspGetAccountOwnerInformation(accountOwnerID).FirstOrDefault();
AccountOwnersModel accountOwner = new AccountOwnersModel()
{
AccountOwnerID = owner.AccountOwnerID,
AccountOwnerName = owner.AccountOwnerName,
AccountOwnerEmail = owner.AccountOwnerEmail,
AccountOwnerPhoneNumber = owner.AccountOwnerPhoneNumber
};
return Json(accountOwner, JsonRequestBehavior.AllowGet);
}
In the View, there's a dropdownlist for the AccountOwnerModels by AccountOwnerID and AccountOwnerName, then lines to show and modify the data for that AccountOwnerID, save a different AccountOwnerModel to the AccountModel, and fetch the data for a different selected AccountOwnerID:
<div class="row">
<div class="col-lg-4">
#Html.LabelFor(m => m.AccountOwnerID, "Account Owner Name", new { #class = "req" })
#Html.DropDownListFor(m => m.AccountOwnerID, Model.AccountOwners, "--New Owner--")
</div>
<div class="col-lg-8" id="AccountOwnerName">
#Html.LabelFor(m => m.AccountOwner.AccountOwnerName, new { #class = "req"})
#Html.TextBoxFor(m => m.AccountOwner.AccountOwnerName)
</div>
</div>
<div class="row">
<div class="col-lg-6" id="AccountOwnerPhoneNumber">
#Html.LabelFor(m => m.AccountOwner.AccountOwnerPhoneNumber, "Owner Phone Number")
#Html.TextBoxFor(m => m.AccountOwner.AccountOwnerPhoneNumber, new { #class = "form-control", data_parsley_required = "true" })
</div>
<div class="col-lg-6" id="AccountOwnerEmailAddress">
#Html.LabelFor(m => m.AccountOwner.AccountOwnerEmail, "Owner E-Mail Address")
#Html.TextBoxFor(m => m.AccountOwner.AccountOwnerEmail, new { #class = "form-control", data_parsley_required = "true" })
</div>
</div>
<div class="row">
<div class="col-lg-12 text-right">
<button type="submit" class="btn btn-success">Save Account Owner</button>
</div>
</div>
#section Scripts{
<script src="~/Scripts/jquery-2.1.3.js"></script>
<script src="/Scripts/jquery-ui-1.11.4.js"></script>
<script>
$("#AccountOwnerID").change(function () {
var $ownerName = $("#AccountOwner.AccountOwnerName"),
$ownerEmail = $("#AccountOwner.AccountOwnerEmail"),
$ownerPhone = $("#AccountOwner.AccountOwnerPhoneNumber");
if (this.value >= 1) {
$.ajax({
type: "POST",
url: '/Sales/GetAccountOwnerInfo',
data: { ownerID: $("#AccountOwnerID").val() },
success: function (data) {
//Fill data
$ownerName.val = data.AccountOwnerName;
$ownerEmail.val = data.AccountOwnerEmail;
$ownerPhone.val = data.AccountOwnerPhoneNumber;
}
});
}
else {
//clear fields
$ownerName.val('');
$ownerEmail.val('');
$ownerPhone.val('');
}
}).change();
</script>
So, to be more specific, can the variables in the jQuery code be assigned by $("#AccountOwner.AccountOwnerName"), or will the period refer to a class id? Also, is the AJAX Post syntax correct? This code isn't showing errors in either Visual Studio or the Chrome console, but it isn't returning anything on different dropdown selections, either. I've tried referring the variables to just the field name, e.g. $("AccountOwnerName"), searching this site to no avail, and using $("#AccountOwnerID").val() in the AJAX Post data, which was null each time but seemed to at least send a null on each dropdown change. There's an id for each column class, but will using that in the references affect the "#LabelFor" as well? Thanks in advance!
The actual answer to this came from the sister question here: the generated HTML was referring to the elements of type Model as ("#Model_Element"), or ("#AccountOwner_AccountOwnerName") for the "m.AccountOwner.AccountOwnerName" in this situation, and did not require the syntax for escaping the period in the jQuery selector.