MVC Hover Over Item in View to render View - c#

I have this fiddle here. It demonstrates a hover over and a box appearing with info in it.
What I'm trying to achieve is, when the "View Details" is hovered over, it triggers the MVC action Details(guid Id) and the result of that action is rendered in the box.
I'm not entirely sure how to do this. I would assume that a AJAX form is submitted on hover, so this will need to be done by JS (I really don't know how to do AJAX with JS). Then the div would be displayed with a newly rendered #Html.Action("Detail", "Stuff", new { Id = #item.Model.Id })
Am I close?
The View would be something like this
<table>
<thead>
<tr>
<td>Name</td>
<td>E-mail</td>
</tr>
</thead>
<tbody>
#foreach (var item in Model.ItemList)
{
<tr>
<td>#Html.DisplayFor(model => item.Name)</td>
<td>#Html.DisplayFor(model => item.Email)</td>
<td>#using(Ajax.BeginForm(ajaxOpts))
{
<span>Hover for Details</span>
#Html.HiddenFor(model => item.Id)
}
</td>
</tr>
}
</tbody>
</table>
The action would purely be:
[ChildActionOnly]
public ActionResult Detail(Guid id)
{
var item = _repository.Stuff.FirstOrDefualt(x => x.Id.Equals(id));
return View(item);
}
So the specification is:
When "Hover for Details" has been hovered to show a box where the cursor is displaying the recently got details from the database
I've wrote this all off the top of my head, so don't scrutinise it for accuracy, its purely to demonstrate an idea, i'm not looking for errors in my code. I'm looking for ideas with valid working examples. Thanks.

1) Submit Ajax on Hover.
2) Follow the example here Render a view as a string to render your view as a HTML string within the server.
3) Use $("#showme").html(ReturnedHTMLData); to place the returned html into the DOM object.
i.e. server side
public JsonResult GetDetail(Guid id)
{
return Json(ViewToStringMethod(ViewName, id), "rest of Json allowget stuff");
}
i.e. Client side
$("#DomElement").on("hover", function(){
$.getJSON("GetDetail", {id: $('this').attr("id"), function(returnedData){
$("#showme").html(ReturnedHTMLData);
}
});

Related

Asp.net MVC Razor #foreach + onclick the data gets listet

I'm working on a Project Tool that lists all the Projects on the Dashboard. Now I want that when I click on the Project that the Data from my Database gets listed on the right site of it.
Problem 1
Code:
#foreach (var item in Model)
{
<tbody>
<tr>
<td>Project Titel</td>
<td>#item.PrjTitel</td>
</tr>
</tbody>
}
With this all the Database Data gets listet, but i just want the Data from one Project not from Project 1,2,3 listet.
How can i make that ?
Problem 2
How can i make that the Data gets listet when the User clicks on a Project.
So if i click on Project 2 the data from Project to gets listet on the right site. See Screenshot -->
Screenshot of the front page
#foreach (var item in Model.Projects) {
<tbody>
<tr>
<td>#Ajax.ActionLink("Select","SelectProjects",new { #id=item.ProjectId},new AjaxOptions { HttpMethod="GET",OnSuccess="LoadProjectsSuccess", OnFailure="LoadProjectsFailur",InsertionMode=InsertionMode.Replace,UpdateTargetId= "Projects" },new { #class="btn btn-info btn-table"})</td>
</tr>
</tbody>}
<div class="row row-equal" id="Privileges"><div>
you can use AjaxHelper if you don't have any information about ajax helper please visit Ajax Helper
public ActionResult SelectProjects(int id)
{
DemoViewModel model = new DemoViewModel()
{
// Your ViewModel
};
return PartialView("_ProjectDetails", model);
}
_ProjectDetails Partial View with data you wont to update

MVC ajax update partial result from inside

I have a view Index which has a partial view GetAlertData referenced inside:
Index.cshtml
<table>
<thead>
<tr>
<th>Date</th>
<td>Message</td>
<td>Type</td>
<td>Actions</td>
</tr>
</thead>
<tbody id="tableBody">
#Html.Action("GetAlertData", new { selectedAlertType = Model.SelectedAlertType })
</tbody>
</table>
GetAlertData.cshtml
foreach (var alert in Model.UserAlerts)
{
<tr>
<td>
#alert.Date.ToString("d")
</td>
<td>
#alert.Message
</td>
<td>
#alert.AlertTypeName
</td>
<td>
#Ajax.ActionLink("Dismiss", "Dismiss", new { userAlertID = alert.UserAlertID }, new AjaxOptions() { HttpMethod = "Post" })
</td>
</tr>
}
Controller code
public PartialViewResult GetAlertData(string selectedAlertType = "All")
{
//create viewModel
return PartialView(viewModel);
}
[HttpPost]
public ActionResult Dismiss(int userAlertID)
{
alertModel.DismissAlert(userAlertID);
return RedirectToAction("Index"); //does nothing, because ajax (?)
}
The problem is this: I want the "parent" view to refresh the data from the "GetAlertData" Html.Action after clicking Dismiss. How can I get the "parent" view to rerun the GetAlertData after an alert is Dismissed? Returning a RedirectToAction does nothing because it's an ajax call.
I know I could set up a javascript method in the parent view, and then call that in the OnSuccess in the Dismiss ajax call, but that seems kinda messy and I was wondering if there's anything in the MVC framework or helper methods that would help me do this.
There's only two ways to update page content with something from the server: 1) Reload the entire page or 2) AJAX.
If you want to just update a portion of your page without causing a reload, then you must use AJAX to request some action that will return the information you desire and then JS to replace the portion of the page in the DOM. Since this is about essentially reloading a partial, you'll need an action that returns that partial. Also, since you're already using a child action, the same action can be used for this as well. Just make sure to remove [ChildActionOnly], if present, so the action is exposed to the routing framework.
If you move the ActionLink to a jQuery/Javascript click event then you can call the Dismiss from there returning a success/error flag. If the Dismiss was successfull then call the GetAlertData method with another Ajax call and use the returned HTML to replace the table body. You may need to make some other changes.
I solved this problem. I changed the redirect action from "Index" to "GetAlertData", and set the UpdateTargetId option to the same as it is in the parent view. After clicking the dismiss button, it replaces the content of the partial view with the new result.
The only thing that is smelly to me about this answer is that I have to reference the id of an element in the parent view ("tableBody"). I tried to wrap the whole child view in a div and replace that, but that resulted in the duplication and poor formatting. That might be partially because <table><div><tr> isn't exactly valid HTML.
New Child view code:
#{
var ajaxOpts = new AjaxOptions()
{
UpdateTargetId = "tableBody",
HttpMethod = "Post",
};
if (Model.UserAlerts != null)
{
foreach (var alert in Model.UserAlerts)
{
<tr>
<td>
#alert.Date.ToString("d")
</td>
<td>
#alert.Message
</td>
<td>
#alert.AlertTypeName
</td>
<td>
#Ajax.ActionLink("Dismiss", "Dismiss", new { userAlertID = alert.UserAlertID }, ajaxOpts)
</td>
</tr>
}
}
}

Populate table with MVC on submit

I am learning MVC by converting an old Web Form to MVC 5. The page is pretty simple, just a few text boxes, a submit button and a grid. I want similar functionality where there is no grid on page load, and after the submit takes place, the grid appears. The issue I am having is all the examples I have seen contain the data coming at page load.
Here is my View
<h2>Search Craigslist</h2>
#using (Html.BeginForm())
{
<p>
Enter Search Criteria:<br />
#Html.TextBox("Criteria", null, new { #style = "width: 450" })
#Html.DropDownList("DropDownValues")
Days:
#Html.TextBox("Days")
<br />
<input type="submit" value="Submit" />
</p>
}
#Html.Partial("~/Views/Search/_Search.cshtml")
and the partial
#model IEnumerable<CraigsListSearch.MVC.Models.SearchModel>
#{
Layout = null;
}
<table cellspacing="0" border="1" style="border-collapse:collapse;">
<tr>
<th>
#Html.DisplayNameFor(model => model.Location)
</th>
<th>
Link
</th>
<th>
#Html.DisplayNameFor(model => model.DateSubmitted)
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Location)
</td>
<td>
#Html.Hyperlink(Html.DisplayFor(modelItem => item.URL).ToString(), Html.DisplayFor(modelItem => item.Title).ToString())
</td>
<td>
#Html.DisplayFor(modelItem => item.DateSubmitted)
</td>
</tr>
}
and finally the controller
public class SearchController : Controller
{
[HttpGet]
//public ViewResult Index(string DropDownValues, string Criteria, string Days)
public ViewResult Index()
{
Populate();
Session["list"] = SearchModel.GetQuickList();
return View(new List<SearchModel>());
}
[HttpPost]
public ViewResult Index(string DropDownValues, string Criteria, string Days)
{
Populate();
Criteria = Server.UrlPathEncode(Criteria).Replace(",", "%2c");
List<Location> list = (List<Location>)(Session["list"]);
List<SearchModel> results = SearchModel.Search(Criteria, Days, DropDownValues, list.Take(5).ToList());
return View(results);
}
private void Populate()
{
List<DropDownModel> ddlList = DropDownModel.GetDropdowns();
ViewBag.DropDownValues = (from a in ddlList
select new SelectListItem
{
Text = a.Text,
Value = a.Value
}).ToList();
}
}
What I am looking for is to have the partial only be "called" on POST. Is this something that can easily be done? Let me know if other info is needed.
Thanks!
There are a couple of ways you could approach solving this problem.
One option would be to use AJAX. When the user clicks the button make an AJAX call to the controller and have the controller render the partial and return the HTML which you then inject into the page DOM.
Another option is to add a "DisplayGrid" property to your model. When you first render the View set it to false and then set it to true after the post.
One point I want to make is that rendering a View from the Post action isn't a great idea. If the user hits Refresh in their browser it's going to post again, giving the user that annoyingly ugly dialog that tells them they're going to send data to the server. In general you should use a Post-Redirect-Get pattern, the user posts, you redirect, and then you use a get to re-render in the browser. If you use the AJAX approach this all becomes moot because you never post the whole form back to a controller action. If you continue to use a full post the HttpPost version of Index should return a RedirectToAction result sending the user back to the Get version of Index. You can communicate between the two actions by using TempData, for example:
[HttpGet]
public ActionResult Index()
{
if( TempData.ContainsKey( "DisplayGrid" )
{
// Use the other values from TempData to populate the model with the grid data
myModel.DisplayGrid = (bool)TempData["DisplayGrid"];
}
}
[HttpPost]
public ActionResult Index( string dropDownValues, string criteria, string days )
{
TempData["DisplayGrid"] = true;
TempData["DropDownValues"] = dropDownValues;
TempData["Criteria"] = criteria;
TempData["Days"] = days;
return RedirectToAction( "Index" );
}
You should pass whatever information you need to render view via model (or ViewBag).
Since you already have sample of how to use Model here is how you can use ViewBag
#if(ViewBag.RenderSearch)
{
#Html.Partial("~/Views/Search/_Search.cshtml")
}
And set RenderSearch in particular action:
public ViewResult Index(string DropDownValues...
{
....
ViewBag.RenderSearch = true;
With model just add property to your model (you'd need to make it custom class instead of just List) and check that flag instead.
Try This, the Ajax only replace the GridDiv only
<h2>Search Craigslist</h2>
using (Ajax.BeginForm("BindGridAction", "Contoller",new AjaxOptions { UpdateTargetId = "GridDiv" }))
{
<p>
Enter Search Criteria:<br />
#Html.TextBox("Criteria", null, new { #style = "width: 450" })
#Html.DropDownList("DropDownValues")
Days:
#Html.TextBox("Days")
<br />
<input type="submit" value="Submit" />
</p>
}
<div id="GridDiv">
#Html.Partial("~/Views/Search/_Search.cshtml")
</div>
Bind your partial view in controller
public PartialViewResult BindGridAction()
{
// your model coding
return PartialView("~/Views/Search/_Search.cshtml", model);
}

.NET MVC 4 - Button actions in a foreach loop

I've currently got a View like this:
#using (Html.BeginForm("Compare", "Carousel", FormMethod.Post))
{
#foreach (var product in Model.Products)
{
<tr>
<td>#product.Provider.Name</td>
<td>£#Math.Round(product.MonthlyPremium, 2, MidpointRounding.AwayFromZero)</td>
<td>#Html.ActionLink("More Details", "MoreDetails", new { id = product.ProductId })</td>
<td><button name="compare" value="#product.ProductId">Compare</button</td>
</tr>
}
}
Controller:
[HttpPost]
public ActionResult Compare(ProductsWithDetailModel model) // This is a guess, Model may not persist?
{
// Code here
return View("Index", model);
}
What I actually want is, when a button is clicked, the Controller is going to be called and the product that has been selected (the button clicked) will be added to a list of items.
How do I actually find out which button has been clicked in the Controller? How come I cant find any tutorials out there on the web that have done this before, surely its basic functionality? Or am I approaching it wrong?
ASP.NET MVC takes all inputs and send it by a verb to an action. The bind of these controls is made by the name attribute on your View and the value is made by depending of what control we are talking about (text, checkbox, radio, select, button etc...). You could have a a property on your ProductsWithDetailModel called compare and it would recevie the value of the button you've clicked.
How about having 1 form per item?
E.g.
#foreach (var product in Model.Products)
{
<tr>
<td>#product.Provider.Name</td>
<td>£#Math.Round(product.MonthlyPremium, 2, MidpointRounding.AwayFromZero)</td>
<td>#Html.ActionLink("More Details", "MoreDetails", new { id = product.ProductId })</td>
<td>
#using (Html.BeginForm("Compare", "Carousel", FormMethod.Post))
{
<input type="hidden" name="productId" value="#product.ProductId" />
<button name="compare">Compare</button>
}
</td>
</tr>
}
use onclick. set js hidden value in loop. in controller check.

Dynamically load data with #Ajax.ActionLink using Skip() and Take()

I am new to ASP.NET MVC, so please help me to solve this, at a first glance, simple issue.
I have a table of students on my View and a Load More link below it. By clicking on this link I need to load more students records with AJAX.
So this is my View (omitted unnecessary data)
<table id="studentTable">
<thead>
...
</thead>
<tbody>
#Html.Partial("_StudentDetailsList", Model)
</tbody>
</table>
#Ajax.ActionLink("Load More", "LoadMoreStudents", new AjaxOptions
{
HttpMethod = "POST",
InsertionMode = InsertionMode.InsertAfter,
UpdateTargetId = "studentTable"
})
_StudentDetailsList partial view to display students
#model IEnumerable<MvcApplication1.Models.Student>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.FirstName)
</td>
</tr>
}
action
public ActionResult LoadMoreStudents(int skip = 0)
{
return PartialView("_StudentDetailsList", studentRepository.Get(orderBy: s => s.OrderBy(st => st.FirstName).OrderBy(st => st.LastName)).Skip(skip).Take(10));
}
So as you can see, I want to load next 10 students every time, but I have to know how much are already loaded. So the question is: from where should I get this skip parameter which I want to pass to the Action from the View. How can I count on the View how many partial views are already loaded and how many students each partial has? Or is it a bad practice to pass this parameter to action, maybe I should handle it somewhere else (e.g. some service)? Please advice the right way to do this. Thanks.
P.S. Please feel free to edit the caption as I can't come up with appropriate one.
The easiest method would be to create a ViewModel that contains these variables for you.
ViewModel
public class YourViewModel(){
public int skip {get;set;}
public IEnumerable<StudentDetails> StudentDetailList {get;set;}
}
The Controller/Action Method
public ActionResult LoadMoreStudents(int skip = 0)
{
return PartialView("_StudentDetailsList", new YourViewModel{
StudentDetailList = studentRepository.Get(orderBy: s => s.OrderBy(st => st.FirstName).OrderBy(st => st.LastName)).Skip(skip).Take(10),
skip = skip + 10});
}
The View
#Html.Partial("_StudentDetailsList", Model.StudentDetailList)
The Partial View
#model MvcApplication1.Models.YourViewModel
<table id="studentTable">
<thead>
...
</thead>
<tbody>
#foreach (var item in Model.StudentDetailList)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.FirstName)
</td>
</tr>
}
</tbody>
</table>
#Ajax.ActionLink("Load More", "LoadMoreStudents", new {skip = Model.skip}, new AjaxOptions
{
HttpMethod = "POST",
InsertionMode = InsertionMode.InsertAfter,
UpdateTargetId = "studentTable"
})
Basically, you have to be able to dynamically update the Ajax.ActionLink with values coming back from the controller. Here, I have moved it into the PartialView (arguabley you could move the entire table including the fetch more link into the PartialView and have it be even cleaner).
You are on the way. You should replace the Ajax.ActionLink for a link with $.get, and retrieve the skip by counting the numbers of rows at the tbody that you already have:
First replace the ActionLink for:
Load More Students here!
Second, create this function to do the get:
$('mylink').click(function (e) {
e.preventDefault();
//Gets the number of rows that you alredy have loaded
var rowCount = $('studentTable').find('tbody > tr').length;
//The URL for the get, with the number of rows
var url = "http://www.myurl.com/controller/action?skip=" + rowCount;
$.get(url, function (data) {
//Append the content from the partial view to the tbody
$('studentTable').find('tbody').append(data);
});
});
I think that this is a good way as well!
Hopes this help you!

Categories