Reputation: 19826
[Sorry for long question but it is necessary to explain the problem]
I am working on a learning website and it is supposed to show a list of messages to user if there are any. Something like this:
When user presses close button, that message must be marked "read" and should not be shown next time. Following code is used to generate those messages:
<% foreach (var m in Model.UserMessages) { %>
<div class="um" id="m<%=Html.AttributeEncode(m.ID) %>">
<p class="mh"><%= Html.Encode (String.Format ("From {0} ({1})", m.From, m.Sent)) %></p>
<p><%= Html.Encode (m.Text) %></p>
<% using (Html.BeginForm ("CloseMessage", "Home", new { id = m.ID })) { %>
<input type="submit" value="Close<%= Html.AttributeEncode (m.ID) %>" id="c<%= Html.AttributeEncode (m.ID) %>"/>
<% } %>
</div>
<% } %>
After that, following the guidelines, I added the support of http post method in controller which marks the message as read and then refreshes the view (to handle disabled JavaScript):
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CloseMessage (int id) {
using (var dl = new DL ()) {
dl.MarkAsRead (id);
}
if (Request.IsAjaxRequest ()) {
return new EmptyResult ();
}
else {
return RedirectToAction ("Index");
}
}
Then I wanted to add JavaScript support such that only the message goes away (using jQuery). But the problem is that I am generating the buttons and messages programmatically.
So ended up with a weird looking javascript code in viewpage:
<script type="text/javascript">
$().ready(function() {
<% foreach (var m in Model.UserMessages) { %>
$("#c<%=Html.AttributeEncode (m.ID) %>").click(function(event) {
$.post("Home/CloseMessage/<%=Html.AttributeEncode (m.ID) %>");
$("#m<%=Html.AttributeEncode (m.ID) %>").slideUp("slow");
event.preventDefault();
});
<% } %>
});
</script>
This is basically creating the javascript code in a C# loop which actually works but too much for me to digest. Is there any better way of doing this?
Upvotes: 0
Views: 1930
Reputation: 16651
You could just create one javascript function that takes the element IDs as parameters :
function myFunction(ID) {
$.post("Home/CloseMessage/" + ID);
$("#m" + ID).slideUp("slow");
}
And :
<% foreach (var m in Model.UserMessages) { %>
<div class="um" id="m<%=Html.AttributeEncode(m.ID) %>">
<p class="mh"><%= Html.Encode (String.Format ("From {0} ({1})", m.From, m.Sent)) %></p>
<p><%= Html.Encode (m.Text) %></p>
<% using (Html.BeginForm ("CloseMessage", "Home", new { id = m.ID })) { %>
<input type="submit" value="Close<%= Html.AttributeEncode (m.ID) %>"
id="c<%= Html.AttributeEncode (m.ID) %>"
onclick="myFunction('<%=Html.AttributeEncode(m.ID)%>')"/>
<% } %>
</div>
<% } %>
Upvotes: 3
Reputation:
I understand its not pretty, but its not that bad either. I think there are easier ways to do this, however.
You can use jquery's positional selectors from the button's click event handler. Then just assign the same handler to every button.
<script type="text/javascript">
$(document).ready(function() {
$("input[type=submit]").click(function(){
$(this).parent().slideup("slow");
$.post("Home/CloseMessage/" + $(this).parent().attr("id"));
event.preventDefault();
});
});
});
</script>
Upvotes: 1
Reputation: 3246
YOu could uses a CSS selector in your JS to get all buttons with a particular class assigned to them. Then you can wire up you click event to them. So your HTML would be something like this:
<% foreach (var m in Model.UserMessages) { %>
<div class="um" id="m<%=Html.AttributeEncode(m.ID) %>">
<p class="mh"><%= Html.Encode (String.Format ("From {0} ({1})", m.From, m.Sent)) %></p>
<p><%= Html.Encode (m.Text) %></p>
<% using (Html.BeginForm ("CloseMessage", "Home", new { id = m.ID })) { %>
<input type="submit" class="MyCloseButton" value="Close<%= Html.AttributeEncode (m.ID) %>" id="c<%= Html.AttributeEncode (m.ID) %>"/>
<% } %>
</div>
<% } %>
I've only added the class="MyCloseButton" to your input
Then in your JS (I use mootools but JQuery has CSS selectors too but you will need to port it sorry) you can do something like this:
window.addEvent( "domready", function() {
$$("input.MyCloseButton").each( function( button ) {
// Add your code here, you can reference button.id etc for each of your buttons
}
});
This way you only have to write out one little function in plan JS and not worry about doing it server-side, all you need to do it decorate your buttons with a css class so the JS can find them.
Upvotes: 2