Passing value from EditorFor to controller - asp.net-mvc

This is my view where education is the list in the model.
#using chpayroll.Models.CustInformations
#model CustInfoExtract
#Html.HiddenFor(x => x.flag, new { #id = "flag" })
#Html.HiddenFor(x => x.StaffId)
<table style=" width:730px">
<tr>
<th>Country</th>
<th>Board</th>
<th>Level</th>
<th>PassedYear</th>
<th>Division</th>
</tr>
<tr>
#Html.EditorFor(x => x.education)
</tr>
<tr>
<td><input type="submit" value="Add Another" id="addedu"/> </td>
</tr>
</table>
I have editor template as below
#using staffInfoDetails.Models
#model staffInfo.education
#Html.HiddenFor(x=>x.staffId)
<tr>
<td >#Html.DropDownListFor(x => x.country, Model.countryList, "--select--", new { #id="country"})</td>
<td>#Html.TextBoxFor(x => x.board, new { #id="board"})</td>
<td>#Html.TextBoxFor(x => x.level, new { #id="level"})</td>
<td>#Html.TextBoxFor(x => x.passedYr, new { #id="passedYr"})</td>
<td>#Html.DropDownListFor(x => x.passedDiv, Model.passedDivList, "--select--", new { #id="division"})</td>
</tr>
I am trying to pass model from controller to view and back from view to controller. While I was passing model to view, the education list passed, but, when i tried to pass model from view to controller, everything else passed except for the education list. How can I solve this problem ?

Only the selected value from the drop down list will be posted back so you'll need to re-populate your drop down list if validation fails (ie. if the View has to be re-displayed).
Your POST action might look something along the lines of the following:
[HttpPost]
public ActionResult Home(CustInformations viewModel)
{
if (!ModelState.IsValid)
{
// Re-populate drop-down list and redisplay form
viewModel.DropdownListOptions = _repository.getEductionList();
return View(viewModel);
}
// Validation passed
// Save, update, etc and redirect to new page
}

Related

Model retains it's value after Submit to server

I'm facing this weird problem ,unable to make sense of it,I have a form which accepts Person Id and then reads the data from an API and fills the UI for person Edit purposes.
Here is the markup of this form,I'm guessing its has something to do with Model binding as I have two Form tag and both having the same Model Id.
#using (Html.BeginForm("UpdatePerson", "Person", FormMethod.Get))
{
<table>
<tr>
<td colspan="2">
<h3>Read Person for Edit</h3>
</td>
</tr>
<tr>
<td>
<label>#Html.LabelFor(m => m.Id)</label>
</td>
<td>
#Html.TextBoxFor(m => m.Id)
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" name="btnReadPerson" value="Read Person" />
</td>
</tr>
</table>
}
#using (Html.BeginForm("UpdatePerson", "Person", FormMethod.Post))
{
<table>
<tr>
<td>
<label>#Html.LabelFor(m => m.Id)</label>
</td>
<td>
#Html.TextBoxFor(m => m.Id, new { #readonly = "readonly" })
</td>
</tr>
<tr>
<td>
<label>#Html.LabelFor(m => m.Type)</label>
</td>
<td>
#Html.TextBoxFor(m => m.Type)
</td>
</tr>
I have stripped the view,I tried to kept it brief.
Below is the Action which handles the Get
[HttpGet]
[ActionName("UpdatePerson")]
public ActionResult UpdatePersonRead(PersonEditModel model)
{
if (model.Id.HasValue)
{
var apiClient = new ApiClient (ApiVersions.v1);
var segmentReplaceList = new Dictionary<string, string> { { "{id}", model.Id.Value.ToString() } };
bool ApiHitStatus = false;
var result = apiClient.MakeAPIRequest(out ApiHitStatus, ResourceUriKey.Person, segmentReplaceList, HttpVerbs.Get, string.Empty);
model = new PersonEditModel();
if (ApiHitStatus)
{
var personToBeUpdated = JsonConvert.DeserializeObject<RootChildPerson>(result);
if (personToBeUpdated != null)//Assigning json obj to model
{
model.NameFirst = personToBeUpdated.name_first;
model.NameLast = personToBeUpdated.name_last;
model.NameMiddle = personToBeUpdated.name_middle;
model.SocialSecurityNumber = personToBeUpdated.social_security_number;
model.SubType = PersonHelper.SubTypeValue(personToBeUpdated.sub_type);
model.Type = "person";
model.DateOfBirth = personToBeUpdated.date_of_birth;
model.Id = personToBeUpdated.id;
}
}
}
return View(model);
}
Now since the Person Id 4 does not corresponds to any person ,so I receive Null json object which upon conversion to C# class results in an empty (not null because it has every property set to null or empty) personToBeUpdated object which is then assigned to the model,I have checked model.Id becomes null in the Controller and even in the View ,but somehow it assigns input value that is 4 (it was null) to both Person Id textboxes.
Kindly let me know whats happening here.
Well as commented by #StephenMuecke ,So I cleared model before updating it.
model = new PersonEditModel();
ModelState.Clear();
Its also interesting to note that view takes data from ModelState instead of current specified model,
HtmlHelpers controls (like .TextBoxFor() etc.) don't bind to model values on Postback, but rather get their value directly out of the POST buffer from ModelState.
Taken from ASP.NET MVC Postbacks and HtmlHelper Controls ignoring Model Changes

Selecting multiple from #Html.ListBoxFor

I have added #Html.ListBoxFor i am able to bind it properly but unable to get multiple selected items after submit. Am i missing something ?
// Below is the code for binding
public ActionResult Create()
{
var cities = So.BL.City.GetCities();
SelectList cityList = new SelectList(cities, "Id", "Name", cityId);
TempData["Cities"] = cityList;
return View("Create");
}
[HttpPost]
public ActionResult Create([Bind(Include="Keywords,Cities")] So.Entities.Approval filter)
{
if (ModelState.IsValid)
{
}
return View(filter);
}
Below is the view file code. I dont have a view model just entities
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<table style="width: 100%">
<tr>
<td>
Cities:
</td>
</tr>
<tr>
#* <td>
#Html.DropDownList("Cities", (SelectList)TempData["Cities"])
</td>*#
</tr>
<tr>
<td>
#Html.ListBoxFor(model => model.Id, new SelectList(TempData["Cities"] as MultiSelectList, "Value","Text",new { style = "width:250px" })))
</td>
</tr>
<tr>
<td>
#Html.LabelFor(model => model.Keywords)
</td>
</tr>
<tr>
<td>
#Html.EditorFor(model => model.Keywords)
</td>
</tr>
<tr>
<td>
</td>
</tr>
<tr>
<td>
<input type="submit" value="Create" class="button" />
</td>
</tr>
</table>
Assuming you have changed the ID property to typeof int[] as per the comments, you still have problems, the main one being that your POST method has
[Bind(Include="Keywords,Cities")]
which excludes binding of the ID property so it will always be null on post back. When ever you use the [Bind] attribute you should reconsider what you doing and use a view model to display/edit just the properties you want, including a property for the SelectList.
You also have some pointless code in the #Html.ListBoxFor() method. TempData["Cities"] is already a SelectList so new SelectList(TempData["Cities"] as MultiSelectList, "Value","Text" is converting the SelectList to a MultiSelectList and then creating a new SelectList form it. All you need is
#Html.ListBoxFor(model => model.ID, (SelectList)TempData["Cities"], new { style = "width:250px" })
In addition, the 3rd parameter in this
SelectList cityList = new SelectList(cities, "Id", "Name", cityId);
is not required (not sure where you declared cityId because as it is, your code does not compile). The ListBoxFor() method selects the options based on the value of your ID property, and ignores the selectedValue parameter in the SelectList constructor.
Finally, in your POST method, if the model is not valid you return the view. You need to reassign the value of TempData["Cities"] or this will be null in the view and throw an exception.
Like Andrei is suggesting, you need to bind the selected value to an array type.
Front End:
<div class="DualListBoxDIV">
#Html.ListBoxFor(model => model.RelatedNewsArticlesSelected, new MultiSelectList(Model.AssignedRelatedNewsArticles, "Value", "Text", Model.RelatedNewsArticlesSelected), new { #class = "SelectedBox", Size = 10 })
</div>
Back End:
public string[] RelatedNewsArticlesSelected { get; set; }
public IEnumerable<SelectListItem> AssignedRelatedNewsArticles { get; set; }
public IEnumerable<SelectListItem> UnassignedRelatedNewsArticles { get; set; }

How to add Edit, Delete and Search functionality in single view in MVC?

I'm new to MVC.
on MSDN i've studied that there should be folder in view with the same name of controller. For every Action Method in the controller we have to create a View in the same folder.
I'm creating a test application in which:
I have a homeController with an Index ActionMethod. Corresponding to it i have a View in View/home/Index, which simply show the listing of the employees.
I know i can add a [HTTP POST] Index ActionMethod in the homeController.
But i want to add the Delete and Search functionality on the view. So that a user can search the employees with there name and can delete an employee on the same page.
I don't know how can i move ahead for this functionality.
Still i'm using this code.
homeController
public ActionResult Index()
{
ViewBag.text = "Records Listing";
var q = from p in objEmp.tbemployees select p;
return View(q);
}
Index.cshtml
#model IEnumerable<MvcApplication6.Models.tbemployee>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>#ViewBag.text</h1>
<table style="font-size:15px;">
<tr>
<th>
Name
</th>
<th>
Address
</th>
<th>
Sallary
</th>
</tr>
#foreach (var item in Model)
{
<tr >
<td style="padding:7px;">
#Html.DisplayFor(mm => item.ename)
</td>
<td style="padding:7px;">
#Html.DisplayFor(mm => item.eadd)
</td>
<td style="padding:7px;">
#Html.DisplayFor(mm => item.esal)
</td>
<td style="padding:7px; color:Blue; text-decoration:underline;">
#Html.ActionLink("Edit", "Edit", new { id = item.empno })
</td>
</tr>
}
</table>
Thanks.
For the Delete you could add a column in the table that will invoke a controller action and pass it the current record id:
<tr>
<td style="padding:7px;">
#Html.DisplayFor(mm => item.ename)
</td>
<td style="padding:7px;">
#Html.DisplayFor(mm => item.eadd)
</td>
<td style="padding:7px;">
#Html.DisplayFor(mm => item.esal)
</td>
<td style="padding:7px; color:Blue; text-decoration:underline;">
#Html.ActionLink("Delete", "Delete", new { id = item.empno })
#Html.ActionLink("Edit", "Edit", new { id = item.empno })
</td>
</tr>
and your Delete action:
public ActionResult Delete(int id)
{
... use the passed id to delete the record from the database
return RedirectToAction("Index");
}
for the Edit functionality you could have a controller action that will fetch the record and render a view that will allow for editing:
public ActionResult Edit(int id)
{
var employee = objEmp.tbemployees.FirstOrDefault(x => x.Id == id);
if (employee == null)
{
// no employee with the specified id was found
return new HttpNotFound();
}
return View(employee);
}
and then you could have a corresponding ~/Views/Home/Edit.cshtml view:
#model Employee
#using (Html.BeginForm())
{
<div>
#Html.LabelFor(x => x.ename)
#Html.EditorFor(x => x.ename)
</div>
<div>
#Html.LabelFor(x => x.eadd)
#Html.EditorFor(x => x.eadd)
</div>
...
<button type="submit">Save</button>
}
and of course a corresponding action to update the record when this form is submitted:
[HttpPost]
public ActionResult Edit(Employee employee)
{
... update the employee record
return RedirectToAction("Index");
}
You can add and implement a Delete action method in your controller. Then in your view, call #Html.ActionLink("Delete", "Delete", new { id = item.empno }). This will return a hyperlink which links to your Delete method in the controller.

How do I return List or Collection to Controller from View in MVC 3?

Someone please help me return this list properly from my view. I don't see why I'm returning null for my fieldModelList I try to pass to the controller...
Here is my view:
#model List<Regions.SOA.UI.CopyBookSchemaCreator.Models.FieldModel>
<script type="text/javascript" src="~/Scripts/jquery-ui-1.8.11.min.js"></script>
#using (Html.BeginForm("GetResponse", "TestMethods", FormMethod.Post))
{
<table id="tblMethods">
<tr>
<th>
Property Name
</th>
<th>
Request
</th>
</tr>
#foreach (FieldModel fieldModel in Model)
{
<tr>
<td>
#Html.DisplayFor(m => fieldModel.PropertyName)
</td>
<td>
#Html.TextBoxFor(m => fieldModel.PropertyValue)
</td>
</tr>
}
</table>
<div>
<input type="submit"/>
</div>
and here is my controller:
[HttpPost]
public ActionResult GetResponse(List<FieldModel> fieldModelList)
{
return GetResponse(fieldModelList);
}
I am hitting the HttpPost method but if I place a breakpoint just inside it, I am returning null for the fieldModelList right off the bat, which I was hoping would be a list of the values I entered into the texboxes on the view that is of model FieldModel...
I think something is wrong with my logic versus my syntax, or as maybe as well as my syntax, but basically what I want to do is return back a list of type FieldModel with each corresponding PropertyName and PropertyValue to the controller. I noticed I am not passing any kind of id parameter in my BeginForm statement in the view. Do I need one here?
Just in case, here is my model class for FieldModel:
namespace Regions.SOA.UI.CopyBookSchemaCreator.Models
{
public class FieldModel
{
[Display(Name = "Property")]
public string PropertyName { get; set; }
[Display(Name = "Value")]
public string PropertyValue { get; set; }
}
}
Phil Haack wrote an article some time ago explaining how to bind collections (ICollection) to view models. It goes into additional detail about creating an editor template, which you could certainly do as well.
Basically, you need to prefix the HTML elements' name attributes with an index.
<input type="text" name="[0].PropertyName" value="Curious George" />
<input type="text" name="[0].PropertyValue" value="H.A. Rey" />
<input type="text" name="[1].PropertyName" value="Ender's Game" />
<input type="text" name="[1].PropertyValue" value="Orson Scott Card" />
Then, your controller could bind the collection of FieldModel
[HttpPost]
public ActionResult GetResponse(List<FieldModel> fieldModelList)
{
return GetResponse(fieldModelList);
}
I'm not 100% sure the following would name the attributes correctly (I'd recommend using the editor template) but you could easily use the htmlAttributes argument and give it a name using the index.
#for(int i = 0;i < Model.Count;i++)
{
<tr>
<td>
#Html.DisplayFor(m => m[i].PropertyName)
</td>
<td>
#Html.TextBoxFor(m => m[i].PropertyValue)
</td>
</tr>
}
Editor Template
If you wanted to go as far as adding an editor template, add a partial view named FieldModel.ascx to /Views/Shared that is strongly typed to a FieldModel
#model Regions.SOA.UI.CopyBookSchemaCreator.Models.FieldModel
#Html.TextBoxFor(m => m.PropertyName) #* This might be a label? *#
#Html.TextBoxFor(m => m.PropertyValue)
And, then the part of your view responsible for rendering the collection would look like:
#for (int i = 0; i < Model.Count; i++) {
#Html.EditorFor(m => m[i]);
}

Model passed to a partial view is null upon form submit

I have the following model:
#model SmartSEOModel
public class SmartSEOModel
{
public SmartSEOSettingsModel SmartSEOSettingsModel { get; set; }
public SEOTemplateModel SEOTemplateModel { get; set; }
}
In my view I have a partial view which I call like this:
#using (Html.BeginForm())
{
some razor code here
<div id="pnlSmartSEO">
#Html.Partial(ViewNames.SmartSEOController_SEOTemplate, Model.SEOTemplateModel)
</div>
}
In the partial view there are some form fields bound to the SEOTemplateModel.
The problem is that when I receive the SmartSEOModel in my HttpPost action, the SEOTemplateModel is null. As if the SEOTemplateModel has been passed by copying it to the partial view.
Please advise why this is and how to workaround it.
Many thanks
My partial view looks like this:
#Html.Telerik().TabStrip().Name("SmartSEO").Items(x =>
{
x.Add().Text(T("Admin.SmartSEO").Text).Content(GetSmartSEOUI().ToHtmlString()).Selected(true);
})
#helper GetSmartSEOUI()
{
#(Html.LocalizedEditor<SEOTemplateModel, SEOTemplateLocalizedModel>("SmartSEO-Localized",
#<table class="adminContent">
<tr>
<td class="adminTitle">
#Html.NopLabelFor(model => model.Locales[item].CategoryTitleSEOTemplate):
</td>
<td class="adminData">
#Html.EditorFor(model => model.Locales[item].CategoryTitleSEOTemplate)
</td>
</tr>
</table>,
#<table class="adminContent">
<tr>
<td class="adminTitle">
#Html.NopLabelFor(model => model.CategoryTitleSEOTemplate):
</td>
<td class="adminData">
#Html.EditorFor(model => model.CategoryTitleSEOTemplate)
</td>
</tr>
</table>
))
}
My HttpPost action looks like this:
[HttpPost]
public ActionResult Configure(SmartSEOModel smartSEOModel)
{
var seoTemplate = SEOTemplateService.GetSEOTemplateById(smartSEOModel.SEOTemplateModel.Id);
if(seoTemplate == null)
{
throw new ArgumentException(String.Format("No SEOTemplate found with Id {0}", smartSEOModel.SEOTemplateModel.Id));
}
if (!ModelState.IsValid)
{
RedirectToAction("Configure");
}
SettingService.SaveSetting(smartSEOModel.SmartSEOSettingsModel.ToEntity());
seoTemplate = smartSEOModel.SEOTemplateModel.ToEntity(seoTemplate);
SEOTemplateService.UpdateSEOTemplate(seoTemplate);
UpdateLocales(seoTemplate, smartSEOModel.SEOTemplateModel);
//activity log
CustomerActivityService.InsertActivity("EditSEOTemplate", LocalizationService.GetResource("ActivityLog.EditSEOTemplate"));
SuccessNotification(LocalizationService.GetResource("SevenSpikes.NopSmartSEO.Admin.SEOTemplate.Notifications.SEOTemplateEdited"));
return View("SevenSpikes.Nop.Plugins.SmartSEO.Views.Configure", smartSEOModel);
}
Becuase you don't have a form within your partial view, it will not persist the data. Try using #Html.EditorFor instead of #Html.Partial.
So your main view would look like
#using (Html.BeginForm())
{
some razor code here
<div id="pnlSmartSEO">
#Html.EditorFor(model => model.SEOTemplateModel)
</div>
}
You would then need to move your partial view into a template. Rename your partial view to EditorTemplates\SEOTemplateModel.cshtml and place it in the same location where your main view is.
You will also need to make your template strongly typed: #model [namespace].SEOTemplateModel

Resources