ASP MVC EF6 Access foreign key table as list - asp.net-mvc

I have 2 tables, codes and countries, with a foreign key constraint on codes.countryid on countries.id - I am using the basic crud given by the controller mvc setup from within visual studio 15 but would like to replace the text input with a select for countryid so that the user can select a country from a dropdown as appose to entering the id as an int.
How do I access a list of the countries through the provided Model? Sample razor code below. Do I need to get the countries list from another model?
<div class="form-group">
<label for="CountryId" class="control-label col-md-2">Country</label>
<select name="CountryId" class="form-control" required>
<option value="">Please select ...</option>
/* Model.Countries is not available even after a foreignkey constraint? */
#foreach(var i in Model.Countries)
{
<option value="#i.id">#i.Name</option>
}
</select>
#Html.ValidationMessageFor(model => model.CountryId, "", new { #class = "text-danger" })
#Html.LabelFor(model => model.CountryId, htmlAttributes: new { #class = "control-label col-md-2" })
</div>

You should set a ViewBag variable in the controller action with the list of countries.
Assuming you have a DB Context inside your controller, you should put the following code in your action
ViewBag.CountriesList = new SelectList(_context.countries.ToList(), "Id", "Name");
And use it as below inside your view
#Html.DropDownListFor(a => a.countryId, (SelectList)ViewBag.CountriesList , htmlAttributes: new { #class = "form-control" })

Related

Set Text Box value using drop-down list's selected value

I have a schema ( table saved in Sql) like this:
ID | Name | Address
1 Sam ADD1
2 John ADD2
3 Tony ADD3
I have three fields in my form - ID , Name and Address.
Now I have implemented a drop-down for the ID field using ViewBag to pass data between the view and the controller.
I want to set the value of the fields Name and Address using the ID selected from the drop-down and not manually but I am unable to figure out a way and tried searching but could not find any appropriate solution.
Thanks for the Help.
EDIT:
My Code So Far:
Model Has been generated using the table itself (Database First Approach)
Controller
public ActionResult Create()
{
ViewBag.codes = db.Users.ToList();
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Entity_Master entity_Master)
{
if (ModelState.IsValid)
{
db.Entity_Master.Add(entity_Master);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.codes = db.Users.ToList();
return View(entity_Master);
}
View
#Html.LabelFor(model => model.ID, htmlAttributes: new { #class = "control-label col-md-2" })
#Html.DropDownListFor(model => model.ID, new SelectList(ViewBag.codes, "ID", "ID", "Select ID"))
#Html.ValidationMessageFor(model => model.ID, "", new { #class = "text-danger" })
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
#Html.LabelFor(model => model.Address, htmlAttributes: new { #class = "control-label col-md-2" })
#Html.EditorFor(model => model.Address, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Address, "", new { #class = "text-danger" })
Rendered Html
<select id="ID" name="ID">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
<input class="form-control text-box single-line" id="Name" name="Name" type="text" value="" />
<span class="field-validation-valid text-danger" data-valmsg-for="Name" data-valmsg-replace="true"></span>
<input class="form-control text-box single-line" id="Address" name="Address" type="text" value="" />
<span class="field-validation-valid text-danger" data-valmsg-for="Address" data-valmsg-replace="true"></span>
You need to listen to the change event on this dropdown, get the selected value and using the value, get the details ( Name & Address) from Id. You may make an ajax call to the server to get the data.
$(function(){
$("#ID").change(function(){
var v = $(this).val();
var url="#Url.Action("Details",Users")";
$.getJSON(url, { id : v }, function(data){
$("#Name").val(data.Name);
$("#Address").val(data.Address);
});
});
});
Now you need to have an action method which accepts the Id and return a JSON structure which has Name and Address property.
public ActionResult Details(int id)
{
var details = new { Name="Shyju", Address="5580 Twin lakes dr" };
//Hard coded for demo. You may replace it with data from db.
return Json(details, JsonRequestBehavior.AllowGet);
}
I have used Url.Action helper method to generate the proper relative url to the action method. This will work if your js code is inside the razor view. If your code is inside an external js file, you may use the solution explained in this post.

MVC validation with only HTML

I am working on a contact us form and I was able to do a successful validation but i have a small problem,
when I submit and miss one of the required values, the form comes back with the error message and does not keep the value and I have noticed that only happens if I use HTML only, it will work fine with HTML helpers.
Here is a snippet of my code:
<div class="form-group">
#Html.LabelFor(model => model.FirstName, "First Name")
<div>
<input class="form-control" name="FirstName" id="FirstName" data-val="true" type="text" value="" />
#Html.ValidationMessageFor(model => model.FirstName, "", new { #class = "text-danger" })
</div>
</div>
But it will work for the last name field:
<div class="form-group">
#Html.LabelFor(model => model.LastName, "Last Name")
<div>
#Html.EditorFor(model => model.LastName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.LastName, "", new { #class = "text-danger" })
</div>
</div>
Filling the info:
Notice after submitting the last name stays there but the first name disappears:
Any help will be appreciated :)
Because your input tag's value property value is set to an empty string.
You should use the Html.TextBoxFor helper method to generate the inuput field and it will show you the value you posted when your model validation fails. The helper method will also generate the relevant html5 attribute needed for client side unobtrusive validation.
#model ContactViewModel
#using(Html.BeginForm())
{
#Html.TextBoxFor(s=>s.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
<!-- Other fields -->
<input type="submit" />
}
Assumin your HttpPost action method is returning the posted model back to the view which Model validation fails
[HttpPost]
public ActionResult Contact(ContactViewModel model)
{
if(ModelState.IsValid)
{
// to do : return something
}
return View(model);
}

Html.DropDownListFor selected value not being selected

EDIT: I've found a solution and what I think is the reason why, see answer below.
I've got a drop down list where the selected calue is not being rendered correctly.
The code to create is as follows:
In the controller
var dlvm = new DonorIndexViewModel();
return View(dlvm);
The ViewModel is created by
public DonorIndexViewModel() {
var list = CreateSearchList();
SearchList = new SelectList(list, "Value", "Text", list.First().Value);
}
CreateSearchList is:
private IEnumerable<SelectListItem> CreateSearchList() {
var list = new List<SelectListItem> {
CreateSelectListItem(Constants.SurnameName, Constants.SurnameValue),
CreateSelectListItem(Constants.CodeName, Constants.CodeValue),
CreateSelectListItem(Constants.PostcodeName, Constants.PostcodeValue),
CreateSelectListItem(Constants.Address1Name, Constants.Address1Value)
};
return list;
}
View code is:
<div class="form-group">
#Html.LabelFor(model => model.SearchList, htmlAttributes: new {#class = "control-label col-md-1"})
<div class="col-md-11">
#Html.DropDownListFor(model => model.SearchListId, Model.SearchList, "Select Search Type", htmlAttributes: new { #class = "control-label input-width-xlarge"})
</div>
</div>
In the view, the model shows the first item is selected:
But the item is not being selected in the browser. Rendered code is as follows:
<select class="control-label input-width-xlarge" data-val="true" data-val- number="The field SearchListId must be a number." data-val-required="The SearchListId field is required." id="SearchListId" name="SearchListId">
<option value="">Select Search Type</option>
<option value="1">Surname</option>
<option value="2">Code</option>
<option value="3">PostCode</option>
<option value="4">Address (Line 1)</option>
</select>
Everything else works fine, e.g. selected value on postback is correct.
Thanks!
The API takes in an object of the selected item, try:
SearchList = new SelectList(list, "Value", "Text", list.First());
No need to add Value.
Got it to work by setting the Id in the controller:
var dlvm = new DonorIndexViewModel();
dlvm.SearchListId = 1;
return View(dlvm);
The value of this seems to determine what is selected, so if it's not set - i.e. has a value 0 - then nothing is selected. Seems a bit counter-intuitive, maybe I'll put in a feature request for this!

Cannot insert explicit value for identity column in table 'UTILISATEUR' when IDENTITY_INSERT is set to OFF

I use Visual Studio 2013 with Sql Server 2012.
I use this
to generate views for my project.
I have two tables:
UTILISATEUR (ID_UTILISATEUR,CIN,NOM,PRENOM...,ID_ROLE):
ID_UTILISATEUR is primary key and ID_ROLE is the foreign key.
ROLE (ID_ROLE, NOM_ROLE, DESCRIPTION_ROLE): ID_ROLE is the primary
key.
After the code generation process is complete, I have this:
Controllers/UtilisateurController.cs .
A new folder (Views/Utilisateur) : Create.cshtml, Delete.cshtml,
Details.cshtml, Edit.cshtml and Index.cshtml .
My problem is that when I access to the Create.cshtml page, remply the fields and click Create I get the error: Cannot insert explicit value for identity column in table 'UTILISATEUR' when IDENTITY_INSERT is set to OFF.
It explains that I can't insert values to the identity column because it is set on ON.
I don't know what I should change in the following code to resolve it.
My Create method in UtilisateurController.cs :
public ActionResult Create()
{
ViewBag.ID_ROLE = new SelectList(db.ROLE, "ID_ROLE", "NOM_ROLE");
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include="ID_UTILISATEUR,CIN_UTILISATEUR,MATRICULE_UTILISATEUR,NOM_UTILISATEUR,PRENOM_UTILISATEUR,PASSWORD_UTILISATEUR,MAIL_UTILISATEUR,TELEPHONE_UTILISATEUR,ID_ROLE")] UTILISATEUR utilisateur)
{
if (ModelState.IsValid)
{
db.UTILISATEUR.Add(utilisateur);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.ID_ROLE = new SelectList(db.ROLE, "ID_ROLE", "NOM_ROLE", utilisateur.ID_ROLE);
return View(utilisateur);
}
The error line is: db.SaveChanges();
My Views/Utilisateur/Create.cshtml page is:
....
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.ID_UTILISATEUR, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ID_UTILISATEUR)
#Html.ValidationMessageFor(model => model.ID_UTILISATEUR)
</div>
</div>
<div class="form-group">
<label for="inputCIN" class="control-label col-xs-2">CIN</label><div class="col-md-10">
#Html.EditorFor(model => model.CIN_UTILISATEUR)
#Html.ValidationMessageFor(model => model.CIN_UTILISATEUR)
</div>
</div>.....
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="créer" class="btn btn-default" />
</div>....
Please help !
The probable reason you are getting this error is that you might have altered/changed the PKEY column or data. To fix, go to your ".edmx" file and right click on the table "UTILISATEUR" and select "Update Model from Database". This should work.

ASP.NET MVC Persisting mdoel's ID value when Editing

public Edit(int? id){ /* Codes */ }
[HttpPost]
public Edit(Item model){ /* Codes */ }
I retrieve a copy of Item in the first Edit method, which would contain a value for ItemID. But when it gets to the HttpPost method, the id value's lost.
If switched to
public Edit(int? ItemID){ /* Codes */ }
[HttpPost]
public Edit(Item model){ /* Codes */ }
this way ItemID can be persisted in the Item model.
But is this a good way to handle it? Will ASP.NET MVC always be able to know that it needs to plug "ItemID" into Item?
and are there other ways to persist the ID value? Thanks.
I cannot understand how do you lose id at the HttpPost handling. Maybe you should check your binder and possibly write one for yourself? In my experience default binders are a little cumbersome. You could start from here although I don't pretend it's the best solution. In case you need to write many binders by hand take a look at some tools that could help you make conversion in declarative way like AutoMapper .
Have you tried adding the id as a parameter to the Post action?
public Edit(int? id){ /* Codes */ }
[HttpPost]
public Edit(int id, Item model){ /* Codes */ }
This way, when the form is posted back, the id will be populated from the URL.
Is the property on your Item model called ItemID? If so, then the default model binder won't populate it if you're passing around a field called ID. If you change your method signatures so that the parameter names match up with your Item property names it should work as expected.
Phil Haack had a post that may or may not be related to what you're doing.
Also, if you're not sending the ID out to the client as part of a form (hidden field or whatnot) and it isn't part of the POST URL then it would only make sense that you wouldn't have the ID field populated properly on POST.
The MVC 2 way of solving the ID issue is Optional URL Parameters.
If you're still on MVC 1 then use a binding attribute on the method argument:
[HttpPost]
public ActionResult Edit([Bind(Exclude = "ItemID")] Item model)
{
// ...
}
Little late answer but when using razor its common to use a hidden field in order to bind the Id to the model.
#Html.HiddenFor(model => model.Id)
A complete form post could look like this:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Address</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.Id)
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.StreetLine1, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.StreetLine1, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.StreetLine1, "", new { #class = "text-danger" })
</div>
</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>
}

Resources