Search method issue - c#

I'm using MVC 5, C# and I'm trying to build a search filter that will filter through upon each key stroke. It works as so, but the textbox erases after submitting. Now this is probably not the best approach to it either. Is there a way to make so when it posts it doesn't erase the textbox, or better yet, is there a better alternative?
#using (Html.BeginForm("Index", "Directory", FormMethod.Post, new { id = "form" }))
{
<p>
Search Employee: <input type="text" name="userName" onkeyup="filterTerm(this.value);" />
</p>
}
<script>
function filterTerm(value) {
$("#form").submit();
event.preventDefault();
}
</script>

I agree with the comments on your question. Posting on every key stroke would be a frustrating user experience.
So, two answers, use ajax to perform the search (which will then keep the value since the whole page will not post) or have a submit button and name the input the same as the controller action parameter.
Controller code (used with your existing code):
public class DirectoryController : Controller
{
[HttpPost()]
public ActionResult Index(string userName)
{
// make the input argument match your form field name.
//TODO: Your search code here.
// Assuming you have a partial view for displaying results.
return PartialView("SearchResults");
}
}
View Code (to replace your code with Ajax):
<p>
Search Employee:#Html.TextBox("userName", new { id = "user-name-input" })
</p>
<div id="results-output"></div>
<script type="text/javascript">
$("#user-name-input").change(function(e) {
$.ajax({
url: '#Url.Action("Index", "Directory")'
, cache: false
, type: "post"
, data: {userName: $("#user-name-input").val() }
}).done(function (responseData) {
if (responseData != undefined && responseData != null) {
// make sure we got data back
$("#results-output").html(responseData);
} else {
console.log("No data returned.");
alert("An error occurred while loading data.");
} // end if/else
}).fail(function (data) {
console.log(data);
alert("BOOOM");
});
}
</script>

A better way is to ditch your Html.BeginForm (unless you actually need it for something else) and use a pure ajax method of getting the data.
So your modified html would be:
<p>
Search Employee:
<input type="text" name="userName" onkeyup="filterTerm(this.value);" />
</p>
<script>
function filterTerm(value) {
$.ajax({
url: '#Url.Action("Index", "Directory")',
data: {
searchTerm: value
},
cache: false,
success: function (result) {
//do something with your result,
//like replacing DOM elements
}
});
}
</script>
You also need to change the action that ajax will be calling (and I have no idea why you are calling the "Index" action).
public ActionResult Index(string searchTerm)
{
//lookup and do your filtering
//you have 2 options, return a partial view with your model
return PartialView(model);
//or return Json
return Json(model);
}
The best thing about this ajax is there is no posting and it's async, so you don't have to worry about losing your data.

Related

Simplest way to get model data/objects in the view from input with an ajax partial view call(s)

Hello i googled to find a solution to my problem, every link brought me to asp forms solution, or solutions that do not ask for form inputs, this problem has form inputs and i cant seem too find a link for help, what im asking for is simple: get the data from user input through models by ajax calls.
View (index.cshtml):
#model UIPractice.Models.ModelVariables
<!-- Use your own js file, etc.-->
<script src="~/Scripts/jquery-1.10.2.js" type="text/javascript"></script>
<div id="div1">
#Html.BeginForm(){ #Html.TextBoxFor(x => x.test1, new { style = "width:30px" })}
<button id="hello"></button>
</div>
<div id="result1"></div>
<script type="text/javascript">
//Job is to load partial view on click along with model's objects
$(document).ready(function () {
$('#hello').click(function () {
$.ajax({
type: 'POST',
url: '#Url.Action("HelloAjax", "Home")',
data: $('form').serialize(),
success: function (result) {
$('#result1').html(result);
}
});
});
});
Model (ModelVariables.cs):
public class ModelVariables
{
//simple string that holds the users text input
public string test1 { get; set; }
}
Controller (HomeController.cs):
// GET: Home
public ActionResult Index()
{
ModelVariables model = new ModelVariables();
return View(model);
}
public ActionResult HelloAjax(ModelVariables model)
{
ViewBag.One = model.test1;`
return PartialView("_MPartial", model);
}
Partial View (_MPartial.cshtml):
#model UIPractice.Models.ModelVariables
#{
<div>
<!--if code runs, i get a blank answer, odd...-->
#Model.test1
#ViewBag.One
</div>
}
So go ahead and copy/paste code to run, you will notice that you get nothing when you click the button, with user text input, odd...
I see a few problems.
Your code which use the Html.BeginForm is incorrect. It should be
#using(Html.BeginForm())
{
#Html.TextBoxFor(x => x.test1, new { style = "width:30px" })
<button id="hello">Send</button>
}
<div id="result1"></div>
This will generate the correct form tag.
Now for the javascript part, you need to prevent the default form submit behavior since you are doing an ajax call. You can use the jQuery preventDefault method for that.
$(document).ready(function () {
$('#hello').click(function (e) {
e.preventDefault();
$.ajax({
type: 'POST',
url: '#Url.Action("HelloAjax", "Home")',
data: $('form').serialize(),
success: function (result) {
$('#result1').html(result);
}
,error: function (a, b, c) {
alert("Error in server method-"+c);
}
});
});
});
Also, you might consider adding your page level jquery event handlers inside the scripts section (Assuming you have a section called "scripts" which is being invoked in the layout with a "RenderSection" call after jQyery is loaded.
So in your layout
<script src="~/PathToJQueryOrAnyOtherLibraryWhichThePageLevelScriptUsesHere"></script>
#RenderSection("scripts", required: false)
and in your indidual views,
#section scripts
{
<script>
//console.log("This will be executed only after jQuery is loaded
$(function(){
//your code goes here
});
</script>
}

Can't call new page by controller in Asp.net

I want to call new page by click on a button by jQuery from Index.cshtml :
$("#btnSearch").click(function(){
var idser = $("#Name").val();
$.ajax({
type: "POST",
url: "/User/getAll",
id : idser,
success: function() {
alert("success");
}
});
});
});
It call to my controller action : UserController/getAll
[System.Web.Services.WebMethod]
public ActionResult getAll(string id,string name)
{
return View("AllUser");
}
But is still at Index.cshtml not go to AllUser.cshtml page? I don't know why...please help.
UPDATE :
my jquery function call my action in controller , and the action work correctly but it not return to AllUser.cshtml page.
Please check out the documentation here. I would attempt using a tag-helper in the Ajax setup like this:
$("#btnSearch").click(function(){
var idser = $("#Name").val();
$.ajax({
type: "POST",
url: '#Url.Action("User", "getAll", new { id = "ID", name = "searchName" })',
id : idser,
success: function() {
alert("success");
}
});
});
});
Firstly I don't know what is your purpose behind using ajax while your are redirecting the other page ?
But you if still want to use Ajax, you can achieve this by two ways:
1) you can assign window.location in your success block.
2) Use your code by following way :
$("#btnSearch").click(function(){
var idser = $("#Name").val();
$.ajax({
type: "GET",
url: "/User/getAll",
id : idser,
success: function() {
alert("success");
return true;
}
});
});
});
you can try it by putting return true in your script.
hope it helps to you
Updating in response to clarification in comments:
In the success callback,
location.href="/user/getall";
That will cause the browser to navigate to that URL after the ajax post has completed.
A button that posts a value from an input to another page - that's a form.
<form action="/User/getAll">
<input type="submit" value="Click me">
</form>
I don't know where your id is coming from, but you can put a hidden input in the form and a script to populate it (unless it's a user input - then you can just put the input right in the form.)
<form action="/User/getAll">
<input type="submit" value="Click me">
<input type="hidden" name="id" id="hiddenId"/>
</form>
<script>
$("#hiddenId").val($("#Name").val());
</script>
Or, if you want to be sure that your form's action URL matches your route:
<form action='#Url.Action("getAll", "User")'>
(Assuming that the controller is called "User".)
Here we go:
window.location.href = "yourUrl" can help you.
$("#btnSearch").click(function(){
var idser = $("#Name").val();
$.ajax({
type: "POST",
url: "/User/getAll",
id : idser,
success: function() {
alert("success");
window.location.href ="../yourUrl"; //This is working!
}
});
});
});
You may redirect in Controller this like:
[System.Web.Services.WebMethod]
public ActionResult getAll(string id,string name)
{
return RedirectToAction("NameOfAction"); //Here is going Name of Action wich returns View AllUser.cshtml
}
Hope it helps;)

JsonResult controller parameter always null

I am using extremely similar code on another view and controller that is working perfectly but for some reason I cannot get this one to work. No matter what I do the controller parameters show undefined even though name and pass in the javascript are working correctly. Any help would be appreciated!
View:
#using (Html.BeginForm())
{
<fieldset>
<legend>User</legend>
Username:
#Html.TextBox("txtUsername")
<br/>
Password:
#Html.TextBox("txtPassword")
<br />
<p>
<input type="submit" id="btnLogin" value="Login" />
</p>
</fieldset>
}
<script>
$(function() {
$("#btnLogin").click(login);
});
function login() {
var name = $('#txtUsername').val();
var pass = $('#txtPassword').val();
$.post("/User/Login/" + name + "/" + pass, null, loginSuccess, "json");
}
function loginSuccess(result) {
alert(result);
}
</script>
Controller:
public ActionResult Login()
{
return View("Login");
}
[HttpPost]
public JsonResult Login(string name, string pass)
{
string result = "test result";
return Json(result);
}
all you need is:
View:
#using (Html.BeginForm())
{
<fieldset>
<legend>User</legend>
Username:
#Html.TextBox("txtUsername")
<br/>
Password:
#Html.TextBox("txtPassword")
<br />
<p>
<input type="button" id="btnLogin" value="Login" />
</p>
</fieldset>
}
Then the controller:
Controller:
public ActionResult Login()
{
return View("Login");
}
[HttpPost]
public JsonResult Login(string name, string pass)
{
string result = "test result";
return Json(result);
}
The ajax part:
<script type="text/javascript">
$( "#btnLogin" ).click(function() {
$.ajax({
url: "#Url.Action("YourControllerActionName", "YourControllerName")",
type: 'POST',
data: {
name: $('#txtUsername').val(),
pass: $('#txtPassword').val()
},
success: function(result) {
alert(result);
}
});
});
<script>
you are sending parameters as a part of the URL (thus, effectively, making it GET regardless of jquery $.post() ) and your controller strictly expects HttpPost (meaning, parameters in http request body, not in query string).
leaving aside that fact that having username/password in url is extremely bad practice.
try sending data as:
$.post('url/of/the/controller', {name: $('#txtUsername').val(), pass: $('#txtPassword').val()});
I don't like string concatenation and hard-coded strings.
First, let's use an HTML helper to resolve an action's URL.
#Url.Action("Login", "User")
Second, let's pass the data as a javascript object.
$.post("#Url.Action("Login", "User")",
{
name: name,
pass: pass
}, loginSuccess, "application/json");
You may be able to do it the way you have it, but I would need to see your routes as well. There is a better way to make this call though.
var data = {
"name": $('#txtUsername').val(),
"pass": $('#txtPassword').val()
};
$.post('#Url.Action("Login", "Home")', data, function(response) {
//Do something with the response if you like
});
You are making the call your controller action method incorrectly. Try passing name and pass as data in the $.post call instead of appended on to the url.
It also may be cleaner to make your controller action method take a model of type LogIn. LogIn could have two properties (Name and Pass). That way when you send data in $.post
you can send it like { name: 'someName', pass: 'somePass' }.
You can Post it as ::
$.ajax({
type:'POST',
url:"User/Login",
data:{UserName:$("#UserName").val(),Password:$("#Password").val()},
success:function(data){
alert(data);
}
})
and On Server side you will get the Information like::
[HttpPost]
public JsonResult Login(string Username, string Password)
{
string result = "test result";
return Json(result);
}

How to replace div's content by partial view or update it's content depending on what json result returns on ajax complete?

Well I have simple ajax form:
This is MyPartialView
#using(Ajax.BeginForm("action", "controller", new AjaxOptions
{
OnBegin = "beginRequest",
OnComplete = "completeRequest",
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "div-to-replace"
}, }))
{
<input type="text" id="my-input" />
...
}
This is parent view:
<div id="div-to-replace">
#Html.RenderPartial("MyPartialView")
</div>
In my controller I have:
[HttpPost]
public ActionResult action(Model model)
{
if (ModelState.IsValid)
{
// do staff with model
// return partial view
return PartialView("MyPartialView");
}
// else add error and return json result
return Json(new {error = "invalid data"});
}
And my javascript on ajax complete method:
function completeRequest(data) {
var result = $.parseJSON(data.responseText);
if (result != 'undefined' && result != null && result.error) {
// just display error and not replace all content
// attachModelError is my custom method, it just adds vlaidation-error class to inputs, etc.
attachModelError("my-input", result.error);
return;
}
// or show returned html (depending on returned model form inputs will be modified:
// select box with different items in my case
$('#div-to-replace').html(data.responseText);
}
But the problem is I have empty #div-to-replace if model state is invalid. If model state is ok every thing works fine. If I use different insertion mode it creates duplicates of div's content before or after div.
Summary:
I want different InsertionMode behavior depending on json result. I don't need replace data if (result != 'undefined' && result != null && result.error).
I had to solve this problem once so very long ago. I came up with a simple solution, which today, may not be the best solution but it gets the job done.
My solution involved setting up a controller action that would render just the partial with data that it would need and have my JavaScript request it.
C#
MyController: Controller
{
public ActionResult GetPartialViewAction()
{
return PartialView("mypartialview", new partialViewModel());
}
}
JavaScript
$.ajax({
url: "/my/getpartialaction/"
}).done(function(data) {
$("#partialViewDiv").html(data);
});
HTML
<div id="partialViewDiv"></div>
A better solution would be to use a MVVM/MVC JavaScript library that would allow you to leverage html templates and only have to transmit the data over your ajax solution. I recommend looking into knockout.js or backbone.js for this more accepted pattern.
I have the same problem with the default c# ajax forms. I have a solution what might work.
jQuery:
$(function () {
var ajaxFormSubmit = function () {
var $form = $(this);
var options = {
url: $form.attr("action"),
type: $form.attr("method"),
data: $form.serialize(),
cache: false
}
$.ajax(options).done(function (data) {
data.replaces.each(function (replace) {
$(replace.id).replaceWith(replace.html);
});
});
return false;
};
$("form[data-ajax='true']").submit(ajaxFormSubmit);});
form.cshtml
#using (Html.BeginForm("Create", "Menu", FormMethod.Post, new { data_ajax = "true" }))
{}
model sample
public string Id {get;set;}
public string Html {get;set;}
The last thing you need to do in your controller is return a json result with a list of your model sample, id is target element to update, for the html you must use a render partial / or view as string.
For render view to partial see [question]: https://stackoverflow.com/questions/434453

Display a loading screen using anything

I sometimes have operation that takes a while to compute. I would like to be able to display something, like a kind of grey layer covering everything, or a loading screen, while the operation computes. But I frankly have no idea how to do it.
I'm building an MVC app using MVC4, I'm beginning with jQuery and opened to any suggestions. How might I do that?
EDIT
Here's a sample of page I've been building:
<h2>Load cards</h2>
<script type="text/javascript">
$(document).ready(function () {
$("form").submit(function (event) {
event.preventDefault();
alert("event prevented"); // Code goes here
//display loading
$("#loadingDialog").dialog("open");
alert("dialog opened"); // Never reaches here.
$.ajax({
type: $('#myForm').attr('method'),
url: $('#myForm').attr('action'),
data: $('#myForm').serialize(),
accept: 'application/json',
dataType: "json",
error: function (xhr, status, error) {
//handle error
$("#loadingDialog").dialog("close");
},
success: function (response) {
$("#loadingDialog").dialog("close");
}
});
alert("ajax mode ended");
});
});
</script>
#using (Html.BeginForm())
{
<div class="formStyle">
<div class="defaultBaseStyle bigFontSize">
<label>
Select a Set to import from:
</label>
</div>
<div class="defaultBaseStyle baseFontSize">
Set: #Html.DropDownList("_setName", "--- Select a Set")<br/>
</div>
<div id="buttonField" class="formStyle">
<input type="submit" value="Create List" name="_submitButton" class="createList"/><br/>
</div>
</div>
}
Here's a snippet of code from my javascript file:
$(document).ready(function ()
{
$(".createList").click(function() {
return confirm("The process of creating all the cards takes some time. " +
"Do you wish to proceed?");
});
}
As a bonus (this is not mandatory), I'd like it to be displayed after the user has confirmed, if it is possible. else I do not mind replacing this code.
EDIT
Following Rob's suggestion below, here's my controller method:
[HttpPost]
public JsonResult LoadCards(string _submitButton, string _cardSetName)
{
return Json(true);
}
And here's the "old" ActionResult method:
[HttpPost]
public ActionResult LoadCards(string _submitButton, string _setName)
{
// Do Work
PopulateCardSetDDL();
return View();
}
As of now the code never reaches the Json method. It does enter the ajax method up there (see updated code), but I don't know how to make this work out.
We hide the main content, while displaying an indicator. Then we swap them out after everything is loaded. jsfiddle
HTML
<div>
<div class="wilma">Actual content</div>
<img class="fred" src="http://harpers.org/wp-content/themes/harpers/images/ajax_loader.gif" />
</div>
CSS
.fred {
width:50px;
}
.wilma {
display: none;
}
jQuery
$(document).ready(function () {
$('.fred').fadeOut();
$('.wilma').fadeIn();
});
First you want to have jQuery "intercept" the form post. You will then let jQuery take care of posting the form data using ajax:
$("form").submit(function (event) {
event.preventDefault();
//display loading
$("#loadingDialog").dialog("open");
$.ajax({
type: $('#myForm').attr('method'),
url: $('#myForm').attr('action'),
data: $('#myForm').serialize(),
accept: 'application/json',
dataType: "json",
error: function (xhr, status, error) {
//handle error
$("#loadingDialog").dialog("close");
},
success: function (response) {
$("#loadingDialog").dialog("close");
}
});
});
More information on the $.ajax() method is here: http://api.jquery.com/jQuery.ajax/
You could use the jquery dialog to display your message: http://jqueryui.com/dialog/
There are other ways to display a loading message. It could be as simple as using a div with a loading image (http://www.ajaxload.info/) and some text, then using jQuery to .show() and .hide() the div.
Then, in your controller, just make sure you're returning JsonResult instead of a view. Be sure to mark the Controller action with the [HttpPost] attribute.
[HttpPost]
public JsonResult TestControllerMethod(MyViewModel viewModel)
{
//do work
return Json(true);//this can be an object if you need to return more data
}
You can try creating the view to load the barebones of the page, and then issue an AJAX request to load the page data. This will enable you to show a loading wheel, or alternatively let you render the page in grey, with the main data overwriting that grey page when it comes back.
This is how we do it in our application, however there is probably a better way out there...
if not I'll post some code!
EDIT: Here's the code we use:
Controller Action Method:
[HttpGet]
public ActionResult Details()
{
ViewBag.Title = "Cash Details";
return View();
}
[HttpGet]
public async Task<PartialViewResult> _GetCashDetails()
{
CashClient srv = new CashClient();
var response = await srv.GetCashDetails();
return PartialView("_GetCashDetails", response);
}
Details View:
<div class="tabs">
<ul>
<li>Cash Enquiry</li>
</ul>
<div id="About_CashEnquiryLoading" class="DataCell_Center PaddedTB" #CSS.Hidden>
#Html.Image("ajax-loader.gif", "Loading Wheel", "loadingwheel")
</div>
<div id="About_CashEnquiryData"></div>
<a class="AutoClick" #CSS.Hidden data-ajax="true" data-ajax-method="GET"
data-ajax-mode="replace" data-ajax-update="#About_CashEnquiryData"
data-ajax-loading="#About_CashEnquiryLoading" data-ajax-loading-duration="10"
href="#Url.Action("_GetCashDetails", "Home")"></a>
</div>
Custom Javascript:
$(document).ready(function () {
// Fire any AutoClick items on the page
$('.AutoClick').each(function () {
$(this).click();
});
});

Categories