I am trying to validate if my dropdownlist's item already exists in the DB. It should set Model.IsValid to false, but it pass true all the time, looks like validator just doesn't get called
DropDownList code:
</td>
</tr>
<tr>
<td> #Html.Label("VendorId ") </td>
<td> #Html.DropDownListFor(x => x.id, new SelectList(Model.validatingVendors, "VendorKey", "VerndorID", Model.id)) #Html.ValidationMessageFor(x=>x.validatingVendors.FirstOrDefault(s=>s.VendorKey == x.id).VerndorID)</td>
</tr>
My custom Validator Class
public class VendorAttribute : ValidationAttribute
{
DataManager manager = new DataManager();
public override bool IsValid(object value)
{
var stringValue = Convert.ToString(value, CultureInfo.CurrentCulture);
if (value == null)
{
return true;
}
if ((value is string) && string.IsNullOrEmpty((string)value))
{
return true;
}
var name = value.ToString().ToLower();
// fake a database lookup and bring back two widgets
return (manager.VendorAllreadyExcists(stringValue));
}
public override string FormatErrorMessage(string name)
{
return name;
}
}
My Model class
public class VelidationVendorViewModel
{
public int VendorKey { get; set; }
[Required]
[Vendor(ErrorMessage = "Vendor Allerede eksister")]
public string VerndorID { get; set; }
public int LatestSalesCWeek { get; set; }
public bool Active { get; set; }
}
My parentViewModel
public class ParentViewModel
{
public List<FactRefIdFileFormatIdViewModel> model { get; set; }
public RefrenceDataViewModel refModel { get; set; }
public List<MetaFileFormatsViewModel> metaModel { get; set; }
public int id { get; set; }
public VelidationVendorViewModel vendorId { get; set; }
public IEnumerable<VelidationVendorViewModel> validatingVendors { get; set; }
}
SOLUTION
Just got it solved
[Required]
[Vendor(ErrorMessage = "Vendor Allerede eksister")]
public string VerndorID { get; set; }
on my viewmodel is wrong since i haveto move my custom validation to my id inside of my ParentViewModel so it looks like this:
public List<FactRefIdFileFormatIdViewModel> model { get; set; }
public RefrenceDataViewModel refModel { get; set; }
public List<MetaFileFormatsViewModel> metaModel { get; set; }
[Required]
[Vendor(ErrorMessage = "Vendor Allerede eksister")]
public int id { get; set; }
public VelidationVendorViewModel vendorId { get; set; }
public IEnumerable<VelidationVendorViewModel> validatingVendors { get; set; }
And last but not least my validation have to call ID instead of vendorId of specific item in a list like this :
#Html.ValidationMessageFor(x=>x.Id)
have you tried debugging and see for yourself if validator get called ?
from your method name it seems you are using wring logic :
return (manager.VendorAllreadyExcists(stringValue));
return TRUE if DO EXISTS, is that what you want? dont you want to return TRUE if it DOES NOT EXISTS ? (assuming from the fact, that you return TRUE for cases when name is "invalid" - not testable against DB)
Just got it solved
[Required]
[Vendor(ErrorMessage = "Vendor Allerede eksister")]
public string VerndorID { get; set; }
on my viewmodel is wrong since i haveto move my custom validation to my id inside of my ParentViewModel so it looks like this:
public List<FactRefIdFileFormatIdViewModel> model { get; set; }
public RefrenceDataViewModel refModel { get; set; }
public List<MetaFileFormatsViewModel> metaModel { get; set; }
[Required]
[Vendor(ErrorMessage = "Vendor Allerede eksister")]
public int id { get; set; }
public VelidationVendorViewModel vendorId { get; set; }
public IEnumerable<VelidationVendorViewModel> validatingVendors { get; set; }
And last but not least my validation have to call ID instead of vendorId of specific item in a list like this :
#Html.ValidationMessageFor(x=>x.Id)
Related
I have customer model
public class Customer
{
public Customer()
{
this.SystemValues = new HashSet<SystemValue>();
}
public string Name { get; set; }
public Nullable<System.Guid> GUID { get; set; }
public int Id { get; set; }
public virtual ICollection<SystemValue> SystemValues { get; set; }
}
and systemValue model
public class SystemValue
{
public int CustomerId { get; set; }
public int SystemValueId { get; set; }
public Nullable<int> SystemValueCategoryId { get; set; }
public string SystemValueType { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string TextValue { get; set; }
public Nullable<int> IntValue { get; set; }
public Nullable<double> FloatValue { get; set; }
public byte[] BlobValue { get; set; }
public Nullable<System.DateTime> DateTimeValue { get; set; }
public Nullable<bool> BooleanValue { get; set; }
public Nullable<int> LookupValueId { get; set; }
public Nullable<int> LookupValueGroupId { get; set; }
public Nullable<bool> IsReadonly { get; set; }
public bool IsHidden { get; set; }
public int Id { get; set; }
public virtual Customer Customers { get; set; }
}
in which way I could show a link in CustomerView(CustomersController) foreach customer that redirect to the SystemValuesView(SystemValuesController) with related to this customer SystemValues?
I found out one way - redirect to this controller's action with parameter.
public ActionResult ViewSystemValues(int? id)
{
return RedirectToAction("Index", "SystemValues", new {id});
}
But I'm sure there must be smarter way.
#for(int i = 0; i < Model.yourcustomerlist.Count(); i++)
{
<tr>
<td>
<a class="btn btn-primary" href="#Url.Action("Index", "SystemValues", new { id = Model.yourcustomerlist[i].CustomerId })">
<b>Go to system values</b>
</a>
</td>
</tr>
}
I hope I understood you correctly.
This code should go in the view. The view should be strongly typed to a model.
Code is if you want a button that redirects to the index view of the SystemValues controller, with the CustomerId as input. You should change "yourcustomerlist" to the list containing the customer information. If it's not part of a table, remove the table-related tags (<td> and <tr>).
My Model:
public ECmain()
{
this.Notes = new Collection<Notes>();
}
public int ID { get; set; }
public string Auth { get; set; }
public string KeyWords { get; set; }
public string Description { get; set; }
public string URL { get; set; }
public string Category { get; set; }
public string SubCategory { get; set; }
public string Title { get; set; }
public string Live { get; set; }
public virtual ICollection<Notes> Notes { get; set; }
public virtual ICollection<Email> Email { get; set; }
}
public class MyViewModel
{
public IQueryable<Notes> NotesList { get; set; }
public IQueryable<ECmain> ECmainList { get; set; }
public int ECmain.ID { get; set; }
public IQueryable<Email> EmailList { get; set; }
}
My Controller:
// GET: ECmain/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var viewModel = new MyViewModel
{
ECmainList = from m in db.ECmain.Take(10)
where m.ID == id
select m,
NotesList = from n in db.Notes
where n.ECmainID ==id
select n,
EmailList = from e in db.Email
where e.ECmainID ==id
select e
};
// viewModel.NotesList = new
if (viewModel == null)
{
return HttpNotFound();
}
return View(viewModel);
}
My Edit View:
#model EditSuite.Models.MyViewModel
#using (Html.BeginForm())
{
#Html.HiddenFor(model => model.ID )
I want to access the ECmainList.ID The error is
Compiler Error Message: CS1061: 'EditSuite.Models.MyViewModel' does not contain a definition for 'ID'
I tried
#Html.HiddenFor(model => model.ECmainListID.ID )
and
#Html.HiddenFor(Model.model.ECmainListID.ID )
Neither one worked.
It seems pretty obvious from the compiler message:
Compiler Error Message: CS1061: 'EditSuite.Models.MyViewModel' does not contain a definition for 'ID'
So where on the following model is the ID?:
public class MyViewModel
{
public IQueryable<Notes> NotesList { get; set; }
public IQueryable<ECmain> ECmainList { get; set; }
public IQueryable<Email> EmailList { get; set; }
// there is no: public int ID { get; set; } ?
}
I want to access the ECmainList.ID
However, per your model the ECmainList is a IQueryable<ECmain> and the IQueryable<T> also does not have a public property or field called ID. How can you add an editor for a ID of a list of objects? You'd need to loop through the list and have multiple ID fields.
Relatively new to MVC and can't figure out how to pass data from multiple models into a single view. I know I need to use a view model, but I can't figure out what to do in the controller.
Models:
public class Child
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ChartNumber { get; set; }
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
public string LastName { get; set; }
public string City { get; set; }
public string State { get; set; }
[Display(Name = "Zip Code")]
public int ZipCode { get; set; }
public string Ethnicity { get; set; }
public string Referral { get; set; }
[Display(Name = "Recommended Re-evaluation")]
public bool ReEval { get; set; }
[Display(Name = "Hearing Aid Candidate")]
public bool HaCandidate { get; set; }
[Display(Name = "Fit With Hearing Aid")]
public bool FitHa { get; set; }
public virtual List<ChildEval> ChildEvals { get; set; }
}
public class ChildEval
{
[Key]
public int ChildEvalId { get; set; }
public DateTime Date { get; set; }
public int PtaRight { get; set; }
public int PtaLeft { get; set; }
public int UnaidedSiiRight { get; set; }
public int UnaidedSiiLeft { get; set; }
public int AidedSiiRight { get; set; }
public int AidedSiiLeft { get; set; }
public int ChartNumber { get; set; }
public virtual Child Child { get; set; }
}
}
DbContext
public class UnitedContext : DbContext
{
public UnitedContext() : base("name=UnitedContext")
{
}
public System.Data.Entity.DbSet<United.Models.Child> Children { get; set; }
public System.Data.Entity.DbSet<United.Models.ChildEval> ChildEvals { get; set; }
}
ViewModel:
public class ChildViewModel
{
public class Child
{
public string FirstName { get; set; }
}
public class ChildEval
{
public int PtaRight { get; set; }
}
}
ViewModelController? :
public class ViewModelController : Controller
{
//
// GET: /ViewModel/
public ActionResult Index()
{
return View();
}
}
}
I'm stuck on how to create the controller for the viewmodel and how to actually get the data into the view. Any help would be greatly appreciated!
Don't have a controller called ViewModelController. Controller is the handler between database and the view. Therefore the name of the controller should tell the programmer what kind of data the controller is controlling. By default, it also indicates the subsite you are in your web application ( ViewModelController would yield http://mysite/ViewModel/ ).
Since you are handling children, I'm calling it ChildrenController for now.
Generally a good idea is to wrap your 2 models into one viewmodel and work with that. In this case Model != ViewModel, model is the database model of the entity while ViewModel is the one that's passed to/from the view.
public class Child
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class SomeOtherModel
{
public int ID { get; set; }
public int SomeInteger { get; set; }
public int SomeOtherInteger { get; set; }
}
public class ChildViewModel
{
public Child Child { get; set; }
public SomeOtherModel SomeOtherModel { get; set; }
public ChildViewModel(Child child, SomeOtherModel s)
{
Child = child;
SomeOtherModel = s;
}
}
In your controller
public class ChildrenController : Controller
{
//
// GET: /Children/
public ActionResult Index()
{
Child child = /*Fetch the child from database*/;
SomeOtherModel someOther = = /*Fetch something else from database*/;
ChildViewModel model = new ChildViewModel(child,someOther);
return View(model);
}
}
View:
#model ChildViewModel
#Html.EditorFor(model => model.Child.FirstName)
#Html.EditorFor(model => model.Child.LastName)
Should T be a for example Customer or CustomerViewModel ?
The annotations bound to Mvc namespace are on the ListViewModel so actually I could pass the Customer object. What do you think?
public class ListViewModel<T>
{
[Required(ErrorMessage="No item selected.")]
public int[] SelectedIds { get; set; }
public IEnumerable<T> DisplayList { get; set; }
}
UPDATE
[HttpGet]
public ActionResult Open()
{
IEnumerable<Testplan> testplans = _testplanDataProvider.GetTestplans();
OpenTestplanListViewModel viewModel = new OpenTestplanListViewModel(testplans);
return PartialView(viewModel);
}
public class OpenTestplanListViewModel
{
public OpenTestplanListViewModel(IEnumerable<Testplan> testplans)
{
var testplanViewModels = testplans.Select(t => new TestplanViewModel
{
Name = string.Format("{0}-{1}-{2}-{3}", t.Release.Name, t.Template.Name, t.CreatedAt, t.CreatedBy),
TestplanId = t.TestplanId,
});
DisplayList = testplanViewModels;
}
[Required(ErrorMessage = "No item selected.")]
public int[] SelectedIds { get; set; }
public string Name { get; set; }
public IEnumerable<TestplanViewModel> DisplayList { get; private set; }
}
public class TestplanViewModel
{
public int TestplanId { get; set; }
public string Name { get; set; }
}
public class Testplan
{
public int TestplanId { get; set; }
public int TemplateId { get; set; }
public int ReleaseId { get; set; }
public string CreatedBy { get; set; }
public DateTime CreatedAt { get; set; }
public Template Template { get; set; }
public Release Release { get; set; }
}
T should ideally be a view model. Having a view model referencing domain models is some kind of a hybrid view model, not a real one. But if you think that in this specific case the domain model will be exactly the same as the view model then you could keep it as well.
this is my model
public class Post
{
public long PostID { get; set; }
[Required]
[MaxLength(255)]
public string Title { get; set; }
}
public class Tag
{
public long TagID { get; set; }
[Required]
[Display(Name = "Tag Name")]
[MaxLength(30)]
public string TagName { get; set; }
public bool IsActive { get; set; }
}
public class TagPost
{
public long TagPostID { get; set; }
public long PostID { get; set; }
public long TagID { get; set; }
[ForeignKey("PostID")]
public virtual Post Posts { get; set; }
[ForeignKey("TagID")]
public virtual Tag Tags { get; set; }
}
1) Is this the right many to many configuration in EF 4.1 without mentioning the modelbinder for many to many.
2) if i have completed the many to many configuration using dataannotation why the data is not inserting in tagpost .
public void InsertPostQuestion(Post post,List<string> tags)
{
context.Posts.Add(post);
foreach (string tag in tags)
{
Tag tagr = new Tag();
tagr.TagName = tag;
tagr.IsActive = true;
context.Tags.Add(tagr);
}
context.SaveChanges();
}
3) I do have to define modelbinder to have many to many inserts or delete or update?
modelBuilder.Entity<Post>().
HasMany(c => c.Tags).
WithMany(p => p.Posts).
Map(
m =>
{
m.MapLeftKey("PostID");
m.MapRightKey("TagID");
m.ToTable("TagPost");
});
Change your models to this:
public class Post
{
public long PostID { get; set; }
[Required]
[MaxLength(255)]
public string Title { get; set; }
public bool IsActive { get; set; }
public virtual List<Tag> Tags { get; set; }
}
public class Tag
{
public long TagID { get; set; }
[Required]
[Display(Name = "Tag Name")]
[MaxLength(30)]
public string TagName { get; set; }
public bool IsActive { get; set; }
public virtual List<Post> Posts { get; set; }
}
and then save like so:
public void InsertPostQuestion(Post post,List<string> tags)
{
context.Posts.Add(post);
foreach (string tag in tags)
{
// TODO: If tag has a unique index on TagName, see if it exists first
Tag tagr = new Tag();
tagr.TagName = tag;
tagr.IsActive = true;
context.Tags.Add(tagr);
post.Tags.Add(tagr);
}
context.SaveChanges();
}
EF will create the intermediate table in the db and populate it nicely automatically.