Partial views inside my asp.net mvc will ignore all the model data annotations - asp.net

I have the following action method which render the following partial view:-
public ActionResult CreateVMNetwork(int vmid)
{
AssignIps vmips = new AssignIps()
{
TechnologyIP = new TechnologyIP() { TechnologyID = vmid},
IsTMSIPUnique = true,
IsTMSMACUnique = true
};
return PartialView("_CreateNetworkInfo",vmips);
}
The partial view is :-
model TMS.ViewModels.AssignIps
#if (this.ViewContext.FormContext == null)
{
this.ViewContext.FormContext = new FormContext();
}
#using (Ajax.BeginForm("CreateVMNetwork", "VirtualMachine", new AjaxOptions
{
InsertionMode = InsertionMode.InsertAfter,
UpdateTargetId = "networktable",
LoadingElementId = "loadingimag",
HttpMethod= "POST",
OnSuccess="submitform"
}))
{
#Html.ValidationSummary(true)
#Html.HiddenFor(model=>model.TechnologyIP.TechnologyID)
#Html.AntiForgeryToken()
<div>
<span class="f">IP Address</span>
#Html.EditorFor(model => model.TechnologyIP.IPAddress)
#Html.ValidationMessageFor(model => model.TechnologyIP.IPAddress)
<input type="CheckBox" name="IsTMSIPUnique" value="true" #(Html.Raw(Model.IsTMSMACUnique ? "checked=\"checked\"" : "")) /> IP Unique. |
<span class="f"> MAC Address</span>
#Html.EditorFor(model => model.TechnologyIP.MACAddress)
#Html.ValidationMessageFor(model => model.TechnologyIP.MACAddress)
<input type="CheckBox" name="IsTMSMACUnique" value="true" #(Html.Raw(Model.IsTMSMACUnique ? "checked=\"checked\"" : "")) /> MAC Unique.
</div>
<input type="submit" value="Save" class="btn btn-primary"/>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
but all the data annotation on the view model will not fire on the partial view , the AssignIps view model class is :-
namespace TMS.ViewModels
{
public class AssignIps
{
public TechnologyIP TechnologyIP { get; set; }
public bool IsTMSIPUnique { get; set; }
public bool IsTMSMACUnique { get; set; }
}
}
and he TechnologyIP model class is :-
namespace TMS.Models
{
[MetadataType(typeof(TechnologyIP_Validation))]
public partial class TechnologyIP
{}}
namespace TMS.Models
{
public class TechnologyIP_Validation
{
[Required]
public string IPAddress { get; set; }
but the [Required] data annotation on the TechnologyIP model, will not fire on the partial view,, can anyone adovce please?
Thanks.

Sections defined in your layout view don't get populated when using PartialViewResult, so the unobtrusive validation scripts are not being added.
You can test this by creating an action on your controller that just returns a partial view, and then call this via $.get() (using jQuery, obviously). If you use console.log(), you can inspect the result in Firebug. You could also use something like Fiddler; regardless, if you look at the HTML returned you will not see the script references anywhere.

Exactly, a wrong practice is to have:
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
in the partial view, try to do it just putting
#Scripts.Render("~/bundles/jqueryval")
and it should work!

Related

editor template return null value

I have created an editor template base on this article ASP.NET MVC: Annotated for Input by Dino Esposito
Everything works fine until i press the submit button. I find out that my POST function return model is NULL, its like the model is not bind to the view. I have been trying all trick that I know and I found from the internet but I still can't fix it.
This is my controller
// GET: /Asset/New
public ActionResult New()
{
ViewBag.typeID = new SelectList(db.Ref_Asset_Types, "ID", "name");
return View(new AssetViewModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult New(AssetViewModel vm)
// vm.asset should contain new value but currently return null
{
if (ModelState.IsValid)
{
db.Assets.Add(vm.asset);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.typeID = new SelectList(db.Ref_Asset_Types, "ID", "name", vm.asset.typeID);
return View("New", vm);
}
this is my view
#using (Html.BeginForm("New","Asset","POST")) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.EditorFor(m=>m.asset, "InputTemplate" )
// note : the code works if i don't use my own template ==> #Html.EditorFor(m=>m.asset)
<div class="form-actions btn pull-right">
#Html.ActionLink("Back to List", "Index", null, new { #class = "btn btn-sm"})
<button type="reset" class="btn btn-sm" value="Index">
Reset
</button>
<button type="submit" class="btn btn-sm btn-success">
<i class="glyphicon glyphicon-plus"></i>
Tambah
</button>
</div>
}
and this is my InputTemplate
#inherits System.Web.Mvc.WebViewPage
#if (Model == null)
{
<span>#ViewData.ModelMetadata.NullDisplayText</span>
}
else
{
foreach (var prop in ViewData
.ModelMetadata
.Properties
.Where(pm => pm.ShowForDisplay && !ViewData.TemplateInfo.Visited(pm)))
{
if (prop.DisplayName != null) { // only display prop not of ComplexType
// note : using bootstrap for css styling
<div class="form-group col-xs-6">
<label class="col-xs-4 control-label text-right">
<span style="color:red"> #(prop.IsRequired ? "*" : "") </span>
<span>#prop.GetDisplayName()</span>
</label>
<div class="col-xs-8">
#if(prop.IsReadOnly)
{
<span class="readonly-field">#Html.Display(prop.PropertyName)</span>
}
else if (prop.TemplateHint == "DropDown")
{
<span>#Html.DropDownList(prop.PropertyName,(IEnumerable<SelectListItem>) ViewData[prop.PropertyName], new { #class = "form-control" })</span>
<span>#Html.ValidationMessage(prop.PropertyName)</span>
}
else
{
<div class="editor-field">
<span>#Html.Editor(prop.PropertyName, new { #class = "text-box single-line form-control" })</span>
<span>#Html.ValidationMessage(prop.PropertyName, new { #class = "label-danger" } )</span>
</div>
}
</div>
</div>
} // if
} // foreach
}
This is my viewmodel
using System;
using SIGMA.Models;
namespace SIGMA.ViewModels
{
public class AssetViewModel
{
public AssetViewModel()
{
asset = new Asset();
}
public Asset asset { get; set; }
}
}
This is my model
public class Asset
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
[HiddenInput(DisplayValue = false)]
public int ID { get; set; }
[DisplayName("No. Siri")]
[StringLength(45)]
public string serial_num { get; set; }
[DisplayName("Model")]
[Required(ErrorMessage = "Model perlu diisi!")]
[StringLength(45)]
public string model { get; set; }
[DisplayName("Harga Seunit")]
[RegularExpression(#"^\d{0,6}(\.\d{2})?$", ErrorMessage = "Sila gunakan format harga yang betul.")]
public float? unit_cost { get; set; }
[UIHint("DropDown")]
[DisplayName("Jenis Aset")]
[Required(ErrorMessage = "Jenis aset perlu dipilih!")]
[DisplayFormat(NullDisplayText = "Belum didaftar")]
public int? typeID { get; set; }
public virtual Ref_Asset_Type type { get; set; }
}
Sorry guys for the trouble.. i think i solve it.
My biggest mistake is using reserved word 'model' and 'type' as my property name. This some how cause problem to asp.net in interpreting my model using the user define editor template.
Once I change my property name - model to model_name and type to asset_type, i can see the my entry in my return model already.
Thanks to all
.... spends the whole day and night for this silly mistake but the lesson learn is worth it

Addition of two numbers in MVC

I am trying to add two numbers in MVC.
My requirement is "I have 2 text boxes in View from which I have to retrieve data to controller"
View :
#using (Html.BeginForm("Addition", "Addition", FormMethod.Post))
{
<input id="Text1" type="text" value=#ViewBag.a name="firstNum" />
<input id="Text2" type="text" value=#ViewBag.b name="secondNum" />
<input id="Text3" type="text" value=#ViewBag.result />
<input type="submit" value="Submit" />
}
Controller Name : Addition
Action Name: Addition
[HttpPost]
public ActionResult Addition(FormCollection fc)
{
string[] keyss = fc.AllKeys;
ViewBag.a = fc.Keys[0];
ViewBag.b = fc.Keys[1];
ViewBag.total = ViewBag.a + ViewBag.b;
return View();
}
Now, from this form collection I want to retrieve values of textboxes.
Thanks.
One of the powers of MVC is the model binder - which you are completely ignoring here. Create a view model to match the expected content of your view
public class AdditionViewModel
{
public int A { get; set; }
public int B { get; set; }
public int Result { get; set; }
}
Use this as the expected parameter in your action
[HttpPost]
public ActionResult Addition(AdditionViewModel model)
{
model.Result = model.A + model.B;
return View(model);
}
Then finally in your view
#model AdditionViewModel
#using (Html.BeginForm("Addition", "Addition", FormMethod.Post))
{
#Html.EditorFor(x => x.A)
#Html.EditorFor(x => x.B)
#Html.DisplayFor(x => x.Result)
<input type="submit" value="Submit" />
}
Assuming you get the data in to ur controller , afterwards you just add Addition view and use
#ViewBag.total simple or you also can use viewdata or tempdata in case if u required .
The better way is
[HttpPost]
public ActionResult Addition(int firstNum, int secondNum )
{
ViewBag.Result=firstNum+secondNum;
return View();
}
Make sure you are doing a Numeric validation at client side

Required Meta Data Validation is not working on Partial Views

I have the following Main view inside my asp.net mvc-4:-
#model TMS.ViewModels.SwitchJoin
#Ajax.ActionLink("Add Port Info", "CreatePort","Switch",
new { switchid = Model.Switch.SwitchID },
new AjaxOptions {
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "AssignPort" ,
LoadingElementId = "progress"
}
)
</p>
//code goes here
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
And the following two partial view;-
#model TMS.Models.TMSSwitchPort
#using (Ajax.BeginForm("CreatePort", "Switch", new AjaxOptions
{
InsertionMode = InsertionMode.InsertAfter,
UpdateTargetId = "Porttable",
LoadingElementId = "loadingimag",
HttpMethod= "POST",
OnSuccess="submitform"
}))
{
#Html.ValidationSummary(true)
#Html.HiddenFor(model=>model.SwitchID)
#Html.Partial("_CreateOrEditPort", Model)
<input type="submit" value="Save" class="btn btn-primary"/>
}
&&&
#model TMS.Models.TMSSwitchPort
#Html.AntiForgeryToken()
<div>
<span class="f">Device Tag</span>
#Html.TextBoxFor(model => model.Technology.Tag)
#Html.ValidationMessageFor(model => model.Technology.Tag)
<span class="f"> Port Number</span>
#Html.TextBoxFor(model => model.PortNumber)
#Html.ValidationMessageFor(model => model.PortNumber)
</div>
And I have the following Meta type Model class:-
public class TMSSwitchPort_Validation
{
[Required]
public string PortNumber { get; set; }
}
}
But on the __CreateOrEditPort partial view the required validation will not fire? Can anyone advice please?
Answer #develiper10214 is right but you also write about MetaType model class. I quess, are you want MetadataType class for your class.
If yes. You need to watch a few rules.
Your class and Metadata class need to in the same namespace (if you use this for metadata in EF database first and partial model class).
You need to "tell" your class than you use a metadata class.
Fields in class and metadata class need to be the same.
Example:
namespace TMS.Models
{
public partial class TMSSwitchPort
{
public string PortNumber { get; set; }
}
}
Another class:
namespace TMS.Models
{
[MetadataType(typeof(TMSSwitchPortMetadata))]
public partial class TMSSwitchPort
{
//Nothing
}
public class TMSSwitchPortMetadata
{
[Required]
public string PortNumber { get; set; }
}
}

ASP.NET MVC3: Interaction between Partial View and Main View

I have a partial view for contact. Currently the index view shows this partial view for contact details. There is a save button inside the partial view to save the edited data. There is a validation for age while saving the edited data. This much is working fine.
Whenever user edit age and save it, I need to show the corresponding horoscope prediction on the main view. How do we achieve it?
public class ContactEntity
{
public int ContactID { get; set; }
public string ContactName { get; set; }
[Range(18, 50, ErrorMessage = "Must be between 18 and 50")]
public int ContactAge { get; set; }
}
public class AgeHoroscope
{
public int Age { get; set; }
public string HoroscopePrediction { get; set; }
}
//Home Controller
namespace MYContactEditPartialViewTEST.Controllers
{
public class HomeController : Controller
{
List<AgeHoroscope> horoList = new List<AgeHoroscope>()
{
new AgeHoroscope{Age=16,HoroscopePrediction="You are confused"},
new AgeHoroscope{Age=26,HoroscopePrediction="You are very brilliant"},
new AgeHoroscope{Age=27,HoroscopePrediction="You are practical"}
};
public ActionResult Index()
{
AgeHoroscope selectedHoro = horoList[1];
return View(selectedHoro);
}
}
}
//Contact Controller
namespace MYContactEditPartialViewTEST.Controllers
{
public class ContactController : Controller
{
public PartialViewResult MyContactDetailEdit()
{
Thread.Sleep(500);
return PartialView(GetContact());
}
[HttpPost]
public PartialViewResult MyContactDetailEdit(string conatcclick)
{
//Save to database
Thread.Sleep(500);
return PartialView(GetContact());
}
private ContactEntity GetContact()
{
ContactEntity contactEntity = new ContactEntity();
contactEntity.ContactID = 1;
contactEntity.ContactName = "Lijo";
contactEntity.ContactAge = 26;
return contactEntity;
}
}
}
//Index.cshtml
#model MYContactEditPartialViewTEST.AgeHoroscope
#{
ViewBag.Title = "Index";
}
<script src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"> </script>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<h2>
Index</h2>
<div>
<a>Your age is <b>#Html.DisplayFor(x => x.Age) </b>and the prediction is <b>" #Html.DisplayFor(x => x.HoroscopePrediction)
" </b></a>
<br />
</div>
<div style="border: 3px solid Teal">
#Html.Action("MyContactDetailEdit", "contact")
</div>
// MyContactDetailEdit.cshtml
#model MYContactEditPartialViewTEST.ContactEntity
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<h3>MyContactDetailEdit PARTIAL</h3>
<div>
#Html.HiddenFor(x => x.ContactID)
<br />
<div style="font-weight:bold">
Name:
<br />
</div>
#Html.DisplayFor(x => x.ContactName)
<br />
<br />
<div style="font-weight:bold">
Age
<br />
</div>
#Html.EditorFor(x => x.ContactAge)
#Html.ValidationMessageFor(model => model.ContactAge)
<br />
<br />
</div>
<input type="submit" id="saveButton" value="Save" />
}
READING
ASP.Net MVC Passing multiple parameters to a view
ASP.Net MVC 3 RC2, Partial Views Form Handling
I would like just use jQuery to do ajax post and then change the parent view client side directly
you'll need to create a new ViewModel to do this. This ViewModel (IndexViewModel.cs) would look something like this (I'm guessing at this):
public class IndexViewModel
{
public int ContactID { get; set; }
public string ContactName { get; set; }
public int ContactAge { get; set; }
public string HoroscopePrediction { get; set; }
}
you'd then use it in your controller index action (and view):
#model MYContactEditPartialViewTEST.IndexViewModel
the idea being that you'd populate the HoroscopePrediction in a join between ContactEntity and AgeHoroscope (or via Linq etc) and thus show each line in the index as a complete object (showing contact and horoscope).
As data is posted to "HomeController" and "Index" action, so changes are reflected when you change age in View.
Try to modify the home controller as follows,then it will work as expected.
1) Instead of having a list of AgeHoroscope, we can have a dictionary of age and prediction.
2) Create two Index Action for HttpGet and HttpPost as follows.
public class HomeController : Controller
{
Dictionary<int, string> AgePred = new Dictionary<int, string>()
{
{16,"You are confused"},
{26,"You are very brilliant"},
{27,"You are practical"}
};
[HttpGet]
public ActionResult Index()
{
AgeHoroscope selectedHoro = new AgeHoroscope() { Age = 26 };
selectedHoro.HoroscopePrediction = AgePred[selectedHoro.Age];
return View(selectedHoro);
}
[HttpPost]
public ActionResult Index(AgeHoroscope model,ContactEntity entity)
{
model.Age = entity.ContactAge;
model.HoroscopePrediction = AgePred[entity.ContactAge];
return View(model);
}
}

LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression

This is my controller class
public class HomeController : Controller
{
private rikuEntities rk = new rikuEntities();
public ActionResult Index()
{
var db = new rikuEntities();
IEnumerable<SelectListItem> items = db.emp.Select(c => new
SelectListItem
{
Value = c.Id.ToString(),
Text = c.name
});
ViewBag.CategoryID = items;
return View();
}
}
this is my view
#using (Html.BeginForm("viewToController", "Home"))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>emp</legend>
<div class="editor-field">
#Html.DropDownList("CategoryID", (IEnumerable<SelectListItem>) ViewBag.Categories)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
whenever I run this program I get this error:
LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression." in the statement #Html.DropDownList("CategoryID", (IEnumerable) ViewBag.Categories). i am using entity framework mechanism for databse connection. please help me to find out the error...
I would recommend you to use view models and strongly typed views instead of ViewBag. So start with defining your view model:
public class EmployeeViewModel
{
public string CategoryId { get; set; }
public IEnumerable<Employee> Categories { get; set; }
}
then in the controller populate this view model:
public class HomeController : Controller
{
public ActionResult Index()
{
var db = new rikuEntities();
var model = new EmployeeViewModel
{
Categories = db.emp.ToArray() // <-- you probably want categories here
};
return View(model);
}
}
and in the view:
#model EmployeeViewModel
#using (Html.BeginForm("viewToController", "Home"))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>emp</legend>
<div class="editor-field">
#Html.DropDownListFor(
x => x.CategoryId,
new SelectList(Model.Categories, "Id", "name")
)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Sadly EF does not know how to convert ToString() to an SQL statement.
You must, therefore, use the embedded function SqlFunctions.StringConvert.
There is no overload for int so you will need to typecast to double :-(
var items = from v in db.emp
select new SelectListItem
{
Text = c.name,
Code = SqlFunctions.StringConvert((double)c.Id)
};

Resources