how to convert formcollection to model in mvc - asp.net-mvc

Is it possible to convert formcollection to a 'model' known?
[HttpPost]
public ActionResult Settings(FormCollection fc)
{
var model=(Student)fc; // Error: Can't convert type 'FormCollection' to 'Student'
}
NOTE : for some reasons i can't use ViewModel instead.
Here is my code VIEW: Settings.cshtml
#model MediaLibrarySetting
#{
ViewBag.Title = "Library Settings";
var extensions = (IQueryable<MediaLibrarySetting>)(ViewBag.Data);
}
#helper EntriForm(MediaLibrarySetting cmodel)
{
<form action='#Url.Action("Settings", "MediaLibrary")' id='MLS-#cmodel.MediaLibrarySettingID' method='post' style='min-width:170px' class="smart-form">
#Html.HiddenFor(model => cmodel.MediaLibrarySettingID)
<div class='input'>
<label>
New File Extension:#Html.TextBoxFor(model => cmodel.Extention, new { #class = "form-control style-0" })
</label>
<small>#Html.ValidationMessageFor(model => cmodel.Extention)</small>
</div>
<div>
<label class='checkbox'>
#Html.CheckBoxFor(model => cmodel.AllowUpload, new { #class = "style-0" })<i></i>
<span>Allow Upload.</span></label>
</div>
<div class='form-actions'>
<div class='row'>
<div class='col col-md-12'>
<button class='btn btn-primary btn-sm' type='submit'>SUBMIT</button>
</div>
</div>
</div>
</form>
}
<tbody>
#foreach (var item in extensions)
{
if (item != null)
{
<tr>
<td>
<label class="checkbox">
<input type="checkbox" value="#item.MediaLibrarySettingID"/><i></i>
</label>
</td>
<td>
<a href="javascript:void(0);" rel="popover" class="editable-click"
data-placement="right"
data-original-title="<i class='fa fa-fw fa-pencil'></i> File Extension"
data-content="#EntriForm(item).ToString().Replace("\"", "'")"
data-html="true">#item.Extention</a></td>
</tr>
}
}
</tbody>
CONTROLLER:
[HttpPost]
public ActionResult Settings(FormCollection fc)//MediaLibrarySetting cmodel - Works fine for cmodel
{
var model =(MediaLibrarySetting)(fc);// Error: Can't convert type 'FormCollection' to 'MediaLibrarySetting'
}
data-content and data- attributes are bootstrap popover.

Another approach in MVC is to use TryUpdateModel.
Example:
TryUpdateModel or UpdateModel will read from the posted form collection and attempt to map it to your type. I find this more elegant than manually mapping the fields by hand.
[HttpPost]
public ActionResult Settings()
{
var model = new Student();
UpdateModel<Student>(model);
return View(model);
}

Nice question!
Had same in the quest of making a universal base controller, model independent. Thanks to many people, the last one was #GANI, it's done.
Type ViewModelType is set in subclassed controller to anything you want.
public ActionResult EatEverything(FormCollection form)
{
var model = Activator.CreateInstance(ViewModelType);
Type modelType = model.GetType();
foreach (PropertyInfo propertyInfo in modelType.GetProperties())
{
var mykey = propertyInfo.Name;
if (propertyInfo.CanRead && form.AllKeys.Contains(mykey))
{
try
{
var value = form[mykey];
propertyInfo.SetValue(model, value);
}
catch
{
continue;
}
}
}
now that everything you received from an unknown form is in your real model you can proceed to validation from this post https://stackoverflow.com/a/22051586/7149454

You can try this way
public ActionResult Settings(FormCollection formValues)
{
var student= new Student();
student.Name = formValues["Name"];
student.Surname = formValues["Surname"];
student.CellNumber = formValues["CellNumber"];
return RedirectToAction("Index");
}

maybe it's too late, but maybe it will be useful for someone )
https://www.nuget.org/packages/tidago.apofc
Auto converter formcollection to object.
TestReadonlyModel resultObject = new TestReadonlyModel();
new ObjectPopulator().Populate(HttpContext.Request.Form, resultObject);

Related

With Asp.net Mvc I would like to select multiple languages in which members can speak using Dropdownlist in a form

I didn't understand how to send and save the selected languages.
When I use Plugin (select2), there is a problem with Js and other Plugin in the template.
View:
<div class="form-group">
<label class="col-md-4 control-label">Which Languages Speak *</label>
<span style="color:red;"><small> >>> You can select multiple languages.</small></span>
<div class="col-md-8 inputGroupContainer">
<div class="input-group">
<span class="input-group-addon" style="max-width: 100%;"><i class="glyphicon glyphicon-list"></i></span>
<select class="form-control" name="Dil_Id[]" multiple="multiple" id="select" required>
#foreach (var item in dilList)
{
<option value="#item.Id">#item.DilAdi_Eng</option>
}
</select>
</div>
</div>
</div>
Controller:
public class YeniIhtiyacSahibiController : Controller
{
// GET: IhtiyacSahibi/YeniIhtiyacSahibi
IhtiyacSahibiUyeBLL _ISUye = new IhtiyacSahibiUyeBLL();
ISUDilBLL _isuDil = new ISUDilBLL(); // members languages
public ActionResult Index(int Id = 0)
{
var model = _ISUye.GetById(Id);
ViewBag.Mesaj = GenelAraclarBLL.KayitYeni(); // Message Succesfull
return View(model);
}
[HttpPost]
public ActionResult Index(IhtiyacSahibiUye model)
{
return View(model);
}
}
What can i do without plugin and how can i send and save that items? I don't know how to make and send the list. Thank you for your time.
I post forms with select2 like this:
$.ajax({
url: "/Projects/Edit/",
type: "POST",
data: {
__RequestVerificationToken: token,
ProjectManagersString: $("#ProjectManagers").val(), //select 2 control value
}
})
Controller:
public async Task<ActionResult> Edit(Project project)
{
if (Request.Form["ProjectManagersString[]"] != null)
{
foreach (var pmstring in Request.Form["ProjectManagersString[]"].Split(','))
{
}
}
}
The binding of the form controls is done in the parameter indicated in the Post method of the controller. Following an example to access the selected value.
The Model
public class Mymodel
{
    public List<SelectListItem> dilList { get; set; }
    public int? Id { get; set; }
}
The Controller
public class YeniIhtiyacSahibiController : Controller
{
[HttpGet]
public ActionResult Index()
{
//Get Method
return View(model);
}
[HttpPost]
public ActionResult Index(IhtiyacSahibiUye model)
{
car selectedId=model.Id
return View(model);
}
}
The View
#model namespace.Models.Mymodel 
#{
    Layout = null;
} 
<html>
<head>
</head>
<body>
 #using (Html.BeginForm("Index", "YeniIhtiyacSahibiController", FormMethod.Post))
    {
        <table>
            <tr>
                <td>
                    DilAdi_Eng:
                </td>
                <td>
                    #Html.DropDownListFor(m => m.Id, Model.dilList, "Language")
                </td>
            </tr>           
            <tr>
                <td></td>
                <td>
                    <input type="submit" value="Submit"/>
                </td>
            </tr>
        </table>
    }
</body>
</html>
Cordialement

Post Request is not returning same object as passed

I am trying to do a simple CRUD app asp.net core using MVC and the strangest thing is happening to me.
create the model and pass it in to the form but when I go to save it, it no longer has the Id that I passed into it.
[HttpGet]
public IActionResult CreateCompany(Guid id)
{
//id = 677b57f1-d0b2-484b-9892-b06e6eb9f1f7
var pageId = id;
var company = new CompanyListItem() {PublicPageId = pageId};
return View(company);
}
[HttpPost]
public IActionResult CreateCompany(CompanyListItem model)
{
//model.PublicPageId = 00000000-0000-0000-0000-000000000000
if (ModelState.IsValid)
{
model.Id = Guid.NewGuid();
var newModel = _companyDataProvider.Add(model);
PublicPageViewModel page = null;
if (newModel != null)
{
page = _pageDataProvider.GetPageIdFromCompanyListId(newModel.Id);
}
if (page != null)
{
return RedirectToAction("Details", page);
}
}
return View();
}
my form:
#model CompanyListItem
<h1>Add Company</h1>
<form method="post">
<div class="col-md-6">
<div class="form-group">
<label asp-for="Header"></label>
<input asp-for="Header" class="form-control"/>
</div>
<div>
<input type="submit" class="btn btn-success" value="save"/>
<a class="btn btn-default">Cancel</a>
</div>
</div>
</form>
Does anyone know why this is happening? Or how i can prevent it from happening?

The edit button is deleting from the database instead of saving to it MVC

I have posted the relevant code to this issue below. My problem is, let's say, the database is displaying NA, I want to edit it and put in 1.1, or some number. Instead of updating and saving this new number, it deletes NA and does not update or save anything, so I know it is doing something, but I'm not sure where I have gone wrong. If I change the type in the model to int or object, it gives an error for conversion to string. Can someone help please? Thank you!
Controller:
public ActionResult Edit ()
{
return View ();
}
[HttpPost]
public ActionResult Edit(MyIssue issues)
{
var model = new Test.Models.Tables();
if (ModelState.IsValid)
{
db.Entry(issues).State = EntityState.Modified;
issues.Number = model.Number;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(issues);
}
Model:
namespace Test.Models
{
public class Tables: DbContext
{
public string Number { get; set; }
}
}
View:
<td>
#if (issue.Number != null)
{
#Html.HiddenFor(modelItem => issue.Number)
#Html.DisplayFor(modelItem => issue.Number)
<text>|</text>
<h5 id="editclass">
#Html.ActionLink("Edit", "Page1", new { id = issue.Number })
</h5>
using (Html.BeginForm())
{
#Html.ValidationSummary(true) {
<fieldset>
#Html.HiddenFor(modelItem => issue.Number)
<div class="editor-field">
#Html.EditorFor(modelItem => issue.Number)
#Html.ValidationMessageFor(modelItem => issue.Number)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
}
}
</td>
From your code, I assume that the code you shown is inside a loop where issue is the loop iterator variable. So razor will generate an input field with name "issue.Number". When the form is submitted, model binder cannot bind this form value to the Number property of your MyIssue object ! So it gets the default null value and your code is assigning the null value as the Number property and saving it.
You should generate an input field with name="Number". You may use the Html.TextBox helper method to do so.
#foreach (var issue in SomeCollection)
{
<tr>
<td>
#using (Html.BeginForm())
{
<!-- Other fields also goes here -->
#Html.TextBox("Number",issue.Number)
<input type="submit" />
}
</td>
</tr>
}

There is no ViewData item of type 'IEnumerable<SelectListItem>' that has the key 'CategoryID

I have found a lot of similar threads on this problem. But whatever I do, it never works for me.
The ONLY thing I want to achieve right now, is to fill a dropdown list with database values in a partial view, that's within a partial view. That is all, and this is driving me absolutely nuts. A user should be able to chose a category name in the dropdown list.
Here's my Controller Class:
public class AttributeController : Controller
{
private readonly IRepository<ClassLibrary.Entities.Attribute> _aRepository;
private readonly IRepository<Category> _cRepository;
public AttributeController() : this(new Repository<ClassLibrary.Entities.Attribute>(), new Repository<Category>())
{
}
public AttributeController(IRepository<ClassLibrary.Entities.Attribute> repo, IRepository<Category> repository)
{
_aRepository = repo;
_cRepository = repository;
}
//
// GET: /Attribute/
public ActionResult Index()
{
var attributes = _aRepository.GetAll();
var attributeViewModels = new List<AttributeViewModel>();
foreach (ClassLibrary.Entities.Attribute attribute in attributes)
{
var viewModel = new AttributeViewModel();
viewModel.Id = attribute.Id;
viewModel.AttributeName = attribute.Name;
attributeViewModels.Add(viewModel);
}
return View(attributeViewModels);
}
//
// GET: /Attribute/Details/5
public ActionResult Details(int id)
{
return View();
}
//
// GET: /Attribute/Create
public ActionResult Create()
{
ViewData["CategoryID"] = new SelectList(_cRepository.GetAll().ToList(), "Category_id", "Category");
IEnumerable<SelectListItem> items = _cRepository.GetAll().Select(c => new SelectListItem
{
Value = c.Id.ToString(),
Text = c.Name
});
ViewData["CategoryID"] = items;
return View();
}
//
// POST: /Attribute/Create
[HttpPost]
public ActionResult Create(FormCollection collection)
{
try
{
// TODO: Add insert logic here
return RedirectToAction("Index");
}
catch
{
return View();
}
}
And here's the index View:
#model IEnumerable<GUI.Models.AttributeViewModel>
#{
ViewBag.Title = "Attributes";
}
<div>
#Html.Partial("~/Views/Attribute/Create.cshtml", new GUI.Models.AttributeViewModel())
</div>
<h2>All existing Attributes</h2>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.AttributeName)
</th>
<th></th>
</tr>
#if(Model != null)
{
foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.AttributeName)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
#Html.ActionLink("Details", "Details", new { id=item.Id }) |
#Html.ActionLink("Delete", "Delete", new { id=item.Id })
</td>
</tr>
}
}
</table>
Here's the partial View Within the index view:
#model GUI.Models.AttributeViewModel
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Create an attribute for this Category</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.Partial("~/Views/Attribute/CategoryPartial.cshtml", new GUI.Models.CategoryViewModel())
<div class="form-group">
#Html.LabelFor(model => model.AttributeName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.AttributeName)
#Html.ValidationMessageFor(model => model.AttributeName)
</div>
</div>
</div>
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
And finally CategoryPartialView within the partial view that will contain the DropDown List where the user should be able to select a category Name.
#model GUI.Models.CategoryViewModel
#using GUI.Controllers
#using System.Collections.Generic
#{
//var categories = (IEnumerable<GUI.Models.CategoryViewModel>)ViewData["categories"];
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.Name, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("CategoryID", (IEnumerable<SelectListItem>)ViewData["CategoryID"])
</div>
</div>
}
The exception ALWAYS occurs when I'm debugging the application and it points to the #Html.DropDownList part. Claiming that "There is no ViewData item of type 'IEnumerable' that has the key 'CategoryID".
#Html.DropDownList("CategoryID", (IEnumerable<SelectListItem>)ViewData["CategoryID"]
I'm sorry for posting so many code blocks. But I would really like to solve this.I've beaten my head against the wall for hours with frustration, and any help would be greatly appreciated.
When you use #Html.Partial("~/Views/Attribute/CategoryPartial.cshtml", new GUI.Models.CategoryViewModel()) you are directly instantiating the partial view. The controller does not get called and is not responsible for generating the HTML markup string. Additionally, you are passing an empty view model (new GUI.Models.CategoryViewModel()). Since the controller does not get called, it does not get the data for the drop down list and, obviously, does not save it in your ViewData.
Use the #Html.Action helper instead:
<div class="form-group">
#Html.Action("Create", "Attribute")
<div class="form-group">
Change the Create action like this:
//
// GET: /Attribute/Create
public ActionResult Create()
{
ViewData["CategoryID"] = new SelectList(_cRepository.GetAll().ToList(), "Category_id", "Category");
IEnumerable<SelectListItem> items = _cRepository.GetAll().Select(c => new SelectListItem
{
Value = c.Id.ToString(),
Text = c.Name
});
ViewData["CategoryID"] = items;
return PartialView("CategoryPartial", new GUI.Models.CategoryViewModel());
}
Note: I don't know your entire structure, but I might be best to use this approach and to return a Lis<SelectListItem> model.
when calling:
#Html.Partial("~/Views/Attribute/Create.cshtml", new GUI.Models.AttributeViewModel())
you call the view directly with out passing throw the controller so the model you have there is an empty model!
try pass throw the controller to create you'r model and send it back as a view:
#Html.RenderPartial("YOUR CONTROLLER",model);

how can i get the text box for a view? in my controller

I follow this example to make n to n relations
http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/updating-related-data-with-the-entity-framework-in-an-asp-net-mvc-application
it work fine but for the n to n relations with payload to the database i figure out and I can do the [HttpGet] and show the view what i want to show but now i want to know how can i get the textbox I have in my view, I can get the checkbox in my controller (see see below the action) and this is my view so my question will be how can get the textbox too? in my controller for every checkbox?
#using (Html.BeginForm("AgregarEmpresas", "Empleado"))
{
<fieldset>
<div class="editor-field">
<table>
<tr>
#{
int cnt = 0;
List<ITCOrganigrama.ViewModel.AsignarEmpresa> empresas = ViewBag.Empresas;
foreach (var empresa in empresas)
{
if (cnt++ % 5 == 0) {
#: </tr> <tr>
}
#: <td>
<input type="checkbox"
name="selectedEmpresa"
value="#empresa.EmpresaId"
#(Html.Raw(empresa.Assigned ? "checked=\"checked\"" : "")) />
#empresa.Nombre
<div>
#Html.LabelFor(model => empresa.cargo)
#Html.TextBoxFor(model => empresa.cargo, new { style = "width: 150px;" })
#Html.ValidationMessageFor(model => empresa.cargo)
</div>
#:</td>
}
#: </tr>
}
</table>
</div>
<p>
<input type="submit" value="Agregar" />
</p>
</fieldset>
}
the action where i get the chekbox
[HttpPost]
public ActionResult AgregarEmpresas(int? id, FormCollection formCollection, string[] selectedEmpresa)
{
}
my final view:
http://s3.subirimagenes.com:81/otros/previo/thump_7406511add1.jpg
http://www.subirimagenes.com/otros-add1-7406511.html
Edited:
ViewModel Class
public class AsignarEmpresa
{
public int EmpresaId { get; set; }
public string Nombre { get; set; }
public string cargo { get; set; }
public bool Assigned { get; set; }
}
Look at your post action and it's parameters. Names of those are really important.
Your checkboxes
<input type="checkbox"
name="selectedEmpresa"
value="#empresa.EmpresaId"
are working fine beacuse look at the name of the input its "selectedEmpresa" it's the same name as in Controller Action definition. Model binder looks for this name in posted data and if he finds it, he creates object from it. In your case he will try to parse data into string[] object.
So ... first of all you have to change action definition to something like.
[HttpPost]
public ActionResult AgregarEmpresas(int? id, FormCollection formCollection, string[] selectedEmpresa,string [] empresaTextBox)
{
}
Then you have to change generated html.
#Html.TextBoxFor(model => empresa.cargo, new { style = "width: 150px;", name="empresaTextBox" })
With those changes you should get some data inside Action. However you will get something weird beacuse you have multiple checkboxes and textboxes in order to tell model binder that there are multiple elements of those you have to prepare special name of inputs that contains index number.
Look at this example
<input name="childs[0]"></input>
<input name="childs[1]"></input>
In this case Model Binder will create array of objects that contains 2 of them.
So finally your code would have to look like this.
#using (Html.BeginForm("AgregarEmpresas", "Empleado"))
{
<fieldset>
<div class="editor-field">
<table>
<tr>
#{
int cnt = 0;
int i=0;
List<ITCOrganigrama.ViewModel.AsignarEmpresa> empresas = ViewBag.Empresas;
foreach (var empresa in empresas)
{
if (cnt++ % 5 == 0) {
#: </tr> <tr>
}
#: <td>
<input type="checkbox"
name="selectedEmpresa[#i]"
value="#empresa.EmpresaId"
#(Html.Raw(empresa.Assigned ? "checked=\"checked\"" : "")) />
#empresa.Nombre
<div>
#Html.LabelFor(model => empresa.cargo)
#Html.TextBoxFor(model => empresa.cargo, new { style = "width: 150px;" ,name=String.Format("empresaTextBox\[{0}\]",i) })
#Html.ValidationMessageFor(model => empresa.cargo)
</div>
#:</td>
i++;
}
#: </tr>
}
</table>
</div>
<p>
<input type="submit" value="Agregar" />
</p>
</fieldset>
}
If you will get this to work. Then i would try to create a class with one boolean and one string value. With this change you would operate on the array of classes instead of two arrays with strings.

Resources