I have a form with a searchbox on it. When someone types something into the search box and hits the search button I am trying ot do a post to capture the search filter and then fire off a view.
Here is the controller code
public class SpotsController : Controller
{
[HttpPost]
[AllowAnonymous]
public ActionResult SearchSpots(string searchfilter)
{
//your code here....
return Index(searchfilter);
}
Here is the code from my view up until the part that is tryign to do the submit
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>#ViewBag.Title - Haunt Spotter</title>
</head>
<form id="__AjaxAntiForgeryForm" action="#" method="post"><#Html.AntiForgeryToken()></form>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div class="navbar-collapse collapse">
#using (Html.BeginForm("SearchSpots", "Spots"))
{
<input id="searchfilter" type="text" class="form-control" autocomplete="off" placeholder="Search" name="searchfilter">
<button class="btn btn-default" type="submit"><i class="glyphicon glyphicon-search"></i></button>
}
</div>
</div>
</div>
If I take the parameter off of the controller function it works fine. If not it seems to crash and try to re display a get which fails because I only have a post function for this. I am guessing I have something screwed up with the parameter but I can't figure out what it is. Any help woudl be greatly appreciated.
UPDATE
Based on feedback I have changed my post to a get
[HttpGet]
[AllowAnonymous]
public ActionResult SearchSpots(string searchfilter)
{
//your code here....
return Index(searchfilter);
}
and my view code to this
#using (Html.BeginForm("SearchSpots", "Spots", FormMethod.Get, null))
{
<input id="searchfilter" type="text" class="form-control" autocomplete="off" placeholder="Search" name="searchfilter">
<button class="btn btn-default" type="submit"><i class="glyphicon glyphicon-search"></i></button>
}
Unfortunately I still have the original issue. If I remove the searchfileter parameter from my controller call then it goes into the call with no problems but when I am expecting the modelbinder to give me a searchfilter it crashes out.
Here is the call I am redirecting to in my search function
private ApplicationDbContext db = new ApplicationDbContext();
// GET: Spots
public ActionResult Index(string filter = "")
{
ViewBag.initialFilter = filter;
if (User.IsInRole("SiteAdmin"))
{
return View(db.Spots.ToList());
}
else
{
return View(db.Spots.Where(x => x.Approved).ToList());
}
}
and the view that is displayed
#model IEnumerable<HauntSpots.Models.Spot>
#{
ViewBag.Title = "Index";
}
<h2 class="align-right">Haunt Spots</h2>
#if (Context.User.IsInRole("SiteAdmin"))
{
<p style="padding-top:20px">
<i class="icon-plus-sign"></i> Add New
</p>
}
<table id="dt-spots" class="table table-striped">
<thead>
<tr>
<th></th>
<th></th>
<th></th>
#if (Context.User.IsInRole("SiteAdmin"))
{
<th></th>
}
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#if (Context.User.IsInRole("SiteAdmin"))
{
#Html.Hidden(Url.Action("Edit", "Spots", new { id = item.Id }))
<a style="color: Red; vertical-align: middle; font-size: 2em" href="#Url.Action("Delete", "Spots", new { id = item.Id })" title="Delete Spot" class="btn"><i class="icon-remove-sign"></i></a>
}
else
{
#Html.Hidden(Url.Action("Details", "Spots", new { id = item.Id }))
}
</td>
<td>
#if (item.Image == null)
{
<img width="100" height="100"
src="~/Content/Images/NoPhoto.jpg" class="img-rounded" />
}
else
{
<img width="100" height="100"
src="#item.Image" class="img-rounded"/>
}
</td>
<td >
<div class="form-group pull-left col-md-2">
<h4>#item.Title </h4>
<h5 style="clear: left">
#if (item.Address != null)
{
<span>#item.Address</span>
<br/>
}
#if (item.State == null)
{
<span>#item.City</span><br/>
<span>#item.Country</span>
}
else
{
if (item.State == "")
{
<span>#item.City</span>
<br/>
<span>#item.Country</span>
}
else
{
<span>#item.City, #item.State</span>
<br/>
<span>#item.Country</span>
}
}
</h5>
</div>
<div class="form-group pull-left col-md-8">
<h6>#item.Summary</h6>
</div>
</td>
#if (Context.User.IsInRole("SiteAdmin"))
{
<td>
#if (#item.Approved)
{
<span style="color: green">Approved</span>
}
else
{
<span style="color: red">Not Approved</span>
}
</td>
}
</tr>
}
</tbody>
</table>
<script type="text/javascript">
$(document).ready(function () {
//Initalize and configure DataTables
$('#dt-spots').dataTable({
"oSearch": { "sSearch": "#ViewBag.initialFilter" }
});
$("tbody").on("click", "tr", function () {
window.location = $(this).find('input').attr('name');
});
});
</script>
Do a GET instead of a POST—you're not doing any inserts or updates, just fetching results based on a parameter (searchfilter). With a GET, the values of the input elements in your form will be appended as parameters to the query string of the target URL, which would produce something like mywebsite.com/spots/spotsearch?searchfilter=whateverValueInTheInputBox (depending on how you have your routing configured).
Razor:
#using (Html.BeginForm("SearchSpots", "Spots", FormMethod.Get, null))
{
<input id="searchfilter" type="text" class="form-control" autocomplete="off" placeholder="Search" name="searchfilter">
<button class="btn btn-default" type="submit"><i class="glyphicon glyphicon-search"></i></button>
}
Controller:
public class SpotsController : Controller
{
[HttpGet]
[AllowAnonymous]
public ActionResult SearchSpots(string searchfilter)
{
// ...
}
}
Edit: As per #BviLLe_Kid, you can try replacing <button> with <input>.
Edit 2: Can't help but wonder why you are proxying the call to Index via SearchSpots, causing an unnecessary redirect. If all that SearchSpots does is redirect to Index, why not submit the form directly to Index?
Razor:
#using (Html.BeginForm("Index", "Spots", FormMethod.Get, null))
{
<!-- remember to rename to name="filter" below -->
<input id="filter" type="text" class="form-control" autocomplete="off" placeholder="Search" name="filter">
<input class="btn btn-default" type="submit" <i class="glyphicon glyphicon-search"</i>/>
}
Controller:
// GET: Spots
public ActionResult Index(string filter = "")
{
ViewBag.initialFilter = filter;
if (User.IsInRole("SiteAdmin"))
{
return View(db.Spots.ToList());
}
else
{
return View(db.Spots.Where(x => x.Approved).ToList());
}
}
In agreement with most of the other answers stating that this needs to be an HttpGet request rather than an HttpPost request I believe that this can be solved by changing your HTML.
HTML:
#using (Html.BeginForm("SearchSpots", "Spots", FormMethod.Get, null))
{
<input id="searchfilter" type="text" class="form-control" autocomplete="off" placeholder="Search" name="searchfilter">
<input class="btn btn-default" type="submit" <i class="glyphicon glyphicon-search"</i>/> // part that needs changing
}
Controller:
[HttpGet]
public ActionResult SearchSpots(string searchfilter)
{
// logic
}
I believe your issue can be related to this. <button> is exactly what it is.. a button.. it basically does nothing, and is mainly used for JS purposes. However, the <input type="submit" /> actually submits the surrounding form.
I hope this helps!
UPDATE
I did need the input to pass the parameter. I still had the same error even after it was being passed and I had to make this final tweak to get it running
[HttpGet]
[AllowAnonymous]
public ActionResult SearchSpots(string searchfilter)
{
return RedirectToAction("Index", new { filter = searchfilter});
}
I needed to redirect instead of trying to return a view
I believe you're missing FormMethod.Post in
#using (Html.BeginForm("SearchSpots", "Spots", FormMethod.Post))
{...
you don't need two forms in your HTML and this code is working and post search text
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>#ViewBag.Title - Haunt Spotter</title>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div class="navbar-collapse collapse">
#using (Html.BeginForm("SearchSpots", "Spots", FormMethod.Post))
{
#Html.AntiForgeryToken()
<input id="searchfilter" type="text" class="form-control" autocomplete="off" placeholder="Search" name="searchfilter">
<button class="btn btn-default" type="submit"><i class="glyphicon glyphicon-search"></i></button>
}
</div>
</div>
</div>
And you can add [ValidateAntiForgeryToken] in your action
This is a routing issue. You don't have a route that will hit SearchSpots with a parameter. So either change your route, or change the BeginForm to include the parameter.
ASP.NET MVC - passing parameters to the controller
Pass multiple parameters in Html.BeginForm MVC
Related
I have a search bar in my website, but if the searched word is not valid than I do an if statement to redirect user to home page:
if (jsonResponse is null)
{
return RedirectToAction("Index", "Home");
}
I would like that my site redirect to home page after this check on my controller and than show a pop-up in home page saying "You searched for an invalid word"
You could try this way,
Search Page Controller
public IActionResult SearchPage()
{
var data = TempData["serachResultFromDb"];
if (data != null)
{
ViewData["serachResultFromDb"] = JsonConvert.DeserializeObject<List<PrinterJob>>(TempData["serachResultFromDb"].ToString());
}
return View();
}
Search Page Chtml
#using Newtonsoft.Json.Linq
#using msPartnerSupport.Models
#{
ViewData["Title"] = "Search Page";
}
<h2>#ViewData["Title"]</h2>
#using (Html.BeginForm("SearchKey", "Home", FormMethod.Post))
{
<div>
<table class="table-bordered ">
<tr>
<td><strong>Search</strong></td>
<td>
<input type="text" name="searchkey" placeholder="Enter Search Key" />
</td>
<td>
<input type="submit" value="Search" />
</td>
<td></td>
</tr>
</table>
</div>
<br />
}
<table class="table-bordered ">
<tr>
<th>Printer Name </th>
<th>Total</th>
</tr>
#{
var searkeyResult = (List<PrinterJob>)ViewData["serachResultFromDb"];
if (searkeyResult != null)
{
foreach (var item in searkeyResult)
{
<tr>
<td><strong> #item.PrinterName</strong></td>
<td><strong> #item.TotalPrint</strong></td>
</tr>
}
}
}
</table>
Output should be like :
SearchKey Controller
[HttpPost]
public IActionResult SearchKey(string searchkey)
{
//Searching From Database
List<PrinterJob> serachingFromDb = _context.PrinterJobs.Where(skey => skey.PrinterName == searchkey).ToList();
//If no search Result then redirecting to new page
if (serachingFromDb.Count == 0)
{
return RedirectToAction("About");
}
//On successful search result
TempData["serachResultFromDb"] = JsonConvert.SerializeObject(serachingFromDb);
return RedirectToAction("Index");
}
Note: I am testing on Home controller so directly redirecting to Index action. This controller has no view page.
Index Controller
public IActionResult Index()
{
ViewData["Message"] = "You searched for an invalid word";
return View();
}
Note: It will be redirected when there will be no search result.
Index Chtml
#{
ViewData["Title"] = "Index";
}
<div class="container">
<div class="modal fade" id="samplePopup" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title"> </h4>
</div>
<div class="modal-body">
#ViewData["Message"]
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js"></script>
<script type="text/javascript" language="javascript">
$(document).ready(function() {
$(function () {
$('#samplePopup').modal('show');
});
});
</script>
Pop Up When No Search Results:
Hope it will help you. Let me know if you have any more concern.
Ok So this works fine in a view model but when i move it out to a view component it doesnt.
#foreach (var notes in Model) {
<tr>
<td>#notes.LastModifedDate</td>
<td>#notes.LastModifiedBy</td>
<td>#notes.Notes </td>
<td>
<a class="btn btn-app">
<i class="fas fa-edit"></i> Edit
</a>
|<p>#notes.Id</p> <i class="glyphicon glyphicon-trash"></i>Delete
</td>
</tr>
}
This is my Model in the same view component
<div id="deleteLink" class="modal fade" role="dialog">
<div class="modal-dialog">
#using (Html.BeginForm("DeleteNotes", "MISObjects", FormMethod.Post)) {
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Delete Record!</h4>
</div>
<div class="modal-body">
Are you sure you wish to delete this record ?.
<!--this is how to pass the id through-->
<input type="text" name="linkId" id="linkId" />
</div>
<div class="modal-footer">
<button type="submit" id="btnSubmit" class="btn btn-danger"
onclick="$('#testForm').submit()">
Yes
</button>
<button class="btn btn-warning" data-dismiss="modal">No</button>
</div>
</div>
}
</div>
</div>
Here I am telling it to attach the notes Id here but for some reason its not finding the text field the notes id is being passed through the data-id="#notes.Id" of the button above.
#section Scripts
{
<script>
function deleteModal(id) {
alert(id);
$("#linkId").val(id);
}
function EditModal(id) {
$("#editMode").val(id);
}
</script>
}
I am getting the following error I presume this will be something to do with jquery not ready at this point.
Here is a worked demo to use view component:
TestViewComponent.cshtml:
#{
ViewData["Title"] = "TestViewComponent";
}
<h1>TestViewComponent</h1>
<div>
#await Component.InvokeAsync("Notes", new List<notes> { new notes { Id = "1", Notes = "note1", LastModifedDate = "2020/01/01", LastModifiedBy = "Joy" }, new notes { Id = "2", Notes = "note2" }, new notes { Id = "3", Notes = "note3" } })
</div>
#section Scripts
{
<script>
function deleteModal(id) {
alert(id);
$("#linkId").val(id);
}
function EditModal(id) {
$("#editMode").val(id);
}
</script>
}
Shared/Components/Notes/Default.cshtml:
#model IEnumerable<notes>
#foreach (var notes in Model)
{
<tr>
<td>#notes.LastModifedDate</td>
<td>#notes.LastModifiedBy</td>
<td>#notes.Notes </td>
<td>
<a class="btn btn-app">
<i class="fas fa-edit"></i> Edit
</a>
|<p>#notes.Id</p> <i class="glyphicon glyphicon-trash"></i>Delete
</td>
</tr>
}
ViewComponents/Notes:
public class Notes:ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync(List<notes> list)
{
return View(list);
}
}
Result:
You should use jquery's event binding instead of on click.
First update your anchor tag by adding additional class.
<i class="glyphicon glyphicon-trash"></i>Delete
Then ensure that the #section Scripts block is on the main view not the partial view. Then bind the class using the following
<script>
$(window).on("load", function () {
$(".delete-notes").on('click', function () {
alert($(this).attr("data-id"));
});
function EditModal(id) {
$("#editMode").val(id);
}
})
</script>
In AccountController, I notice that the sample registration code catches UserFriendlyException and returns the error message in the ViewBag.
How can I return it from a SweetAlert?
[HttpPost]
public virtual async Task<ActionResult> Register(RegisterViewModel model)
{
try
{
// Code omitted for brevity
}
catch (UserFriendlyException ex)
{
ViewBag.ErrorMessage = ex.Message; // I need to return this using SweetAlert
return View("Register", model);
}
}
html code
<form action="javascript:;" id="register-form" class="login-form" method="post">
<div class="alert alert-danger display-hide">
<button class="close" data-close="alert"></button>
<span>Enter required fields. </span>
</div>
#if (#ViewBag.ErrorMessage != null)
{
<div class="alert alert-danger">
<i class="fa fa-warning"></i> #ViewBag.ErrorMessage
</div>
<script>abp.message.error("#ViewBag.ErrorMessage");</script>
<input type="hidden" value=" #ViewBag.ErrorMessage" id="hf_error" >
}
<div class="row">
<div class="col-xs-12">
<input type="text" class="form-control form-control-solid placeholder-no-fix form-group" autocomplete="off" name="name" placeholder="#L("Name")" required autofocus id="name">
</div>
<div class="col-xs-12">
<input class="form-control form-control-solid placeholder-no-fix form-group" type="text" autocomplete="off" placeholder="#L("Surname")" name="surname" required id="surname" />
</div>
<div class="col-xs-12">
<input type="password" class="form-control form-control-solid placeholder-no-fix form-group" autocomplete="off" name="password" placeholder="#L("Password")" required autofocus id="password">
</div>
</div>
<div class="row">
<div class="col-sm-6 text-left">
<div class="forgot-password" style="margin-top: 5px;">
Login To Your Account
</div>
</div>
<div class="col-sm-6 text-right">
<button class="btn green" id="btnSubmit" type="submit">Register</button>
</div>
<hr />
</div>
</form>
jquery function below
var jsonObject = {
Name: name,
Surname: surname,
//EmailAddress: email,
// UserName: username,
Password: password
};
abp.ajax({
url: abp.appPath + 'Account/Register',
type: 'POST',
data: JSON.stringify(jsonObject)
}).done(function(data) {
alert("done");
}).fail(function(data) {
alert("fail");
});
Since that method returns a View result, it makes sense to use ViewBag for the error message.
To show a SweetAlert, add the following in #section Scripts in Register.cshtml:
#section Scripts {
// ...
#if (ViewBag.ErrorMessage != null)
{
<script>abp.message.error("#ViewBag.ErrorMessage");</script>
/*<script>swal("#ViewBag.ErrorMessage", "", "error");</script>*/
}
}
Both <script> tags trigger identical popups.
I have a textbox that when the user enters a string and presses a button this is then compared to find which matching fields are in database. I also have another button that launches the display of a bootstrap modal which then views the results.
The issue I'm having is I only want one button but when I try to combine the two i get the modal and the string search never happens.
Can anyone tell me how I combine the two ?
Button 1 (search string button)
#using (Html.BeginForm("Index", "Home", FormMethod.Get))
{
<p>
<label for="platform" class="control-label">Enter Code:</label><br />
#Html.TextBox("filtername")
<input type="submit" value="Filter" "/>
</p>
}
Button 2 (Activates modal but no data comparision)
<div class="form-group">
<div class="col-xs-offset-2 col-xs-10">
<div class="span7 text-center">
<input type="text" class="form-control" id="theCode" placeholder="Please Enter Code">
<input type="submit" value="Go!" class="btn btn-success" id="sendcoderequest" data-toggle="modal"
data-target="#basicModal2" />
</div>
</div>
</div>
Home/Index Method:
public ActionResult Index(string filtername)
{
var filterresults = from m in db.UserInfoes
select m;
filterresults = filterresults.Where(x => x.UserCode.ToString().Contains(filtername)).OrderBy(x => x.UserCode);
return View(filterresults);
}
Modal :
<div class="modal fade" id="basicModal2" tabindex="-1" role="dialog" aria-labelledby="basicModal" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Summary</h4>
</div>
<div class="modal-body">
<h2>Results</h2>
<span id="printCode"></span><br />
<div class="pull-right"><button type="submit" class="btn btn-success" id="toggle">Toggle</button> </div>
<table class="table">
<thead>
<tr>
<th></th>
<th>Date</th>
<th>Test Type</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
<input type="checkbox" class="checks">
</td>
<td>
#Html.DisplayFor(modelItem => item.CreationDateTime)
</td>
<td>
#Html.DisplayFor(modelItem => item.AppModeId)
</td>
</tr>
}
</tbody>
</table>
Code currently working with:
Form:
<form id="formid">
<label for="platform" class="control-label">Enter Code:</label>
<input type="text" name="filtername" />
<input type="submit" class="btn btn-success" value="Filter" />
</form>
JQuery:
$("#formid").submit(function () {
$.ajax({
url: "Home",
data: $(this).serialize()
}).done(function (response) {
$('#modal_content').html(response);
$('#basicModal2').modal('show');
});
return false; // prevent the form submission
});
Modal is unchanged.
You could use an AJAX call instead of the form submission. Then you could open the modal via Javascript once you receive the AJAX response. According to the tags, you're probably using JQuery, so it would look like this :
$("form").submit(function(){
$.ajax({
url: "Home",
data: $(this).serialize()
}).done(function(response){
// Fill your modal window with the response here
$('#basicModal2').modal('show');
});
return false; // prevent the form submission
});
Edit
You can find here an example that uses AJAX to send the filter name to the server, fill the modal with the server response and finally show the modal:
http://jsfiddle.net/yohanrobert/e3p4yv55/
I have a single asp.net page it contains a number of tabs and a datetime picker.
When the user selects a date from the datetime picker and clicks on the update button it does that it should do but it does not return the user to the same tab.
HTML Code
<ul class='tabs'>
<li><a href='#tab1'>Production</a></li>
<li><a href='#tab2'>Page2</a></li>
<li><a href='#tab4'>Page3</a></li>
<li><a href='#tab6'>Page4</a></li>
</ul>
<div id='tab1'>
<hr />
<div class="ProductionDiv">
<label class="ProductionLabel">Production Data</label>
#{
using (Html.BeginForm("UpdateProductionData", "Home", FormMethod.Post))
{
<h3>Date :</h3> <input type="text" id="dp4" name="dp4"/>
<input type="submit" value="Update"/>
}
}
</div>
<div id='tab2'>
<hr />
<div class="ProductionDiv">
<label class="ProductionLabel">Production Data</label>
#{
using (Html.BeginForm("UpdateProductionData", "Home", FormMethod.Post))
{
<h3>Date :</h3> <input type="text" id="dp4" name="dp4"/>
<input type="submit" value="Update"/>
}
}
</div>
<div id='tab3'>
<hr />
<div class="ProductionDiv">
<label class="ProductionLabel">Production Data</label>
#{
using (Html.BeginForm("UpdateProductionData", "Home", FormMethod.Post))
{
<h3>Date :</h3> <input type="text" id="dp4" name="dp4"/>
<input type="submit" value="Update"/>
}
}
</div>
<div id='tab4'>
<hr />
<div class="ProductionDiv">
<label class="ProductionLabel">Production Data</label>
#{
using (Html.BeginForm("UpdateProductionData", "Home", FormMethod.Post))
{
<h3>Date :</h3> <input type="text" id="dp4" name="dp4"/>
<input type="submit" value="Update"/>
}
}
</div>
C# code
I do what i need to do and return to the Index form is there any way to specify what tab to return too.
return View("Index");
How about using hidden field + jquery, like this:
Update your ViewModel and add an int property for example LastTabIndex, then Add a hidden field to your form:
#Html.HiddenFor(m=>m.LastTabIndex)
and then use jquery :
<script type="text/javascript">
$(function() {
$(".tabs").tabs({
create: function() {
var index = 0;
if (Modernizr.localstorage) {
if (localStorage.getItem("LastTabIndex") === null) {
localStorage.setItem("LastTabIndex", 0);
} else {
index = localStorage.getItem("LastTabIndex");
}
} else {
index = $('#LastTabIndex').val();
}
$(".tabs").tabs("option", "active", index);
},
activate: function() {
var sel = $('.tabs').tabs('option', 'active');
$("#LastTabIndex").val(sel);
if (Modernizr.localstorage) {
localStorage.setItem("LastTabIndex", sel);
}
}
});
});
</script>
EDIT: I've updated my code to use a hybrid solution (localstorage and if local storage is unsupported then use hidden field).
Hope this helps!
Regards,
Uros