I wonder if it's possible to have controls (dataanotation) on hidden fields (HiddenFor or hidden EditorFor) ?
I don't think so, but we never know.
There are a lot of posts on how to hide EditorFor such as :
TextBoxFor vs EditorFor, and htmlAttributes vs additionalViewData
In my case,in a view I have a jquery call to a WCF REST service, that in success case fill my EditorFor. I would like that the Required DataAnotation to be applied on that EditorFor, would it be possible ?
I think that as long as the EditorFor is invisible the DataAnotation cannot be applied. Would it have a way to apply the DataAnotation on the hidden EditorFor ?
Here is the code :
To hide the EditorFor :
#Html.EditorFor(model => model.VilleDepart, "CustomEditor", new {style = "display:none;" })
The CustomEditor :
#{
string s = "";
if (ViewData["style"] != null) {
// The ViewData["name"] is the name of the property in the addtionalViewData...
s = ViewData["style"].ToString();
}
}
#Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { style = s })
the model :
string _VilleDepart;
[Required]
[Display(Name = "Ville Départ")]
public string VilleDepart
{
get
{
if (Commune != null) {
return Commune.Commune1;
}
return _VilleDepart;
}
set {
_VilleDepart = value;
}
}
The JQuery call to WCF REST Service :
$(document).ready(function () {
$([document.getElementById("IVilleDepart"), document.getElementById("IVilleArrivee")]).autocomplete({
source: function (request, response) {
$.ajax({
cache: false,
type: "GET",
async: false,
dataType: "json",
url: GetSearchCommunetURl + "(" + request.term + ")",
success: function (data) {
//alert(data);
response($.map(data, function (item) {
return {
label: item['Commune'] + ' (' + item['CodePostal'] + ')',
val: item
}
}))
},
error: function (response) {
alert("error ==>" + response.statusText);
},
failure: function (response) {
alert("failure ==>" + response.responseText);
}
});
},
select: function (e, i) {
if (e.target.id == "IVilleDepart") {
VilleDepart = i.item.val;
EVilleDepart.value = VilleDepart.Commune;
ECodePostalDepart.value = VilleDepart.CodePostal;
ECodeINSEEDepart.value = VilleDepart.CodeINSEE;
}
if (e.target.id == "IVilleArrivee") {
VilleArrivee = i.item.val;
EVilleArrivee.value = VilleArrivee.Commune;
ECodePostalArrivee.value = VilleArrivee.CodePostal;
ECodeINSEEArrivee.value = VilleArrivee.CodeINSEE;
}
},
minLength: 2
});
});
If I don't hide the EditorFor I can see it is correctly filled after the WCF REST service call and the Required DataAnotation is applied.
There are other way to hide the EditorFor, for instance to apply the style='width:0px;height:0px'
It hides but disable the Required DataAnotation,
if I apply the style='width:0px;height:1px', we don't see a lot of the EditorFor but the Required DataAnotation is active.
I've seen an answer at http://www.campusmvp.net/blog/validation-of-hidden-fields-at-the-client-in-asp-net-mvc
(but it seems i had badly searched precedently, the validation of hidden field is treated in some blogs and sites).
To active the validation of hidden fields, you just have to add this little javascript line :
$.validator.setDefaults({ ignore: null });
and it works !
Apparently it doesn't work with mvc2, but works since mvc3.
Related
I am modifying a preexisting application. I am trying to add the jquery autocomplete functionality. I have it working and calling the controller but the problem is the name attribute in the input field is "someClass.someMethod" so because I can't put this in the controller parameter like this, but still want to satisfy asp.net's Model Binding rules, what can I do?
Controller:
public JsonResult GetPs(string pN, PSModel pS)
{
List<string> pNs = null;
pNs= pS.PEntryBL.BusinessLayerPS.PS
.Where(x => x.Text.StartsWith(pN)).Select(y => y.Text).ToList();
return Json(pNs, JsonRequestBehavior.AllowGet);
}
View:
$(function () {
$("#autoCompletePNBox").autocomplete({
source: '#Url.Action("GetPs", "PS", new {pS = #Model})'
});
});
In Form:
#Html.Label("Scan PN: ", new { #class = "DFont"})
#Html.TextBoxFor(r => r.PEntryBL.PS, new { #class = "pageFont", id = "autoCompletePNBox" })
Using This Post
I was able to get it working by grabbing the value of the input field and passing it on each function call (or each time a user enters a character).
Now when the user selects the item from the autocomplete list, and selects submit then the frameworks form model binding behind the scenes will still work as originally implemented.
Here is the jquery code change:
<script type="text/javascript">
$(function () {
var src = '#Url.Action("GetPs", "PS", new {pS = #Model})'
$("#autoCompletePNBox").autocomplete({
source: function (request, response) {
$.ajax({
url: src,
dataType: "json",
data: {
pN: $("#autoCompletePNBox").val()
},
success: function (data) {
response(data);
}
});
}
});
});
I couldn't figure this out right away as my Jquery skills are not very strong. Hopefully this helps someone.
A contrived example of bi-directional data binding
var user = {
model: function(name) {
this.name = m.prop(name);
},
controller: function() {
return {user: new user.model("John Doe")};
},
view: function(controller) {
m.render("body", [
m("input", {onchange: m.withAttr("value", controller.user.name), value: controller.user.name()})
]);
}
};
https://lhorie.github.io/mithril/mithril.withAttr.html
I tried the above code does not work nothing.
It was the first to try to append the following.
m.mount(document.body, user);
Uncaught SyntaxError: Unexpected token n
Then I tried to append the following.
var users = m.prop([]);
var error = m.prop("");
m.request({method: "GET", url: "/users/index.php"})
.then(users, error);
▼/users/index.php
<?php
echo '[{name: "John"}, {name: "Mary"}]';
Uncaught SyntaxError: Unexpected token n
How do I operate the m.withAttr tutorials code?
Try returning m('body', [...]) from your controller.
view: function (ctrl) {
return m("body", [
...
]);
}
render should not be used inside of Mithril components (render is only used to mount Mithril components on existing DOM nodes).
The example is difficult to operate because it's contrived, it's not meant to be working out-of-the-box. Here's a slightly modified, working version:
http://jsfiddle.net/ciscoheat/8dwenn02/2/
var user = {
model: function(name) {
this.name = m.prop(name);
},
controller: function() {
return {user: new user.model("John Doe")};
},
view: function(controller) {
return [
m("input", {
oninput: m.withAttr("value", controller.user.name),
value: controller.user.name()
}),
m("h1", controller.user.name())
];
}
};
m.mount(document.body, user);
Changes made:
m.mount injects html inside the element specified as first parameter, so rendering a body element in view will make a body inside a body.
Changed the input field event to oninput for instant feedback, and added a h1 to display the model, so you can see it changing when the input field changes.
Using m.request
Another example how to make an ajax request that displays the retrieved data, as per your modifications:
http://jsfiddle.net/ciscoheat/3senfh9c/
var userList = {
controller: function() {
var users = m.prop([]);
var error = m.prop("");
m.request({
method: "GET",
url: "http://jsonplaceholder.typicode.com/users",
}).then(users, error);
return { users: users, error: error };
},
view: function(controller) {
return [
controller.users().map(function(u) {
return m("div", u.name)
}),
controller.error() ? m(".error", {style: "color:red"}, "Error: " + controller.error()) : null
];
}
};
m.mount(document.body, userList);
The Unexpected token n error can happen if the requested url doesn't return valid JSON, so you need to fix the JSON data in /users/index.php to make it work with your own code. There are no quotes around the name field.
I want to sync the notification counter on both sides at a time. The attached image will make you understand easily what i need to do on which I am stuck from quite a few days.
Image:
The Right Side of the notification bell is in Layout:
<div class="header-top">
<h2 style="width:100%">#ViewBag.Heading</h2>
<a class="info sprite" id="lnkInfo"></a>
#{
if(ViewBag.ShowNotification != null && ViewBag.ShowNotification) {
<span class="notifications-icon"><em>#ViewBag.NotificationCount</em></span>
}
}
</div>
The Left Notification Bell is in View.
Code:
<div class="head">
<span class="notifications-icon"><em>#Model.Announcement.Count</em></span>
<h3>Notifications</h3>
</div>
Jquery Ajax Call to Controller Action:
function UpdateNotification(id) {
var json = { "AnnouncementID": id };
$.ajax({
type: 'POST',
url: '#Url.Action("UpdateNotificationData", "Home")',
contentType: 'application/json; charset=utf-8',
data: '{"AnnouncementID":' + id + '}',
dataType: 'json',
cache: false,
success: function (data) {
if (data) {
updatenotificationUI(id);
}
}
})
}
function updatenotificationUI(id) {
var $notificaitonContainer = $(".notifications");
if (id != null) {
var $li = $notificaitonContainer.find("li[id=" + id + "]");
if ($li != null) {
$li.slideUp("slow", function () {
$(this).remove();
var legth = $notificaitonContainer.find("#listing li").length;
if (legth > 0)
$notificaitonContainer.find("em").html(legth);
else
$notificaitonContainer.find("em").html("");
});
}
}
else {
$notificaitonContainer.find("ul").html("");
$notificaitonContainer.find("em").html("");
}
}
Home Controller :
public ActionResult UpdateNotificationData(string AnnouncementID)
{
var announcements = new AnnouncementResponse() { Announcement = new List<Announcement>() };
if (IsUserAuthenticated)
return RedirectToAction("Index", "Account");
announcements = _contentManager.Announcement();
var item = announcements.Announcement.Where(p => p.AnnouncementID == Convert.ToInt32(AnnouncementID)).FirstOrDefault();
announcements.Announcement.Remove(item);
ViewBag.NotificationCount = announcements.Announcement.Count;
return Json(new { success = true });
}
But the Notification Bell in Layout doesnt update with the viewbag value or even when the model is assigned to it.
Please provide a solution for this.
You're only updating one of the two notifications. First you find a containing element:
var $notificaitonContainer = $(".notifications");
The HTML in the question doesn't have any elements which match this, so I can't be more specific. But just based on the naming alone it sounds like you're assuming there's only one such container.
Regardless, you then choose exactly one element to update:
var $li = $notificaitonContainer.find("li[id=" + id + "]");
(This can't be more than one element, since id values need to be unique.)
So... On your page you have two "notification" elements. You're updating one of them. The solution, then, would be to also update the other one. However you identify that elements in the HTML (jQuery has many options for identifying an element or set of elements), your updatenotificationUI function simply needs to update both.
Firstable sorry for my English. I've problem with KendoUI TreeView control on ASP.NET MVC4.
<div class="treeview-back">
#(Html.Kendo().TreeView()
.Name("treeview-left")
.DragAndDrop(true)
.Events(ItemAction)
.BindTo(Model)
)
I got treeview and binded event OnDrop:
function OnDrop(e) {
dropped = GetValueFromTags(e.destinationNode.innerHTML);
inDrag = !inDrag;
OnHover();
e.setValid(e.valid && id > 10000);
if (e.valid && id > 10000) {
var webMethod = "/Sitemap/UpdateData";
var data = $("div.treeview-back").find("span.items").text();
//var data = $("div.treeview-back").data("kendoTreeView").dataSource.data();
console.log(data);
$.ajax({
type: "POST",
url: webMethod,
data: data,
contentType: "application/json",
dataType: "json",
converters: {
'text json': true
},
success: function(data) {
},
error: function(data) {
console.log("error: " + data);
}
});
}
}
And my action in Controller:
[HttpPost]
public ActionResult UpdateData(IEnumerable<TreeViewItemModel> data)
{
// some database operations here
return Json(data);
}
I would like to send current state of my treeview to action. Problem is current method is sending null. I was able to send datasource but it was orginal data (that what i binding to control on start), not the current.
Thanks for help,
Łukasz
I am having the hardest time pulling data out of my url and putting it in my jqGrid in asp.net MVC4. What am I missing here?
$(document).ready(function () {
jQuery("#frTable").jqGrid ({
cmTemplate: { sortable: false },
caption: '#TempData["POPNAME"]' + ' Population',
url: '#Url.Action("GetAjaxPagedGridData", "Encounters", new { popId = TempData["POPULATIONID"] })',//'/Encounters/GetAjaxPagedGridData/'+ '',
datatype: "jsonstring",
mtype: 'GET',
pager: '#pager',
height: '450',
...
Then you go into the colNames and colModels and all that stuff which is tangential to this particular inquiry. Here is the methods that return my data. Suffice it to say that the stuff that I do to do client side paging seems to work. But I can't verify unless I can actually see the data?
What am I doing wrong here?
public string GetAjaxPagedGridData(int page, int rows, int popId) {
string userID = HttpContext.User.Identity.Name;
DataRepository dr = new DataRepository();
string encounter = dr.Get(popId, userID, "1", page, rows, "");
return encounter;
}
You can use postData option of jqGrid in the form
postData: {
popId: 123
}
or in the form
postData: {
popId: function () {
return 123;
}
}
You should use additionally datatype: "json" instead of datatype: "jsonstring".