This question already has answers here:
Event handler not working on dynamic content [duplicate]
(2 answers)
Closed 8 years ago.
I have the body of a table which is appended dynamically with ajax to the table element through a partial view in ASP.NET MVC. The partial view looks something like this...
#model IEnumerable<Plan>
#{
Layout = null;
}
#foreach (var plan in Model)
{
<tr>
<td>
#plan.Name
</td>
</tr>
}
...and appended to the table element which is static in the main View...
<table id="myPlanTable">
</table>
I am trying to register an onclick event for each of these anchor elements (there are a lot currently), using the jQuery on() function like this...
jQuery('#myPlanTable').on('click', 'tbody > tr:gt(0) > td > a.jumpToMyPlans', function () {
console.log('click');
});
...but the event refuses to fire. I've checked the DOM traversal in the browser console and it's definitely correct and returns the expected DOM set.
This selection statement worked for me....
jQuery('#myPlanTable').on('click', 'tr:gt(0) > td > a.jumpToMyPlans', function () {
console.log('click');
});
I think the problem was specifying tbody in the selector, which I guess is probably also dynamically generated, though not by me, I guess by the browser or something.
When partial view is render through ajax or jquery then to bind Jquery events use "live" as following:
jQuery('#myPlanTable').live('click', 'tbody > tr:gt(0) > td > a.jumpToMyPlans', function () {
console.log('click');
});
Try this:
jQuery('#myPlanTable').on('click', 'tbody > tr:gt(0) > td > a.jumpToMyPlans', function () {
console.log('click');
});
1) Change a.jumpToMyActionPlans to a.jumpToMyPlans
2) Add ); to close your click handler
I tested this and the click worked:
$(document).on('click', '#myPlanTable a.jumpToMyPlans' , function () {
alert('click');
});
the html i used to test it was:
<table id="myPlanTable">
<tr>
<td>
PAPA
</td>
</tr>
<tr>
<td>
Sapo
</td>
</tr>
</table>
Hope this helps you!
Related
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>
}
}
}
Hi I want to access text present in all section of my application. I cannot use id because in one application there are different tables with different id's. I want to access text name whenever I place mouse on that td cell irrespective of table so I can't use id. Please suggest me a way to do this using JQuery. The text which I want to access are from asp.net aspx page.
In jquery, you can apply a hover event to every td which fetches it's text. put the text in a variable, then pass it on to your .aspx handler with ajax. here is a simple example. its a good idea to put this script block in your ready function, or near the end of your document.
jQuery
$('td').hover(function () {
//mouse over
//get the data
var tdText = $(this).text();
console.log(tdText);
//do something with the data
var jqxhr = $.ajax("handler.aspx?text=" + tdText)
.done(function () {
console.log("success");
//do something
})
.fail(function () {
console.log("error");
//do something else
});
},
function () {
//mouse out
console.log("mouse-out");
}
);
I can only help you with determining if the mouse cursor is above any td element. You will need to modify the code to fit your needs to display something useful.
HTML:
<p id="message"> </p>
<table>
<tr>
<td>Data 1</td>
<td>Data 2</td>
<td>Data 3</td>
</tr>
<tr>
<td>Data A</td>
<td>Data B</td>
<td>Data C</td>
</tr>
</table>
JS:
addEventListener("mouseover", function(event) {
if (event.toElement.localName == 'td')
$('#message').html("You are in a table cell");
else
$('#message').html(" ");
}, false);
I also created a fiddle for you to test: http://jsfiddle.net/m3EmK/
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);
}
});
I am stuck in a situation, web site is running in ASP.NET 1.1
I am loading a page with some data. In the page there is a Html Table.
In each row, I am loading status(active/inactive) in one and message in another .
There is a save button when clicked it should save the status and message to database.
Since the data is in Html Table I am loosing the data while button is clicked.
I tried one option of keeping the status and message at page load in a global Javascript variable. But I will loose that also when button is clicked.
JS Code to store the data :
// To store all active or inactive feature values.
var arrType = [];
var interiorValues = [arrType];
var exteriorValues = [];
var mechanicalValues = [];
var standardValues = [];
function StoreChromeVallue()
{
var $jDecode = jQuery.noConflict();
var table = document.getElementById('dlInterior');
for (var i = 1, row; row = table.rows[i]; i++)
{
for (var j = 0, col; col = row.cells[j]; j++)
{
var imagePath = $jDecode(row.cells[0]).find('img:first').attr('src');
if(imagePath == "../icon_active1.gif")
{
arrType.push("active");
}
else if(imagePath == "../icon_deleted1.gif")
{
arrType.push("deleted");
}
else
{
arrType.push("active");
}
var featureValue = $jDecode(row.cells[1]).text();
arrType.push(featureValue);
arrType.push("Interior");
interiorValues.push(arrType);
}
}
alert(interiorValues[5][0]);
}
HTML TABLE WHERE DATA IS STORE
<TABLE id="dlInteriors" Width="300" Runat="server" CellSpacing="0" CellPadding="0">
<TR>
<TD id="interiortd" vAlign="top" width="350" runat="server"></TD>
</TR>
</TABLE>
Rows are dynamically added on page load.
Please guide me how I should go ahead on this.
You cant easily get all the values/strings in your HTML page while postback. You could able to get the form fields like input, select, etc in post back using Request.params[""].
But you could try with hidden variable (here it is your alternative Viewstate for your HTML table string values)
When & What you store / how to store /how to access in post back.
You can try the below steps for above question.
Before submit a form, fire a javascript function 'saveTableValues()'
which loops your HTML table and creates the object (var) for each row.
Prepare a javascript object array (just pushing the item in for each loop)
Convert it into JSON string and assign the whole JSON string
into Hidden Field
Do post back // just return true in JS
In code behind try accessing using Request.Params[""] or
normal way like hdnField.Text if it is server side control
In Code behing use a JavaScript Serializer
or JSON.Net to convert the JSON string into some collection.
Recommending JSON.Net here
This may help you.!
Edit:
As your website is running in 1.1 not sure those serializer dll will help you. So you try in XML format instead of JSON. Not sure JSON serializer dll is exist for 1.1 framework
Create table to run at server like this
<table id="users" runat="server">
and you will be able to access it using HtmlTable class,If required create a DataTable dynamically from the table rows and save that in a session. Have a look at http://msdn.microsoft.com/en-us/li
Use Jquery to get the rows values. Then store the data into hiddenfields. This way:
<script type="text/javascript">
function getTableValues() {
var tds = $('#dlInteriors tr td')
jQuery.each(tds, function () {
var url = $(this).children('img:first').attr('src');
var text = $(this).text();
if (url)
$('#hidValuesStatus').val($('#hidValuesStatus').val() + ',' + url);
if (text)
$('#hidValuesMessages').val($('#hidValuesMessages').val() + ',' + text);
});
}
</script>
Call the javascript function on the event "OnClientClick" of your asp:button
<TABLE id="dlInteriors" Width="300" Runat="server" CellSpacing="0" CellPadding="0">
<TR>
<TD id="interiortd" vAlign="top" width="350" runat="server"><img src="icon_active1.gif" /></TD>
<TD id="TD2" vAlign="top" width="350" runat="server">message1</TD>
</TR>
<TR>
<TD id="TD1" vAlign="top" width="350" runat="server"><img src="icon_deleted1.gif" /></TD>
<TD id="TD3" vAlign="top" width="350" runat="server">message2</TD>
</TR>
</TABLE>
<asp:Button runat="server" ID="btnSubmit" OnClientClick="javascript:getTableValues()" Text="SUBMIT" />
<input type="hidden" id="hidValuesMessages" runat="server" />
<input type="hidden" id="hidValuesStatus" runat="server"/>
And in the code behind get the data from the hidden fields:
Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
If IsPostBack Then
If Not IsNothing(Request.Form("hidValuesMessages")) Then
Dim str As String = Request("hidValuesMessages")
End If
If Not IsNothing(Request.Form("hidValuesStatus")) Then
Dim str2 As String = Request("hidValuesStatus")
End If
End If
End Sub
Split the string and get the final values.
Hope this helps!
Regards.
I am having a problem with the <text> tag. The following code will not run due to the </tr> tag near the bottom. If i remove it, it works but it then prints an incorrect table. If i leave it i get the following error: Encountered end tag "tr" with no matching start tag. Are your start/end tags properly balanced?
How can i tell razor to ignore such things?
(I also tried to add a text tag around the /tr and also around all html code but that produces this: Encountered end tag "text" with no matching start tag. Are your start/end tags properly balanced?
#{
int i = 0;
foreach (var item in Model.Model)
{
if (i % 2 == 0)
{
<text><tr class="alternate-row"></text>
}
else
{
<text><tr></text>
}
<td>
<input type="checkbox" />
</td>
<td>
#item.Firstname
</td>
<td>
#item.Surname
</td>
<td>
george#mainevent.co.za
</td>
<td class="options-width">
<a href="" title="Edit" class="icon-2 info-tooltip">
</a><a href="" title="Edit"
class="icon-4 info-tooltip"></a><a href="" title="Edit" class="icon-5 info-tooltip">
</a>
</td>
</tr>
}
}
Update with another question
Why does Razor even test html-tags?
You can do this
<tr#if (i % 2 == 0) { <text> class="alternate-row"</text> }>
or you can set a variable that "holds" your extended html for the <tr> tag like this
int i = 0;
foreach (var item in Model.Model)
{
string ext = "";
if (i % 2 == 0)
{
ext = " class=\"alternate-row\"";
}
<tr#ext>
// ...
Thats the simplest solution, or you can create a custom html helper.
More information: Creating Custom HTML Helpers
Update
Darin said too, what he would create a custom html helper.
I suggest that too, if you need that more than one time.
conclusion
first choice is to create a html helper, second is to use my first
approach (inline if statement) and at last to use a variable.
It does not really depends on "how often" you need that, but if you really need
that only one time, choose the first approach.
Every of the three solutions are correct, its your decision depending on the time
you have.
hope this helps you
<tr#Html.Raw(i % 2 == 0 ? " class=\"alternate-row\"" : "")>
... some tds
</tr>
But personally I would write a custom Html helper to avoid this spaghetti code and have something along the lines of:
#using (Html.Tr(i))
{
<td>
<input type="checkbox" />
</td>
<td>
#item.Firstname
</td>
...
}
I would also refactor and get rid of the foreach loop and replace it with a simple display template call: #Html.DisplayForModel().
I have an alternate approach for you using javascript. Since you are using MVC3, you probably have access to jQuery. Add this little nugget of javascript (See jsFiddle Example)
$(function() {
$('tr:odd').addClass('alternate-row');
})
remove the the <text> blocks from around the tr tag in your conditional