How to insert a record in MVC4? - asp.net-mvc

How to insert a record in MVC4 with Entity Framework?
here is my viewpage:
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.brand_id)
</td>
<td>
#Html.DisplayFor(modelItem => item.brand_name)
</td>
<td>
#Html.ActionLink("ADD", "BrandList", new { item.brand_id })
</td>
</tr>
}
here is my controller code:
public ActionResult BrandList()
{
return View(db.brand.ToList());
}
[HttpPost]
public ActionResult BrandList(int id)
{
lovelist Add_Brand = new lovelist();
Add_Brand.lovelist_member = (int)Session["Member_ID"];
Add_Brand.lovelist_brand = id;
db.lovelist.Add(Add_Brand);
db.SaveChanges();
return RedirectToAction("BrandList");
}
This is what I did so far.
I cannot insert a record to my DB.
There's no any error message. I still cannt insert a record to my DB.

You have 2 actions on your controller called BrandList. The second is decorated with the [HttpPost] attribute meaning that it can only be invoked using the POST verb. But in the code you have shown you have only a hyperlink:
#Html.ActionLink("ADD", "BrandList", new { item.brand_id })
In HTML a hyperlink (anchor) sends GET request. So basically when you click on this link you are invoking the first action which doesn't do any DB saving. If you wanted to invoke the second action using a hyperlink you should rename it (because you cannot have 2 actions with the same name accessible with the same verb) and remove the [HttpPost] attribute from it:
public ActionResult SaveBrandList(int id)
{
lovelist Add_Brand = new lovelist();
Add_Brand.lovelist_member = (int)Session["Member_ID"];
Add_Brand.lovelist_brand = id;
db.lovelist.Add(Add_Brand);
db.SaveChanges();
return RedirectToAction("BrandList");
}
You will obviously need to adapt your view as well:
#Html.ActionLink("ADD", "SaveBrandList", new { item.brand_id })
There's also a possibility to use an AJAX link which would allow you to send a POST request:
#Ajax.ActionLink("ADD", "BrandList", new { item.brand_id }, new AjaxOptions { HttpMethod = "POST" })
You will need to include the jquery.unobtrusive-ajax.js script in your view for this to work. Also since you are using an AJAX call now, there's no need to be redirecting anymore from your POST controller action but simply return some partial view or JSON that could be used on the client to refresh some portion of the page.

You have missed parameter name in id and controllername . please change your action-link to
#Html.ActionLink("ADD", "BrandList","ControllerName", new {id = item.brand_id })

Related

Model Not Submitting / Binding Correctly on POST

Scenario:
I have a table with rows that are populated from a ViewModel. There are checkboxes for each row that allow the user to check 1 or more of the rows and then choose from actions in a dropdown menu to make edits to properties on the selected rows.
Everything works fine to this point, and I can get the ViewModel to pass correctly and then use it and all it's properties in a POST Action method. I could make the changes based on the option the user picked.
However, since some of the options in the dropdown would make fairly substantial and irreversible changes, I am calling a new View with a GET and populating a new table with just the selected rows, and asking the user to confirm they want to make the changes. Everything is still good up to this point. The new View populates as expected with only the rows that were selected in the previous View.
Problem:
After the user confirms their intent, an Action method is called with POST. The ViewModel that correctly populated the current View is making its way into the controller correctly. I get the ViewModel, but not with the same properties as the one that populated the View.
ViewModel
public class ProjectIndexViewModel
{
public List<ProjectDetailsViewModel> Projects { get; set; }
public string FlagFormEditProjects { get; set; }
public string FlagFormNewProjectStatus { get; set; }
}
The List<ProjectDetailsViewModel> Projects is what is used to populate the rows in the table, and Projects are what are not binding correctly in the POST Action methods in the controller.
Initial View where the checkboxes are selected. Note the example of one of the javascript functions that is called when one of the dropdown options is selected, which is what submits the form.
#using (Html.BeginForm("EditProjectsTable", "Project", FormMethod.Get, new { name = "formEditProjects", id = "formEditProjects" }))
{
#Html.HiddenFor(item => item.FlagFormEditProjects)
#Html.HiddenFor(item => item.FlagFormNewProjectStatus)
....
<table>
<thead>
....
</thead>
<tbody>
#for (int i = 0; i < Model.Projects.Count; i++)
{
<tr>
<td>#Html.DisplayFor(x => x.Projects[i].ProjectNumber)</td>
<td>#Html.DisplayFor(x => x.Projects[i].ProjectWorkType)</td>
.... // more display properties
<td>
#Html.CheckBoxFor(x => x.Projects[i].Selected, new { #class = "big-checkbox" })
#Html.HiddenFor(x => x.Projects[i].ProjectModelId)
</td>
</tr>
}
</tbody>
</table>
}
function submitFormRemoveProjects() {
$("#FlagFormEditProjects").attr({
"value": "RemoveProjects"
});
$('#formEditProjects').submit();
}
Action method that returns the "confirmation" View (works fine)
[HttpGet]
[Authorize(Roles = "Sys Admin, Account Admin, User")]
public async Task<ActionResult> EditProjectsTable([Bind(Include = "Projects,FlagFormEditProjects,FlagformNewProjectStatus")]ProjectIndexViewModel projectIndexViewModel)
{
// Repopulate the Projects collection of ProjectIndexViewModel to
// include only those that have been selected
return View(projectIndexViewModel);
}
View that is returned from Action method above (works fine) Note that the Action method that gets called is set dynamically with the actionName variable in the Html.BeginForm call.
#using (Html.BeginForm(actionName, "Project", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(model => model.FlagFormNewProjectStatus)
....
<table>
<thead>
....
</thead>
<tbody>
#for (int i = 0; i < Model.Projects.Count; i++)
{
<tr>
<td>#Html.HiddenFor(x => x.Projects[i].ProjectModelId)</td>
<td>#Html.DisplayFor(x => x.Projects[i].ProjectNumber)</td>
<td>#Html.DisplayFor(x => x.Projects[i].ProjectWorkType)</td>
.... // more display properties
</tr>
}
</tbody>
</table>
<input type="submit" value="Delete Permanently" />
}
An example of one of the Controller Action methods that is called from this View, and that does not have the same Project that was in the View. Somehow, it has the same number of Projects that were originally selected, but if only one was selected, it has the Project with the lowest Model Id. I'm not sure how else to describe what's happening. But in summary, the correct ViewModel is not making it's way into the POST method example shown below.
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "Sys Admin, Account Admin")]
public async Task<ActionResult> DeleteConfirmedMultipleProjects([Bind(Include = "Projects")] ProjectIndexViewModel projectIndexViewModel)
{
if (ModelState.IsValid)
{
// Remove Projects from db and save changes
return RedirectToAction("../Project/Index");
}
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Please help!
The issue is that when you submit to the EditProjectsTable() method from the first view, the values of all form controls are added to ModelState.
Repopulating your collection of ProjectDetailsViewModel does not update ModelState, and when you return the view, the DisplayFor() methods will display the correct values because DisplayFor() uses the values of the model, however your
#Html.HiddenFor(x => x.Projects[i].ProjectModelId)
will use the values from ModelState, as do all the HtmlHelper methods that generate form controls (except PasswordFor()).
One way to solve this is to call ModelState.Clear() before you return the view in the EditProjectsTable() method. The HiddenFor() method will now use the value of the model because there is no ModelState value.
[HttpGet]
[Authorize(Roles = "Sys Admin, Account Admin, User")]
public async Task<ActionResult> EditProjectsTable(ProjectIndexViewModel projectIndexViewModel)
{
// Repopulate the Projects collection of ProjectIndexViewModel to
// include only those that have been selected
ModelState.Clear(); // add this
return View(projectIndexViewModel);
}
For a explanation of why this is the default behavior, refer the second part of this answer.
Side note: Your using a view model, so there is no point including a [Bind] attribute in your methods.
I think your problems comed from this part:
#Html.CheckBoxFor(x => x.Projects[i].Selected, new { #class = "big-checkbox" })
#Html.HiddenFor(x => x.Projects[i].ProjectModelId)
I had this error before and what I did is adding a Boolean property to ProjectDetailsViewModel like IsSelected.
then you should have :
#Html.CheckBoxFor(x => x.Projects[i].IsSelected, new { #class = "big-checkbox" })
Then on method you should add:
foreach (var project in ProjectIndexViewModel.Projects )
{
if (project.IsSelected==true)
"put your logic here"
}

Passing data base info from controller to view in .NET MVC

Hello I'm trying to pass some database info from my controller to my view, but don't find the best way to do it. I'm populating the model in my controller, but I need to populate those values from database. I have a class called DataAccess which is the one that contains all my queries but not sure where I should put the logic to populate. I would say a for loop in my controller to populate the values, but seems to fail since I'm declaring the SchedulerViewModel there
The idea is having my values next to a radio button, so when selecting a radio button, I can "detect" the value and do something with that option....any suggestion would be appreciated...
My model:
public class SchedulerViewModel
{
public string theValue { get; set; }
public SelectListItem[] Items { get; set; }
}
My Controller:
public ActionResult Scheduler()
{
//DataAccess dataAccess = new DataAccess();
//for loop here???
var model = new SchedulerViewModel
{
Items = new[]
{
new SelectListItem { Value = "U", Text = "USA" }
}
};
return View(model);
}
My view:
#using (Html.BeginForm())
{
for (int i = 0; i < Model.Items.Count(); i++)
{
#Html.RadioButtonFor(x => x. theValue, Model.Items[i].Value, new { id = "item_" + i })
#Html.Label("item_" + i, Model.Items[i].Text)
<br />
}
}
Ideally you would have a service class that handles your database access. You shouldn't directly invoke the data layer from the controller, although nothing prevents you from doing it. For simplicity, I'm just putting calling the data access directly in the controller. The idea is that you need to return a collection of data, here an IEnumerable, in the View at the controller level so that the View can display this data.
Controller:
[HttpGet]
public ActionResult Index()
{
KnowledgeBaseEntities context = new KnowledgeBaseEntities();
IEnumerable<ISSUE> issues = context.ISSUES;
if(issues == null)
{
return HttpNotFound();
}
return View(issues);
}
View:
As you can see I'm referencing the collection of data that I'm expecting from the controller.
#model IEnumerable<ISSUE>
In this case it's an IEnumerable just like I had in the controller. Then you'll notice I'm referencing a Model object when I iterate the model.
#foreach (var item in Model)
Then I'm looping through each row of the model in order to add table rows to the table. Because we're using Model Binding from the Entity Framework. We're using Razor Syntax. You also notice I'm using Action Links for each row in the last column. This allows me to Edit, Delete or provide Details for a row of data. However, I will need to invoke another Controller Action for that. For example, you'd have an Edit controller action method that returns a single ISSUE to an Edit View.
#model IEnumerable<ISSUE>
#{
ViewBag.Title = "Knowledge Base Issues";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2 class="line">All Issues</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="flat">
<tr>
<th>#Html.DisplayNameFor(model => model.KEYWORDS)</th>
<th>#Html.DisplayNameFor(model => model.SUBJECT)</th>
<th>#Html.DisplayNameFor(model => model.DATE_ENTERED)</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>#Html.DisplayFor(modelItem => item.KEYWORDS)</td>
<td>#Html.DisplayFor(modelItem => item.SUBJECT)</td>
<td>#Html.DisplayFor(modelItem => item.DATE_ENTERED)</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.ISSUE_ID }) |
#Html.ActionLink("Details", "Details", new { id=item.ISSUE_ID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.ISSUE_ID })
</td>
</tr>
}

Using Model with a Partial View - The name does not exist in the current context

Another nerddinner noob here. I've made it through the example nerddinner project and am starting to create a new similar thing that I need.
So, my index.cshtml looks like this:
#model PagedList.IPagedList<ProjectSender.Models.Incident>
...
#foreach (var item in Model)
{
<tr>
<td>
#Html.ActionLink(item.Title, "Details", new { id = item.IncidentId })
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
<td>
#Html.Partial("_ReserveStatusList", item)
</td>
</tr>
}
My partial view looks like this:
#model PagedList.IPagedList<ProjectSender.Models.Incident>
<script src="/Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>
<script type="text/javascript">
function AnimateProjectMessage() {
$("#projectmsg").animate({ fontSize: "1.5em" }, 400);
}
</script>
<div id="projectmsg">
#Ajax.ActionLink("Reserve this Project",
"Reserve", "Projects",
new { id = item.IncidentId },
new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "projectmsg", OnSuccess = "AnimateProjectMessage" })
</div>
If I replace the partial view and just use the Ajax.ActionLink in the index.cshtml, it works ok. However, if I use it in the partial view, for item (in item.IncidentId) I get "The name item does not exist in the current context." However, there are no red squiggles in VS. I get this error in the browser.
If you're comparing this to nerddinner, I'm basically trying to drop the RSVP option for each dinner inside the list of Dinners. The RSVP partial view is normally on the Details page.
Edit: for the sake of being complete. Here is my controller code as requested in case someone is looking at this in the future:
public ActionResult Index(string searchString, int? page)
{
int pageSize = 10;
int pageNumber = (page ?? 1);
IQueryable<Incident> incidents = null;
incidents = incidentRepository.FindRecentIncidents(searchString);
return View(incidents.ToPagedList(pageNumber, pageSize));
}
Ultimately, after upgrading from MVC3/EF4 to MVC4/EF4 and putting the partial view back to the original nerddinner code (as was suggested in the accepted answer), all is ok.
Note that in partial there is no item defined. Partial view receives it as a model (fix your partial's model to be just a single Incident btw - you are not passing a list in there), so you need to use Model to refer to the item passed instead:
#model ProjectSender.Models.Incident
...
#Ajax.ActionLink("Reserve this Project",
"Reserve", "Projects",
new { id = Model.IncidentId },

Model after post not change why

I have Page for Both Insert User and this work fine but after I insert new info i send new model but this not work.the info that i insert before are still in textbox without any error. why???
return View(new User());
#using (#Html.BeginForm("RegisterUser", "UserManagement", FormMethod.Post))
{
#Html.AntiForgeryToken()
<table class="Registertbl">
<tr>
<td>نام*</td>
<td> #Html.TextBoxFor(m => m.FName, new { maxlength = 20})<br />
</td>
<td>سمت*</td>
<td>#Html.TextBoxFor(m => m.Post, new { maxlength = 200})</td>
</tr>
</table>
<br />
<input type="submit" value="Insert" class="insertBtn" />
#Html.ActionLink("back", "ViewUserList", "UserManagement")
}
//Controller
[HttpGet]
public ActionResult RegisterUser()
{
return View(new User());
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult RegisterUser(Common.UsersManagement.Entities.User model)
{
SetUserManagement();
var Result = userManagement.RegisterUser(model);
if (Result.Mode == Common.Extensions.ActionResultMode.Successfully)
{
return View(new User());
}
// if not Successfull
return View(model);
}
maf748 is correct, you should Post-Redirect-Get. You can communicate to the GET action method using TempData that a message should be displayed, e.g.
TempData.Message = "User registered.";
return RedirectToAction( "RegisterUser" );
Then in your RegisterUser view you can check if TempData.Message has a value.
However, if after all that you still want do do it your way you could try ModelState.Clear() before returning the new View. The problem this will cause is that if the user refreshes the page in their browser it will send them back to your Post method, prompting them in the browser with that awful "do you want to resubmit your data" message and potentially creating duplicate registrations in your database.
Try redirecting back to the GET RegisterUser.
The reason is: when you submit a form to MVC, all the values in the ModelState (basically the Request values) take precedence over any model you pass to the view. The redirect will give you an empty ViewDataDictionary, so all values will be pulled from the Model you're passing (the new User())
if (Result.Mode == Common.Extensions.ActionResultMode.Successfully)
{
return RedirectToAction("RegisterUser");
}

Details asp.net mvc4

I'm trying to open the details of the "Ansatte" object. The problem is that the Int parameter is only null
I have this View
#model IEnumerable<EL4.Administrasjon.Models.Ansatte>
<table>
#foreach (var item in Model) {
<tr data-pkey="#item.IdBaksystem">
<td>
#Html.DisplayFor(modelItem => item.AnsNavn)
</td>
<td>
#Html.DisplayFor(modelItem => item.ePostAdresse)
</td>
<td class="rowControl hidden">
#Html.ActionLink("Details", "Details", new { id=item.ID_Ansatt }) |
</td>
</tr>
}
Then I have this in the controller
public class HMAnsatteController : Controller
{
//
// GET: /HMAnsatte/
public ActionResult Index()
{
HM_000_EL4Entities hmEnt = new HM_000_EL4Entities();
List<Ansatte> HMansatte = hmEnt.Ansatte.ToList();
return View(HMansatte);
}
public ActionResult Details(int? ansattNr)
{
if (ansattNr == null)
{
return null;
}
else
{
Entities ent = new Entities();
Ansatt el4Ansatt = ent.Ansatt.Where(a => a.AnsattNr == ansattNr).First();
return View(el4Ansatt);
}
}
}
When I click details, the URL looks correct: http://localhost:50009/HMansatte/Details/1
But the int ansattNr is always "null"
you have this ...
public ActionResult Details(int? ansattNr)
and it should be this because of the dynamic object you are passing in the link
public ActionResult Details(int? id)
or change this instead ...
#Html.ActionLink("Details", "Details", new { ansattNr=item.ID_Ansatt })
It the line where you are creating your action link, you are naming the parameter "id" but in your action method, you are calling it "ansattNr". Those names should be the same. Since the default routing is already set up for "id", I would just change the method signature of your action method to this:
public ActionResult Details(int? id)
That should solve the problem.
Your passing an variable with a name of id into the controller (which your global.asax has mapped to the URL so it shows like it does) but your controller is looking for a variable with name ansattNr.
You can either change the name of the variable in your controller to id or you can change your Action link to #Html.ActionLink("Details", "Details", new { ansattNr=item.ID_Ansatt }) but the second option will change the formatting on your URL.

Resources