I'm new to ASP.NET MVC, but I need to perform a search for articles that match a selected category. The results of this query need to be written into a "search results" div overlay with DHTML- jquery, probably.
So, I need the results of an Action, but not to render a view. I was thinking I could use Json and then iterate over the resulting records, somehow.
Or is it easier to use RenderPartial... but how would I use this in this DHTML scenario?
Thanks.
I like the way Steve Sanderson describes in his ASP.NET MVC book. It dosnt work with JSON, but returns a partial. This makes it easier to have both: An Ajax and a non-Ajax version.
The cotroller returns a View or Partial depending on the type of request:
public ActionResult GetArticles(string category)
{
...
if(Request.IsAjaxRequest())
{
return PartialView("ArticleListPartial",articleModel)
}
else
{
return View("ArticleListPage",articleModel)
}
}
The search by default submits the from with with a Non-Ajax post:
<form id="articleSearch" method ="post" action="/Article/GetArticles" >
...
<input type="submit" value="Get the articles!" />
<form>
Then there is a Jquery snippet that kicks in when Javascript is available and submits the request via Ajax
<script language="javascript" >
$(function() {
$("#articleSearch").submit(function() {
$.post($(this).attr("action"), $(this).serialize(), function(modelResponse) {
("#articleResultContainer").html(modelResponse);
});
return false;
});
});
</script>
Hmmm, sounds like you are trying to do a filter?
If this is the case I think it's a bad idea trying to search within your html. I think a better approach would be to post back using jQuery, get your result set from whatever database you are using, and return that back to the view as apartial view.
When you are searching your database you should apply the filter at that point using sql, Linq2Sql or whatever you're using.
If you are still Hell bent on searching the HTML then I'd give each relevant div a class name of say class="DivSearchable". Then in jQuery you can do something like;
$('.DivSearchable").each(function() {
var text = $(this).val();
"Now test text for contents of your seach string"
if (BoolIfFound == true)
$(this).addClass("highlightClassName");
});
highlightClassName would set the background-color to something so you can see which divs contains the search string.
make sense?
Related
We have a very simple MVC form with a dropdownlist which gets the user's selected city.
We have a list of cities and we know the average temperature (say) for each city.
Almost as a decoration (it's not a core function) for the form it would be nice to show the temperature for the selected city as the user changes it. Something like this:
This has to happen client side, I guess. Or is it AJAX?
At the moment our form is mostly out-of-the-box MVC4 EF auto built with scaffolding.
We populate the dropdownlist like so:
In the Controller:
ViewData("Cities") = GetCitySelectList()
and in the View:
#Html.DropDownListFor(Function(model) model.City, TryCast(ViewData("Cities"), SelectList))
... so pretty simple stuff.
There are plenty of tutorials for doing cascading dropdowns which are probably overkill for what we're trying to do here. Also if you google "javascript lookup mvc form" or similar a lot of the results tie you to using a framework (knockout? barebone?) which, again, I'm not familiar with and I don't know if I need for such a simple task.
In fact we're so geared to keeping it simple, and our city list is so short, it's almost worth doing it as a giant if then else in javascript (but, I know, yuk).
What's the simplest way to do this?
You can do it as follows:
Make an Ajax call on change on dropdown and then place the result in the corresponding div.
Html for result:
Temperature:<div id="temp"></div>
Ajax call :
$("#dropdownId").change(function () {
$.ajax({
type: "GET",
url: "Home/GetTemperature", // your url
contentType: "application/json; charset=utf-8",
data : {City : " + $(this).val() +"}
dataType: "json",
success: function (result) {
$("#temp").html(result); // place result in div
},
error: function () {
alert("Error.");
}
});
});
Your Action (C#):
[HttpGet]
public JsonResult GetTemperature(string City)
{
int temp = 30; // Get temp from your db..
return Json(temp,JsonRequestBehavior.AllowGet);
}
Your Action (VB):
<HttpGet>
Public Function GetTemperature(City As String) As JsonResult
Dim temp As integer = 30
Return Json(temp, JsonRequestBehavior.AllowGet)
End Function
You should use AJAX call to the server for the temperature. That's probably the "cleanest" way to achieve what you would like to have on your form.
Option 1: Using jQuery and make ajax call to fetch a temprature for the cityId passed and set the html of the temprature div or span container
Option 2: Eager Load on page as Javascript object
You could have eager load the cities and temprature into the JSON object and store it.
Here is the controller action code using JSON.Net for json serialization
public ActionResult myAction()
{
MyViewModel model=new MyViewModel();
List<City> cities=new List<City>();//fill the city id, temp
MyViewModel.CityJSON=JsonConvert.SerializeObject(List<City>);
return View(model)
}
View
#model MyViewModel
// other controls
#Html.HiddenFor(m=>m.CityJSON, new{#id='hdn-city-json'})
JavaScript
var cityList=JSON.parse($('#hdn-city-json')); // returns array of city obj
//do your stuff
If you are trying to avoid unneccesary requests to server, yes, you could eager load the whole collection. You can keep the data in a hidden <ul/> tag that you build on your View. Then, you can use jQuery to fire when the dropdown selection changes. But instead of making an AJAX call, you can lookup the temperature in the list instead and set the content of the target div to the return value of the lookup function.
Is it possible to force an #Html.ActionLink() to do a POST instead of a GET? If so, how?
ActionLink helper method will render an anchor tag, clicking on which is always a GET request. If you want to make it a POST request. You should override the default behviour using a little javacsript
#ActionLink("Delete","Delete","Item",new {#id=4},new { #class="postLink"})
Now some jQuery code
<script type="text/javascript">
$(function(){
$("a.postLink").click(function(e){
e.preventDefault();
$.post($(this).attr("href"),function(data){
// got the result in data variable. do whatever you want now
//may be reload the page
});
});
});
</script>
Make sure you have an Action method of HttpPost type to handle this request
[HttpPost]
public ActionResult Delete(int id)
{
// do something awesome here and return something
}
I suppose that if you need something like that is for an Action that will be doing something "permanent" on server side. For instance, deleting an object in database.
Here is a complete example of doing a delete using a link and posting:
http://www.squarewidget.com/Delete-Like-a-Rock-Star-with-MVC3-Ajax-and-jQuery
From the previous link (recomended reading anyway):
A delete link in your view:
#Ajax.ActionLink("Delete", "Delete", "Widget",
new {id = item.Id},
new AjaxOptions {
HttpMethod = "POST",
Confirm = "Are you sure you want to delete this widget?",
OnSuccess = "deleteConfirmation"
})
A bit of JS:
function deleteConfirmation(response, status, data) {
// remove the row from the table
var rowId = "#widget-id-" + response.id;
$('.widgets').find(rowId).remove();
// display a status message with highlight
$('#actionMessage').text(response.message);
$('#actionMessage').effect("highlight", {}, 3000);
}
What I would do is wrap your html around a form
#using(Html.BeginForm("YourAction","YourController", FormMethod.Post)){
<button>Hello</button>
}
Instead of using a link you might want to use a button.
If you really want to use a link, you might need some javascript
Something like this:
$("#idOfYourLink").click(function(){
var form = $(this).parents('form:first');
form.submit();
});
It's not possible to have a <a> element perform a POST to a web server.
You can use Javascript to capture the click event, stop the navigation, and perform an AJAX POST to the server, but if the user has Javascript disabled nothing will happen.
Do you have to use a <a> element, or just something that resembles a <a> element?
Also worth mentioning is to have a look at AjaxLink. It allows you to easily use a <a> element to perform an AJAX POST.
If you think... there is no tag for link in HTML that does a POST. And that's why you can't force a link to do a POST (and it doesn't make any sense).
To use "POST", ou should "POST" something. And that something should be a form, or you can do a POST using a javascript function for AJAX.
Anyway, if you need to POST without post anything you should review your resourcemodel, something stinks.
Let's say I have a partial view X.ascx like this:
<div id = "updateTargetIdForAjaxForm">
... javascript code which only has function definitions.
... ajax form with buttons inside
<div id = "stuff"></div>
<script type = "text/javascript">
do things to "stuff" div as soon as X.ascx is loaded.
</script>
</div>
Now I want to update things on X.ascx, based on Ajax response. Earlier, I was returning PartialView but inline javascript that does things to stuff div wouldn't like that, meaning the inline javascript just won't get executed when X.ascx is reloaded.
So is there a way I can not return PartialView in my controller, but just update ViewData values and tell the PartialView to re-grab the updated ViewData values? And also call one or two javascript functions based on the response from server maybe?
I see two possible ways to go:
Fixing your javascript code to run with dynamically loaded partial view:
http://api.jquery.com/live/
http://api.jquery.com/delegate/
These two should help you out.
The other way is to create an action on your controller that would return JSON result and from jQuery you should be able to handle JSON object and update your form. Your Action could look like :
public JsonResult GetFormValues()
{
var jsonFormValues = new
{
key1 = "abc",
key2 = "123",
key3 = "abcdef"
};
return Json(jsonFormValues, JsonRequestBehavior.AllowGet);
}
and check out http://api.jquery.com/jQuery.getJSON/ on how to handle the result
I'm new to web programming in general so this is probably a really simple question. I couldn't find anything on the web however.
What I want to do is call my controller with the typed search string and return the results from a database and paginate the results. Right now I am using a function that is called when the button is pressed. The function looks like so:
function SubmitSearch() {
var searchBox = document.getElementById('searchBox');
var searchButton = document.getElementById('SearchButton');
$.post("MyController/MyAction/",
{
searchString: searchBox.value,
page: null
}, function(result) {
$('#searchResults').html(result);
searchButton.value = "Search";
});
}
What happens is my controller is called, and my searchResults div is populated with the results and paginated. The user can click any search result returned to view the details.
The problem is when the user clicks the browsers 'back' button, the page returns to the state before the search was entered, and this is because of the ajax call. What I want to do is, call the controller and have the page load like google would. Instead of using a PartialView, I would use a View (my guess).
How would I call the controller and have the page RELOAD with the results. I must be missing something fundamental because this definitely seems like it should be easy.
If you don't want to use AJAX then you need to place your text field in a form element on your page, something like:
<form action="MyController/MyAction/" method="get">
<input id="SearchBox" name="SearchBox" type="text" />
<button type="submit">Search</button>
</form>
Then in your controller return the view with the list of results.
You probably also want to look into RESTful URLs and the PRG (Post, Redirect, Get) pattern to maintain the integrity of the back button and enable correct bookmarking of pages etc.
I think you might actually be looking for an AJAX History library to help when the Back button is pressed rather than altering your app. Take a look at this blog post.
Aspx:
<% using (Html.BeginForm<MyController>(m => m.MyAction(null)) { %>
<%= Html.TextBox("q"); %>
<% } %>
// Listing
Controller:
public class MyController : Controller
{
public ActionResult MyAction(string q)
{
var repository; // instance of your repository.
if (String.IsNullOrEmpty(q))
{
return View(repository.GetAllBlogs());
}
return View(repository.SearchBlogs(q));
}
}
I'm starting to learn ASP.Net MVC (the release candidate), and I'm having a little trouble. I might just be being picky, but I thought I'd ask.
I want to use the built-in (extended) ASP.Net Ajax methods to make a call to my controller, called "GetNames," that returns a JsonResult object. I've seen examples that use the $.getJSON() jQuery method, but I would instead prefer to do something like this:
<%using ( Ajax.BeginForm("GetNames", new AjaxOptions() { OnSuccess = "GetNamesSuccess", OnBegin = "GetNamesBegin", OnComplete = "GetNamesComplte", OnFailure = "GetNamesFailure" } ) ) { %>
<%=Html.TextBox("DummyData") %>
<input type=submit />
<% } %>
<script type="text/javascript">
function GetNamesSuccess()
{
alert("Success");
}
function GetNamesBegin()
{
alert("Begin");
}
function GetNamesComplete()
{
alert("Complete");
}
function GetNamesFailure()
{
alert("Failure");
}
</script>
When I click the Submit button, I get none of the alerts, and I get prompted to download a file containing the text of Json object, which I believe indicates that at least the controller method is working fine. But that's not the intended behavior for me... Ideally, Ajax.BeginForm would set it up such that the Json object would get passed to either the OnSuccess or the OnComplete method.
Is there a way to accomplish that?
Have you included both the MicrosoftAjax.js and MicrosoftMvcAjax.js javascript files in your view page? It sounds to me like it is actually posting the form instead of using Ajax. I've had this problem when I was missing the MicrosoftAjax.js include because the Ajax postback failed due to missing javascript classes and thus it invoked the normal form post.
On a related note, you should check to see if the request is Ajax or not in the controller and return a ViewResult (or Redirect) instead of Json if it's not. If someone has javascript turned off or you have errors on your page you want it to gracefully degrade and handle it as a normal postback rather than return Json.