Check record if exist (instantly) in MVC - sql

I want to check instantly, after i type something in text box, if a record exist in my database. I managed to return on my page number of how many times record exist in database, but i want to return a message (if exists or not).
So, the question is: How can I display a message if record exist or not?
PS. I`m using ASP.NET MVC
Here is my code:
Model class:
public class AdminModel
{
[Remote("IsUniq", "Home", HttpMethod = "POST")]
public string FirstName { get; set; }
}
My controller action(HomeController):
[HttpPost]
public JsonResult IsUniq(string FirstName)
{
IPAdressProgramEntities r = new IPAdressProgramEntities();
var user = r.spLineExist(FirstName);//spLineExist - procedure in SQL- return how many time record exist in database
return Json(user); //return on my page how many times record exists
}
And this is my view:
#using (Html.BeginForm())
{
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
}
PS WebConfig is configured and also scripts are included in my view.
Thank you.

If you simply want to show message when your count is greater than 0, Add an Error message property to your data annotation.
[Remote("IsUniq", "Home", HttpMethod = "POST", ErrorMessage = "Exist")]
public string FirstName { get; set; }
and return true of false from your action method. To show the error message, you need to return false from the method.
var responseToSend = user!=0; //user is the count returned by your existing code
return Json(responseToSend);
If you want to show both the messages (Exists/ Not exists), you may consider handling the check yourself with a little jQuery ajax call than relying on the remote data annotation. So simply remove the data annotation.
And listen to the keyup event on this input field, read the value, send to server to check it exist or not, based on the result, show appropriate message
$(function () {
$("#FirstName")
.keyup(function () {
$.post('/Home/IsUniq?FirstName=' + $(this).val(), function (res) {
if (res) {
$("span[data-valmsg-for='FirstName']").text("Not Available")
} else {
$("span[data-valmsg-for='FirstName']").text("Available")
}
})
});
});
Make sure you return True or False from your action method.
[HttpPost]
public JsonResult IsUniq(string FirstName)
{
//If exists
return Json(true);
else
return Json(false);
}

Related

Retain the selected value of dropdownlist on clicking browser back button in asp.net mvc

I have a dropdownlist, the user selects an option in the dropdownlist and based on that value there's a dashboard that gets populated. My issue is how do i retain the dropdownlist value as well as the dashboard values when the user clicks back button in the browser. I tried OutputCache but output cache is only to cache the rendered HTML and not data, I tried memory cache but that didn't work either.
Model:
public class InternalViewModel
{
public int totalclients { get; set; }
public int clientid { get; set; }
public DateTime? AsOFdate { get; set; }
}
Controller:
public ActionResult Dropdownlist()
{
InternalViewModel app = new InternalViewModel();
app.totalclients = db2.AppClients.Count();
IEnumerable<SelectListItem> clients = db2.AppClients.Select(c => new SelectListItem
{
Value = c.ClientID.ToString(),
Text = c.ClientName
});
ViewBag.clients = clients;
return PartialView(app);
}
View:
_dropdownlist.cshtml
<div>
#(Html.Kendo().DropDownListFor(model => model.clientid)
.Name("clientid")
.DataTextField("Text")
.DataValueField("Value")
.Filter("contains")
.OptionLabel("--Select --")
.BindTo((System.Collections.IEnumerable)ViewBag.clients)
.HtmlAttributes(new { #id = "dropdown2", #class = "form-control" })
)
</div>
$('#dropdown2').change(function () {
var selectedID = $(this).val();
$('#RecDashboard').load("/InternalRec/Index", { clientid: selectedID }, function () {
$("#recstatus").load("/AppRec/Index", { clientid: selectedID })
})
Based on dropdownlist value - calls are made to internalrec controller and app rec controller. InternalRec controller is used to display dashboard.And AppRec displays another kind of dashboards. Both the dashboards are driven by the dropdownlist selection.
The InternaRec returns a view with the dashboard, I'm not including all of that for code brevity.
But it's something like this
public ActionResult InternalRec(int? clientid)
{
//some stuff is done
//values to be displayed on dashboard are computed, all these values need clientid.
return PartialView();
}
So when the user clicks on back button on the browser and comes back to this page. I want the user to be able to see the selected dropdownlist value along with the dashboard values, basically the page should not be refreshed. How can I achieve this?
Thanks
You must persist that choice somehow. There's pretty much two options:
Use AJAX to set a session variable (server-side) any time the drop down selection is changed. When rendering the drop down, you should check this session variable, and if it exists, set the drop down to the value it has.
Use localStorage. This is a pure client-side approach. Basically, you just set a key in localStorage when the drop down is changed. On page load, read that key from localStorage and set the drop down accordingly.
The first approach is going to be your safer, more cross-browser option, but localStorage does have pretty decent support even among even some older versions of IE, so it's not as much a deal-breaker as it once might have been.
UPDATE
To set it, you first need an action server-side to response to the AJAX request. At its simplest, that would look something like:
[HttpPost]
public ActionResult SetClientId(int clientId)
{
Session["ClientId"] = clientId;
return Json(new { success = true })
}
Then, you AJAX, client-side:
$('#clientid').on('change', function () {
$.post('/url/to/action/above/', { clientId: $(this).val() });
// omitted success function as there's nothing you really need to do,
// just fire and forget
});
When you are in an action that will allow editing of clientid, you simply try to set it from Session:
model.clientid = Session["ClientId"] as int? ?? default(int);
That looks at little odd, but it's mostly so because you've got a non-nullable int property. First, session values are stored as strings, so you need to cast the value to a nullable int (as int?). Since we're using as, if the value cannot be converted to an int, it will be set as null, instead, so we have to cast to a nullable. However, you still can't store a nullable int for this property, so the null-coalesce operator (??) is used to set the value to default(int) if it's null, instead.

MVC 4 ModelState invalid because it is trying to auto-fill values and not accept new ones

I have a comments section. In the view there is only a comments editor box.
#using (Html.BeginForm(new { courseID = #ViewBag.courseID, userName = #User.Identity.Name }))
{
#Html.ValidationSummary(true)
<div class="NewComment">
<div class="editor-field">
#Html.TextAreaFor(model => model.CommentText, new { maxLength = 500})
#Html.ValidationMessageFor(model => model.CommentText)
</div>
<input type="submit" class="PostComment" value="Post Comment" />
<div id="Counter" class="CommentCounter"/>
</div>
}
The model has the course the comment is linked too, date, comment text, and user. The other values get filled in the create post method.
[HttpPost]
public ActionResult AddComment(CourseComment coursecomment, int courseID, String userName)
{
userName = userName.Split('\\')[1];
coursecomment.CommentDate = System.DateTime.Now;
coursecomment.CourseID = courseID;
coursecomment.UserName = db.Users.FirstOrDefault(u => u.UserName == userName).UserID;
if (ModelState.IsValid)
{
db.CourseComments.AddObject(coursecomment);
db.SaveChanges();
}
return RedirectToAction("Details", "Course", new { courseID = courseID });
}
The problem occurs here. The model is trying to use the userName parameter for the value for courseComment.UserName before I actually do the work and set it. After it gets set the ModelState doesn't change.
Example, domain\abc123 gets passed into the post method and also set in the ModelState for UserName. I do some work, change the userName to abc123 and find the linked ID, lets say ID = 1, to that user with said name, then plug that into the courseComment.UserName ModelState still leaves the domain\abc123 in there and the model stays invalid.
Now, this was working original, then I changed the underlying database around, mainly just column names and some relations.
My solution for this.
Move receiving the username from the post method
[HttpPost]
public ActionResult AddComment(CourseComment coursecomment, int courseID)
{
coursecomment.CommentDate = System.DateTime.Now;
coursecomment.CourseID = courseID;
coursecomment.UserName = db.Users.FirstOrDefault(u => u.UserName == userName).UserID; //Moved
if (ModelState.IsValid)
{
db.CourseComments.AddObject(coursecomment);
db.SaveChanges();
}
return RedirectToAction("Details", "Course", new { courseID = courseID });
}
to a get method.
[HttpGet]
public JsonResult GetUserName(string userName)
{
var ret = db.Users.FirstOrDefault(u => u.UserName == userName).UserID;
return Json(ret, JsonRequestBehavior.AllowGet);
}
Then changed the view to be like
#Html.HiddenFor(model => model.UserName)
....
<script type="text/javascript">
$(function () {
var userName = '#User.Identity.Name.Split('\\')[1]';
$.ajax({
url: '#Url.Action("GetUserName", "CourseComment")',
data: { userName: userName },
type: 'get'
}).done(function (data) {
$('#UserName').val(data);
});
});
The problem is that all the view cares about is what's in ModelState. This is confusing to many devs, but it's logical when you think about it.
Essentially, ModelState is composed from the values of Model, of course, but then also from values in ViewBag, ViewData, and Request, which override anything set via Model. To understand why, imagine a scenario where the user is editing an existing object, but makes an error in one of the values, causing the form to be returned to correct their error. If the values from Model were use, the users edits would be completely undone, replaced with the original values on the object. However, by using the values from Request, ModelState preserves the users submitted values, allowing them to only make the necessary corrections.
Long and short, you have to be very careful about naming request parameters, ViewBag properties, etc., the same as properties on your model. Probably the simplest solution in your scenario is to just change the request param, userName to something else.
Also, for what it's worth, ModelState is case insensitive, so UserName is the same as userName, username, USERNAME or UsErNaMe.

ModelState.IsValid == false, although all model values are inserted

today I have the problem, that after i inserted all data to a formular to create a new Product, the programm say that ModelState.IsValid==false.
When i look into the modelState during debugging there is a Error on field 0. The error: "The CuId field is required".
To prevent that i set CuId right in the Creat POST action like so in the ProductController.cs:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Product product)
{
int lastcu = db.Customers.Max(l => l.Id);
product.CuId = last;
if (ModelState.IsValid)
{
db.Products.Add(product);
db.SaveChanges();
return RedirectToAction("Create", "NewIssue");
}
return View(product);
}
But again it sets the same error.
My view looks like that. Actually the model.CuId should already set there:
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Product</legend>
<div class="editor-label">
#Html.LabelFor(model => model.CuId, "Customer")
#ViewBag.Cuname
#Html.HiddenFor(model => model.CuId, new { id = "lastcu" })
</div>
My GET Controller looks like this:
public ActionResult Create()
{
int lastcu = db.Cu.Max(l => l.Id);
//gives the id a Name
var lastcuname = db.Customers.Find(lastcu).Name;
//show to User by creating the product
ViewBag.Cuname = lastcuname;
ViewBag.CuId = lastcu;
return View();
}
When I look in debug mode into the values of the model product, all fields are filled (also CuId) except of the the foreign key what is bind to the product.CuId and the Id of the product what is set automatically from the database.
Hopefully you can help me. Thanks in advance.
As for the first part of your question, ModelState is populated by the DefaultModelBinder when the method is first called. If property CuId has the [Required] attribute and its value is not posted back, then an error is added to ModelState and therefore ModelState.IsValid is false. Just setting a property of your model does not remove ModelState values.
As for the second part of your question, your not passing you model to the view in the GET method so #Html.HiddenFor(m => m.CuId) generates a hidden input with no value (because the value of model.CuId is null or its default). All you currently doing is passing some values to the view using ViewBag (not good practice) which you never even use. Instead, pass the model to the view as follows.
public ActionResult Create()
{
int lastcu = db.Cu.Max(l => l.Id);
var lastcuname = db.Customers.Find(lastcu).Name;
// Initialize a new instance of the model and set properties
Product model = new Product()
{
CuId = lastcu,
Cuname = lastcuname // assume this is a property of your model?
};
return View(model); // return the model
}
Side note: #Html.LabelFor(model => model.CuId, "Customer") generates a html <label> which is an accessibility element. Clicking on it sets focus to its associated form control. But you don't have an associated form control (just a hidden input which cannot receive focus)

using MVC4 Strongly typed view with Knockout

I am trying to use knockout with MVC strongly typed view. Since my model will have over 20 properties, I prefer to use strongly-typed view model to post back data by using ko.mapping.toJS and ko.Util.postJson. The Eligible field was passed back correctly, however the following code does not post back the selected option from drop down list, it just showed value as 0 when I looked that selectOptionModel on the controller. Can someone point out what I did wrong?
the view model from server side is as follows:
public class SelectOptionModel
{
public bool Eligible { get; set; }
public int selectedOption { get; set; }
public IEnumerable<SelectListItem> AvailableOptions
{
get
{
return Enum.GetValues(typeof(OptionEnum)).Cast<OptionEnum>()
.Select(x => new SelectListItem
{
Text = x.ToString(),
Value = x.ToString()
});
}
}
}
public enum OptionEnum
{
[Description("First")]
FirstOption = 1,
[Description("Second")]
SecondOption = 2,
[Description("Third")]
ThirdOption = 3
}
The razor view is like following:
#model TestKo.Models.SelectOptionModel
...
subViewModel = ko.mapping.fromJS(#Html.Raw(Json.Encode(Model)));
...
}
#using (Html.BeginForm()){
<button type="submit" class="button" id="SaveBtn">Save</button>
<div data-bind="with:vm">
<div>
#Html.LabelFor(model => model.Eligible)
#Html.CheckBoxFor(model => model.Eligible, new { data_bind = "checked: selectOptionVM.Eligible" })
</div>
<div>
#Html.LabelFor(model => model.selectedOption)
#Html.DropDownListFor(model => model.selectedOption, Model.AvailableOptions,
new
{ data_bind = "options: selectOptionVM.AvailableOptions, optionsText: 'Text', optionsValue: 'Value', value: selectOptionVM.selectedOption"
})
</div>
</div>
}
The javascript for the knockout view model is:
sectionVM = function (data) {
var self = this;
var selectOptionVM = data;
return {
selectOptionVM: selectOptionVM
}
}
$(document).ready(function () {
var viewModel = {
vm: new sectionVM(subViewModel)
};
ko.applyBindings(viewModel);
$("#SaveBtn").click(function () {
var optionModel = ko.toJS(viewModel.vm.selectOptionVM);
ko.utils.postJson($("form")[0], optionModel)
});
});
The controller part:
[HttpPost]
public ActionResult Create(SelectOptionModel selectOptionModel)
{
try
{
// TODO: Add insert logic here
var modelSaved = selectOptionModel;
return RedirectToAction("Index");
}
catch
{
return View();
}
}
I'm venturing a bit of a guess here, but this could be the problem: the id-bit of your selected option will always be a string (because it will go in the <option value="" attribute). Your endpoint expects an int. As far as I can see, you don't convert the selectedOption before sending it to the server. try parseInt(selectedOption, 10) before sending it to the server. Also, use the network tool in your browser to debug the info that is being sent to the controller. That might help you to zone in on the problem.
Actually it works. Somehow it was not working previously, but after I cleared cache, cookies etc, it just worked. Thanks everyone!

Orchard Cms Fetching UserPart Field Data in LazyField<T>

I've been Following this post To get my head around Lazy field of T, Which I think I understand, But I'm having trouble getting associated Field Data for a Part loaded this way
Aim - To show photo of blog post author on a blog post.
I want to add a content part "Content Author"
The part Editor should appear as a drop down list of orchard users.
(regardless of the content owner cms users should be able to pick the author)
I have added an image upload field to the User Content Type
I want to show the image of the user on the front end in the view for the Content Author Part
For the first part I have created the content type and used the lazy Filed of UserPart to get the username. However when I try and get the associated fields for the UserPart. There dosent seem to be any.
public class ContentAuthorRecord : ContentPartRecord
{
public virtual string AuthorEmail { get; set; }
}
public class ContentAuthorPart : ContentPart<ContentAuthorRecord>
{
internal readonly LazyField<UserPart> Owner = new LazyField<UserPart>();
public string AuthorEmail
{
get { return Record.AuthorEmail; }
set { Record.AuthorEmail = value; }
}
public UserPart Author
{
get { return Owner.Value; }
set { Owner.Value = value; }
}
public string AuthorName
{
get
{
if (Author == null)
return "Riders for health";
else
{
return Author.UserName;
}
}
}
}
public class ContentAuthorHandler :ContentHandler
{
private readonly IContentManager _contentManager;
public ContentAuthorHandler(IRepository<ContentAuthorRecord> repository, IContentManager contentManager)
{
_contentManager = contentManager;
OnActivated<ContentAuthorPart>(SetUpCustomPart);
Filters.Add(StorageFilter.For(repository));
}
private void SetUpCustomPart(ActivatedContentContext content, ContentAuthorPart part)
{
// Setup the getter of the lazy field
part.Owner.Loader(() => _contentManager.Query<UserPart, UserPartRecord>().List().FirstOrDefault(x => x.Email == part.AuthorEmail));
}
}
I would expect to be able to access the field with something like
(ImageUploadField.Fields.ImageUploadField)Author.Fields.FirstOrDefault(x
=> x.Name == "Photo");
form the within the part class
( although this makes every thing a bit brittle, hard coding a field name, but I'm not sure how eles to go about it)
Further Info
I have a HeaderPart with a Image field added via the cms (not in code) in the display handler I fetch the field like this
protected override DriverResult Display(HeaderPart part, string displayType, dynamic shapeHelper)
{
if (part.HeaderType == HeaderType.Full_width_hero_image)
{
var field = (ImageUploadField) part.Fields.FirstOrDefault(f => f.Name == "HeaderImage");
if (field != null)
{
return ContentShape("Parts_Header_ImageHero",
() => shapeHelper.Parts_Header_ImageHero(ImagePath: field.ImagePath, ImageTitle: field.FileName));
}
return null;
}
if (part.HeaderType == HeaderType.Full_width_hero_video)
{
return ContentShape("Parts_Header_VideoHero", () => shapeHelper.Parts_Header_VideoHero(VideoUrl: part.VideoUrl));
}
if (part.HeaderType == HeaderType.Body_width_video)
{
return ContentShape("Parts_Header_VideoBody", () => shapeHelper.Parts_Header_VideoBody(VideoUrl: part.VideoUrl));
}
return null;
}
This works, But I can do the same for a part loaded into a lazy field.
Cast to dynamic first, then the syntax becomes much simpler: ((dynamic)part.ContentItem).NameOfTheType.NameOfTheField.NameOfTheProperty
If you have added the fields to the User content type via the CMS interface, it may have added the fields to a different part to the one you expect. If you are adding fields to the User content type, by default it will have added the fields to a new part called 'User', not 'UserPart'. Try to following to search all parts in the content item:
(ImageUploadField.Fields.ImageUploadField)Author.ContentItem.Parts
.SelectMany(p => p.Fields).FirstOrDefault(f => f.Name == "Photo");
or directly from the 'User' part:
(ImageUploadField.Fields.ImageUploadField)Author.ContentItem.Parts
.First(p => p.PartDefinition.Name == p.ContentItem.ContentType).Fields
.FirstOrDefault(f => f.Name == "Photo");