I have read hundreds of posts about this problem and I still can't find a solution.
Please help with this horrible mistery;
I would like to have different default values in my DropDownListFor. The "PartialViewList1 exists out of 4 items.
I want the DropDownListFor to select the id of the current item. (item.id)
But because of testing purposes I just filled in "3". And even that doesn't work.
The Models are filled correctly, I am able to add more code of the controller but that wouldn't add much. But please ask if you want me to.
And yes I know that it is better to make the SelectList in the controller, but first I want to make it work.
View:
#foreach (var item in Model.PartialViewList1)
{
<tr>
<td>Plaats: </td>
<td>#item.PlaceNumber</td>
<td>
#Html.DropDownListFor(x => x.PartialView.Id, new SelectList(Model.PartialViewList2, "Id", "Name", 3),
new { onchange = "this.form.submit();" })</td>
</tr>
}
Screen shot of the users view
I hope that maybe someone can use this for his or her problem.
With Stephen Mueke I have found the solution. The problem is that if "x => x.PartialView.Id" already has a value then the default value : "3" will be overriden by the Id.
And you can't generate multiple DropDownlistFor's while binding them to the same property.
My solution on my problem:
View:
#using (Html.BeginForm("_PartialSettingsDropDownList1", "Home")){
<table>
#for (int i = 0; i < Model.maxNumberOfViews; i++)
{
<tr>
<td>
Plaats #(i+1)
</td>
<td>
#Html.DropDownListFor(x => Model.PartialViewList[i].ID, new SelectList(Model.PartialViewList, "Id", "Name", Model.PartialViewList[i].ID), "select")
</td>
</tr>
}
</table>
#Html.HiddenFor(x => x.maxNumberOfViews)
<input class="submit" type="submit" value="Submit" />}
Controller:
[HttpGet]
public PartialViewResult _PartialSettingsDropDownList1()
{
PartialScreenViewModel viewModel = new PartialScreenViewModel();
viewModel.PartialViewList = homeModel.AllBoxViews(databaseRepository.PartialViews);
viewModel.maxNumberOfViews = viewModel.PartialViewList.Count();
return PartialView(viewModel);
}
[HttpPost]
public RedirectResult _PartialSettingsDropDownList1(PartialScreenViewModel viewModel)
{
for (int i = 0; i < viewModel.maxNumberOfViews; i++)
{
PartialView viewOnScreen = databaseRepository.PartialViews.FirstOrDefault(x => x.ID == viewModel.PartialViewList[i].ID);
databaseRepository.UpdatePartialView(viewOnScreen, i+1);
}
return new RedirectResult("Settings");
}
Model:
public List<PartialView> AllBoxViews(IEnumerable<PartialView> allViews)
{
List<PartialView> OnlyBoxViews = new List<PartialView>();
foreach (var item in allViews.Where(item => item.Type.Equals("box")))
{
OnlyBoxViews.Add(item);
}
return OnlyBoxViews;
}
ViewModel:
public class PartialScreenViewModel
{
public List<PartialView> PartialViewList { get; set; }
public int maxNumberOfViews { get; set; }
}
Result on screen: screenshot
Related
For the following code, for some reason the selection of the radio buttons binds x.MyCapability with -> "on" instead of the label of the button (let's assume the labels of the radio element are *a ,*b and *c):
#foreach (var capability in myList)
{
<label>
<input type="radio" name="MyCapability" SelectedValue="MyCapability" #bind-value="x.MyCapability" />
#capability <text> </text>
</label>
}
how can I link x.MyCapability with a, b or c?
.NetCore 3.1
You are binding in a wrong way, here is the way you can
Your html
<div>Your Capability: #MyCapability</div>
<div>
#foreach (var capability in myList)
{
<div>
<label>#capability.MyCapability</label>
<input type="radio"
name="#capability.MyCapability"
#onchange=#(() => MyCapability = capability.MyCapability)
checked="#(capability.MyCapability==MyCapability)">
</div>
}
</div>
Here is the code behind
#code{
private string MyCapability = "a";
private List<Capabilities> myList = new()
{
new Capabilities()
{
MyCapability = "a"
},
new Capabilities()
{
MyCapability = "b"
},
new Capabilities()
{
MyCapability = "c"
}
};
public class Capabilities
{
public string MyCapability { get; set; }
}
}
When you select any option it will be update in above div
I'm currently programming a modal to add some basic information to print an invoice with that information later on. The code is still messy but as soon as i figure out how to solve my problem, I'm going to smarten up the code a little bit.
I'm currently struggling in creating some input fields that are used to add or remove the items of the invoice. Currently it looks like that:
When I open that modal, I retrieve the OrderSpecifications (that's what I call these lines) from the DB and populate the input fields.
protected override void OnInitialized()
{
specs = nfzContext.OrderSpecifications.Where(x => x.FkOrderNumber == order.Id).ToList();
numberOfSpecLines = nfzContext.OrderSpecifications.Where(x => x.FkOrderNumber == order.Id).Count();
SetupSpeclines();
}
I have 5 input fields predefined, which are only hidden in case there are no specification lines already existing. If i press the + button, I show the a new line.
<div class="card-body">
<div class="form-group">
<div class="row">
<div class="col">
<input class="form-control" type="text" #bind="specification1.ItemName" hidden="#specLine1Disabled" placeholder="Zeile 1" />
</div>
</div>
<div class="row">
<div class="col">
<input class="form-control" type="text" #bind="specification2.ItemName" hidden="#specLine2Disabled" placeholder="Zeile 2" />
</div>
</div>
</div>
</div>
The SetupSpecline method grabs the existing speclines and adds a reference for each to one of the five specification1 ... specification5 variables:
void SetupSpeclines() {
if (numberOfSpecLines <= 1) {
specLine1Disabled = false;
if (numberOfSpecLines == 1) specification1 = specs.ElementAt(0);
numberOfVisibleSpecLines = 1;
}
else if (numberOfSpecLines == 2) {
specLine1Disabled = false;
specLine2Disabled = false;
specification1 = specs.ElementAt(0);
specification2 = specs.ElementAt(1);
numberOfVisibleSpecLines = 2;
}
else if (numberOfSpecLines == 3) {
specLine1Disabled = false;
specLine2Disabled = false;
specLine3Disabled = false;
specification1 = specs.ElementAt(0);
specification2 = specs.ElementAt(1);
specification3 = specs.ElementAt(2);
numberOfVisibleSpecLines = 3;
}
else if (numberOfSpecLines == 4) {
specLine1Disabled = false;
specLine2Disabled = false;
specLine3Disabled = false;
specLine4Disabled = false;
specification1 = specs.ElementAt(0);
specification2 = specs.ElementAt(1);
specification3 = specs.ElementAt(2);
specification4 = specs.ElementAt(3);
numberOfVisibleSpecLines = 4;
}
else if (numberOfSpecLines == 5) {
specLine1Disabled = false;
specLine2Disabled = false;
specLine3Disabled = false;
specLine4Disabled = false;
specLine5Disabled = false;
specification1 = specs.ElementAt(0);
specification2 = specs.ElementAt(1);
specification3 = specs.ElementAt(2);
specification4 = specs.ElementAt(3);
specification5 = specs.ElementAt(4);
numberOfVisibleSpecLines = 5;
}
}
This it the database model for OrderSpecification (ID = primary key):
namespace MyNamespace
{
public class OrderSpecification
{
public OrderSpecification();
public int Id { get; set; }
public int FkOrderNumber { get; set; }
public int SeqId { get; set; }
public string ItemName { get; set; }
public virtual Order FkOrderNumberNavigation { get; set; }
}
}
You can unhide (+) up to five inputs and enter some data. After you press the OK button, the routine starts to check if individual lines have a) altered (=ItemName changed), if new ones were added or if some were removed (=empty input):
void Confirm()
{
List<OrderSpecification> linesToAdd = new List<OrderSpecification>();
List<OrderSpecification> linesToRemove = new List<OrderSpecification>();
if (!string.IsNullOrEmpty(specification1.ItemName))
{
// Check if there is a spec at index 0
if (specs.ElementAtOrDefault(0) != null)
{
specs.ElementAtOrDefault(0).ItemName = specification1.ItemName; // Only itemName has changed
}
else
{ // Add new line
linesToAdd.Add(new OrderSpecification { FkOrderNumber = order.Id, ItemName = specification1.ItemName, SeqId = 1 });
}
}
else if (!string.IsNullOrEmpty(specification1.ItemName) && specs.ElementAtOrDefault(0) != null)
Now, while all that works just fine, I have trouble writing the new speclines to the database. For example, When i run
foreach (var spec in LinesToAdd)
{
nfzContext.Add(spec);
}
nfzContext.SaveChanges();
I get the error message
{"Cannot insert explicit value for identity column in table
'OrderSpecifications' when IDENTITY_INSERT is set to OFF."}
What I assume is that EF Core tries to add the new OrderSpecification with the ID=0, which is the standard value when creating a new OrderSpecification element. I need to tell EF Core to not write the ID as 0 but to let the database set the value by using auto_increment.
And what's odd is, although I have assigned the Primary Key to the ID field, when I scaffold, the key is not set in the modelbuilder:
modelBuilder.Entity<OrderSpecification>(entity =>
{
entity.ToTable("OrderSpecifications", "samnfz");
entity.Property(e => e.Id).HasColumnName("ID");
entity.Property(e => e.FkOrderNumber).HasColumnName("FK_OrderNumber");
entity.Property(e => e.ItemName).IsRequired();
entity.Property(e => e.SeqId).HasColumnName("SeqID");
entity.HasOne(d => d.FkOrderNumberNavigation)
.WithMany(p => p.OrderSpecifications)
.HasForeignKey(d => d.FkOrderNumber)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_OrderSpecifications_Orders");
});
Any idea?
Ugh, I think I have found the error. After analyzing the table structure in the modelbuilder, I recognized that the structure is not the same that I have in my database. So i scaffolded once again and the error is gone. obviously, I used model types that were not current and maybe the primary key was set to another attribute...
I'm using asp.net core, when I pass linq lambda query to view I get this error:
An unhandled exception occurred while processing the request.
InvalidOperationException: The model item passed into
the ViewDataDictionary is of type 'System.Collections.Generic.List`1[<>f__AnonymousType7`1[System.Int64]]',
but this ViewDataDictionary instance
requires a model item of type 'System.Collections.Generic.IEnumerable`1[HRMS.Salaries]'.
This my query:
public async Task<IActionResult> Index()
{
var salary = (from salaries in _context.Salaries select new { salaries.Id });
return View(await salary.ToListAsync());
}
and in the view I use:
#model IEnumerable<HRMS.Salaries>
#foreach (var item in Model)
{
<tr>
<td>#item.Id</td>
</tr>
}
Is there a reason you create an object in your query? If no, try this instead :
public async Task<IActionResult> Index()
{
var salary = (from salaries in _context.Salaries
select salaries.Id
);
return View(await salary.ToListAsync());
}
Then in your view :
#model IEnumerable<int>
#foreach (var item in Model)
{
<tr>
<td>#item</td>
</tr>
}
Else, if you need the object, use in your query :
public async Task<IActionResult> Index()
{
var salary = (from salaries in _context.Salaries
select salaries
);
return View(await salary.ToListAsync());
}
And keep your view the same :
#model IEnumerable<HRMS.Salaries>
#foreach (var item in Model)
{
<tr>
<td>#item.Id</td>
</tr>
}
EDIT : If you want to pass multiple fields to your View, it's better to use a new object. For this, create a class (for exemple, SalaryDetailsViewModel) with the required fields. Then in your controller :
public async Task<IActionResult> Index()
{
var salary = (from salaries in _context.Salaries
select new SalaryDetailsViewModel {
Id = salaries.Id,
Amount = salaries.Amount,
Date = salaries.Date,
JobTitle = salaries.JobTitle.Name }
);
return View(await salary.ToListAsync());
}
Then adjust your View to call the different fields of your custom object, for display purpose, for example :
#model IEnumerable<SalaryDetailsViewModel>
#foreach (var item in Model)
{
<tr>
<td>#item.Id</td>
<td>#item.Amount</td>
<td>#item.Date</td>
<td>#item.JobTitle</td>
</tr>
}
I have an MVC4 registration form that employs two custom remote validators. The first validator checks for email uniqueness, and works properly. The second checks number of uses for a voucher code. It correctly displays a message after entering a voucher code, but it fails to honor the custom remote validation at the point of submission.
In other words, you can enter a voucher code and see the "Cannot use voucher..." message from the remote validator. But you can still submit the form.
This is the abbreviated markup for the form, with just the relevant fields and the submit button. The full form is much larger. The email fields, which use custom validation successfully, are retained in this example for comparison. You can see the RegistrationVoucherCode field and validator near the end of the form.
#using (Html.BeginForm("Index", "Registration", FormMethod.Post))
{
<div class="row">
<div class="col-lg-6 col-md-6 col-xs-6 field_wrapper">
<div class="form_label">#Html.LabelFor(m => m.EmailAddress)</div>
<div class="form_field">#Html.TextBoxFor(m => m.EmailAddress)</div>
<div class="form_validator">#Html.ValidationMessageFor(m => m.EmailAddress)</div>
</div>
<div class="col-lg-6 col-md-6 col-xs-6 field_wrapper">
<div class="form_label">Confirm Email</div>
<div class="form_field">#Html.TextBoxFor(m => m.ConfirmEmail)</div>
<div class="form_validator">#Html.ValidationMessageFor(m => m.ConfirmEmail)</div>
</div>
</div>
<div class="row">
<div class="col-lg-6 col-md-6 col-xs-6 field_wrapper">
<div class="form_label">#Html.LabelFor(m => m.RegistrationVoucherCode)</div>
#{
string displayVoucherCode = Model.RegistrationVoucherCode.ToString();
if (Model.RegistrationVoucherCode == 0)
{
displayVoucherCode = string.Empty;
}
}
<div class="form_field">#Html.TextBoxFor(m => m.RegistrationVoucherCode, new { Value = displayVoucherCode, maxlength = 7 })</div>
<div class="form_validator">#Html.ValidationMessageFor(m => m.RegistrationVoucherCode)</div>
</div>
<div class="col-lg-6 col-md-6 col-xs-6 field_wrapper">
</div>
</div>
<div class="row">
<div class="col-xs-12">
<input type="submit" id="submitForm" value="Next" class="standard_button right_button" />
</div>
</div>
}
This is related code from my ProfileModel. The full model is much larger, so only relevant code is presented here. At the end of this you can see RegistrationVoucherCode.
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
namespace SW.CEA.WebSite.Models.Registration
{
public class ProfileModel
{
public ProfileModel()
{
}
public Profile Profile { get; set; }
[Required(ErrorMessage = "Confirm Email is required.")]
[Display(Name = "Confirm Email")]
[StringLength(128)]
[RegularExpression(#"\w+([-+.']\w+)*#\w+([-.]\w+)*\.\w+([-.]\w+)*", ErrorMessage = "Confirm Email Address is Not Valid")]
[System.Web.Mvc.Compare("EmailAddress", ErrorMessage = "Email addresses do not match..")]
public string ConfirmEmail
{
get
{
return Profile.ConfirmEmail;
}
set
{
Profile.ConfirmEmail = value;
}
}
[Required(ErrorMessage = "Email Address is required.")]
[Display(Name = "Email")]
[StringLength(128)]
[Remote("ValidateEmailUniqueness", "Registration")]
[RegularExpression(#"\w+([-+.']\w+)*#\w+([-.]\w+)*\.\w+([-.]\w+)*", ErrorMessage = "Email Address is Not Valid")]
public string EmailAddress
{
get
{
return Profile.EmailAddress;
}
set
{
Profile.EmailAddress = value;
}
}
[Required(ErrorMessage = "Order Code is required.")]
[Display(Name = "Order Code")]
[Remote("ValidateVoucherCode", "Registration")]
public int RegistrationVoucherCode
{
get
{
return Profile.RegistrationVoucherCode;
}
set
{
Profile.RegistrationVoucherCode = value;
}
}
}
}
And these are custom validators from my RegistrationController. Again, email address validators appear here for comparison. My problem is with enforcing the ValidateVoucherCode custom validator at the point of form submission.
private bool IsEmailUnique(string EmailAddress)
{
var profile = ProfileRepository.GetProfile(EmailAddress);
return (profile == null);
}
[HttpGet]
public JsonResult ValidateEmailUniqueness(string EmailAddress)
{
if (!IsEmailUnique(EmailAddress))
{
return Json("Error, email address is already registered, please sign in.", JsonRequestBehavior.AllowGet);
}
return Json(true, JsonRequestBehavior.AllowGet);
}
[HttpGet]
public JsonResult ValidateVoucherCode(int RegistrationVoucherCode)
{
var voucher = VoucherRepository.GetVoucherWithProfiles(RegistrationVoucherCode);
if (voucher == null)
{
return Json("Invalid Order Code", JsonRequestBehavior.AllowGet);
}
if (voucher.Profiles.Count >= Settings.Default.MaxVoucherUses)
{
return Json("Cannot user voucher, will exceed maximum number of voucher uses.", JsonRequestBehavior.AllowGet);
}
return Json(true, JsonRequestBehavior.AllowGet);
}
The message, "Cannot user voucher, will exceed maximum number of voucher uses," will successfully appear on the client in this ValidationMessageFor when an overused validation code is entered. This again is from the form.
#Html.TextBoxFor(m => m.RegistrationVoucherCode, new { Value = displayVoucherCode, maxlength = 7 })
#Html.ValidationMessageFor(m => m.RegistrationVoucherCode)
Upon tabbing off the form field, debugger shows this remote validator being hit.
[HttpGet]
public JsonResult ValidateVoucherCode(int RegistrationVoucherCode)
So the ValidateVoucherCode custom validator is doing part of it's job. It's showing the "Cannot use voucher..." message when I tab off the field. But it doesn't prevent the form from being submitted. By contrast, the unique email address validator on the same form will prevent form submission. I need the RegistrationVoucherCode validator to operate in the same manner. Thanks for your help.
The solution was to replace jquery-2.1.0.min.js with https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js.
The scripts that my form presently uses are:
https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js
jquery.validate.min.js
jquery.validate.unobtrusive.min.js
I'm having troubles with the selectedValue option for SelectedItems, for some reason it won't select the item despite it being in the list...
My Controller:
public ActionResult CreateTransformer(string edit)
{
var equipment = GenIDQueries.FindEquipment(edit);
ViewData["Feeder"] = new SelectList(GenIDQueries.GetFeeders(equipment.OpsCentre.ToString()),
"CircuitID",
"CircuitDescription",
equipment.Feeder);
return View(equipment);
}
equipment.Feeder is of type Integer.
My View:
<p>
<b><%=Html.LabelFor(m=>m.Feeder) %>:</b><font color="red">*</font>
<%=Html.DropDownListFor(m=>m.Feeder, ViewData["Feeder"] as SelectList, "") %>
<%= Html.ValidationMessageFor(m => m.Feeder)%>
</p>
My GenIDQueries.GetFeeders:
public static IEnumerable<Circuit> GetFeeders(string distNo)
{
int distNoNumber;
if ( int.TryParse(distNo, out distNoNumber))
{
return ActiveRecordLinq.AsQueryable<Circuit>()
.Where(x => x.DistrictCircuitRelations
.Any(y => y.District.DistrictNo == distNoNumber))
.OrderBy(x => x.CircuitDescription)
.Select(x => new Circuit
{
CircuitID = x.CircuitID,
CircuitDescription = x.CircuitDescription
});
}
return new List<Circuit>();
}
I have verified that the element I wanted to select is indeed returned by GenIDQueries, however when the page loads it never selects that option, in the HTML source code, the item is not selected either.
Thanks for the help!
When setting the selected value you should set it to the selected CircuitID and not the Feeder object.
Why are you using this Plague of ViewData? I consider ViewData as a virus started at Microsoft open space laboratories and spread through internet blog posts and articles.
View models are the way to go in ASP.NET MVC:
Model:
public class MyViewModel
{
public string SelectedValue { get; set; }
public IEnumerable<SelectListItem> Items { get; set; }
}
Controller:
public ActionResult CreateTransformer(string edit)
{
var equipment = GenIDQueries.FindEquipment(edit);
var items = GenIDQueries.GetFeeders(equipment.OpsCentre.ToString());
var model = new MyViewModel
{
SelectedValue = equipement.CircuitID,
Items = new SelectList(items, "CircuitID", "CircuitDescription")
};
return View(model);
}
View:
<%= Html.DropDownListFor(m => m.CircuitID, Model.Items, "") %>
<%= Html.ValidationMessageFor(m => m.CircuitID) %>