• Coding
  • [jQuery] Opening the corresponding Conversation in a Modal Box

I am using @Darin Dimitrov's method explained in Loading a partial view in jquery.dialog to allow users to click on one of their Private Messages and view it inside a modal box. I am using ASP.NET MVC3 and Razor as my view engine. But I'm having some trouble getting this to work... Below is what I've attempted so far:

The messages are displayed in a table:
<tr id="@item.Id" class="openConversationLink">
    <td class="newMessageStatus">@MessageStatus(item)</td>
    <td class="msgSenderName">@item.Sender</td>
    <td class="msgSubject">@item.Subject</td>
    <td class="msgLastUpdated">@item.LastUpdated</td>
    <td class="modalItemActions"></td>
</tr>
And inside the same partial view, I got the following script block:
<script type="text/javascript">
    $(function () {
        $("#conversationModal").dialog({
            autoOpen: false,
            width: 850,
            height: 600,
            resizable: false,
            draggable: false,
            modal: true,
            open: function (event, ui) {
                var convId = event.target.attr('id');
                alert(convId);
                $(this).load('Message/Conversation/' + convId);

            }
        });

        $(".openConversationLink").click(function () {
            $("#conversationModal").dialog('open');
        });
    });

</script>
Basically, I'm not sure what the event and ui parameters inside the open handler refer to. So a little explanation on both would be appreciated. I am getting the following error:
Compiler Error Message: event.target.attr('id') is not a function
//I also tried ui.attr('id') and got the same error
Basically, I do not want that line to get triggered until I actually click on one of the rows (to open the conversation dialog), but it seems like it's actually getting triggered when the Messages page opens.

Anything that can be done about that? :)
If I'm not mistaken the third line is executing when the page loads, wouldn't you be better off assigning it to a variable and invoking that on click?

I suck at jquery sorry.
xterm wroteIf I'm not mistaken the third line is executing when the page loads, wouldn't you be better off assigning it to a variable and invoking that on click?

I suck at jquery sorry.
I'm not really sure what you are trying to say, but the line that says something.dialog('open') is what opens the dialog box. And that happens inside the click event of the table row...
I don't know anything about your environment, but in client-side javascript you can normally use console.log() to dump a string, or an object to the browser javascript console. If you have Firefox it'll appear in Firebug, inside the Console tab. Chrome and safari have similar features.
So you if you do console.log(event.target) you should see the whole hierarchy of that object and it might help you in figuring out what's happening.
I finally got it to work properly (and found a shit-load of bugs along the way!)... I think this is what xterm was trying to say...? Check it out:
    $(function () {
        var clickedId;

        $(".openConversationLink").click(function () {
            clickedId = parseInt($(this).attr('id'));
            $("#conversationModal").dialog({
                autoOpen: false,
                width: 850,
                height: 600,
                resizable: false,
                draggable: false,
                modal: true,
                open: function (event, ui) {
                    $(this).load('Message/Conversation/' + clickedId);

                }
            });
            $("#conversationModal").dialog('open');
        });
    });
rolf wroteI don't know anything about your environment, but in client-side javascript you can normally use console.log() to dump a string, or an object to the browser javascript console. If you have Firefox it'll appear in Firebug, inside the Console tab. Chrome and safari have similar features.
So you if you do console.log(event.target) you should see the whole hierarchy of that object and it might help you in figuring out what's happening.
rolf, I'm still trying to find my way around jQuery and FireBug. It's been very helpful actually, and I guess that Console.log() tip is going to save me a lot of annoying alert's. Thanks for the tip :)
On a side note, mods and admin, don't you think it's about time get get off your asses (no insult intended) and install some code coloring script? We've complained about this several times before, let's get it done please. :)

P.S: I do understand that you guys have full time jobs and I think we all appreciate what you're doing for this community. But I really hate posting code over here because it's literally painful to read "green" code.
I haven't used jquery in a while, but I hope this will help clear some things up:
Kassem wroteCompiler Error Message: event.target.attr('id') is not a function
//I also tried ui.attr('id') and got the same error
The error is a good starting point, your problem is clearly with the "id" attribute of your event's target. Since it didn't complain that target is undefined, we know we have an event and a target, but for some reason this target doesn't have an id attribute. Makes you wonder what the target is, since it is clearly not a dom node...

You assume that the event here is the event of the onclick... and so you assume the target is the domnode that was clicked. In fact the event is that of the "open" on the dialog [http://docs.jquery.com/UI/Dialog#event-open] which isn't associated with your clicked dom node.
Kassem wrote$(".openConversationLink").click(function () {
$("#conversationModal").dialog('open');
});
See your event is generated from the onclick here, but you don't pass it to the dialog method, so when dialog.open gets called, it isn't aware of the onclick event/target anymore.

While your solution works, I would offer the following criticisms:

1- You have associated the initialization of the dialog with the onclick of the node. This is unnecessarily expensive, you just need to init the dialog once and open it on each click.

I would suggest revisiting your initial structure where the dialog gets initialized independent of the openConversationLink click:
$(function () {

var clickedId = null;

            $("#conversationModal").dialog({
                autoOpen: false,
                width: 850,
                height: 600,
                resizable: false,
                draggable: false,
                modal: true,
                open: function (event, ui) {
                    $(this).load('Message/Conversation/' + clickedId);
                }
            });

        $(".openConversationLink").click(function () {
            clickedId = parseInt($(this).attr('id'));
            $("#conversationModal").dialog('open');
        });
    });
2- You are storing your clickedId in a scope larger than needed. If clickedId is only needed within the open of the dialog, then it would be preferable to pass it to it rather than define it externally and access it. I'm not sure if the dialog plugin will allow setting of custom options, but if so then something like this should work:
$(function () {

            $("#conversationModal").dialog({
                autoOpen: false,
                width: 850,
                height: 600,
                resizable: false,
                draggable: false,
                modal: true,
clickedId: null,
                open: function (event, ui) {
                    $(this).load('Message/Conversation/' + clickedId);
                }
            });

        $(".openConversationLink").click(function () {
            var clickedId = parseInt($(this).attr('id'));
            $("#conversationModal").dialog('option', 'clickedId', clickedId);
            $("#conversationModal").dialog('open');
        });
    });
disclaimer: totally untested code... and I haven't worked with jquery in quite some time...
@vic: This is exactly what I was hoping I could do but unfortunately, it doesn't allow passing in custom options although that would be a great feature IMO.

Thanks for the help :)
Kassem, I implemented such a box a while ago.
But I did not use a dialog box, you see I used fancybox and populated it with an inline div which loaded its content dynamically.
The way I did it was have all the html inside a div with id "container"
<div id="container">
	<div style="display:none">
		<div id="data"style="width:600px;min-height:500px;height:100%;padding-top:10px;padding-right:10px;">
			
		</div>
	</div>

... rest of the page
you see data is not displayed, I can use it when a user clicks a button to load data into it then display is as a box, for example I have a list of albums and each albums has pictures, when a user clicks on an album, I show him the list of pictures which I load from the album's ID:
function EditPictures(id)
{
	$('#container').hide();
	$.fancybox.showActivity();
	//get the articles into data:
	
	var data = { t:Math.random(), id:id};
	$.ajax({
	  type: "POST",
	  url: 'getAlbumPics.php',
	  data:data,
	  success: function(data) {
		$('#container').show();
		$('#data').html(data);
		
		$.fancybox({
			'padding'		: 0,
			'href'			: '#data',
			'width'				: 700,
			'height'				: 800,
			'transitionIn'	: 'elastic',
			'transitionOut'	: 'elastic',
			'autoDimensions' : false
		});
	  }
	});
}
I can also have a button to close this dialog:
$.fancybox.close();
$('#container').hide();
Personally I prefer building the box in HTML, then use jQuery only to hide/show it and position it if necessary.
rolf wrotePersonally I prefer building the box in HTML, then use jQuery only to hide/show it and position it if necessary.
This is the way I was using fancybox actually.
you can ignore fancybox and create the box manually and show/hide it as necessary.
ZeRaW wrote
rolf wrotePersonally I prefer building the box in HTML, then use jQuery only to hide/show it and position it if necessary.
This is the way I was using fancybox actually.
you can ignore fancybox and create the box manually and show/hide it as necessary.
Yep, I noticed that is almost what you were talking about. You gave a much more detailed solution.
It is true, you can just replace calls to fancybox by $("#myModal").show()/hide()
Here's my current implementation. I noticed I was setting up the dialog box inside the click handler which is redundant. So I moved it outside. The only thing I do not like about the code now is the clickedId being a "global" variable, but I'll try to sort that out later after I'm done with the project.
        var clickedId;

        $("#conversationModal").dialog({
            autoOpen: false,
            width: 850,
            height: 600,
            resizable: false,
            draggable: false,
            modal: true,
            open: function (event, ui) {
                //grab the URL to the Conversation action method and append /clickedId to it
                $(this).load('@Url.Action("Conversation", "Message")' + '/' + clickedId);
            }
        });

        $(".openConversationLink").click(function () {
            clickedId = parseInt($(this).attr('id'));
            $("#conversationModal").empty();
            $("#conversationModal").dialog('open');
        });
    });
can't you actually do:
//do this inside the click handler:
$( "#conversationModal" ).unbind("dialogopen");
$( "#conversationModal" ).bind( "dialogopen",{id: clickedId },function(event, ui) {
   $(this).load('@Url.Action("Conversation", "Message")' + '/' + event.data.id);
});
and remove
open: function (event, ui) {
                //grab the URL to the Conversation action method and append /clickedId to it
                $(this).load('@Url.Action("Conversation", "Message")' + '/' + clickedId);
            
            }
10 days later
ZeRaW wrotecan't you actually do:
//do this inside the click handler:
$( "#conversationModal" ).unbind("dialogopen");
$( "#conversationModal" ).bind( "dialogopen",{id: clickedId },function(event, ui) {
   $(this).load('@Url.Action("Conversation", "Message")' + '/' + event.data.id);
});
and remove
open: function (event, ui) {
                //grab the URL to the Conversation action method and append /clickedId to it
                $(this).load('@Url.Action("Conversation", "Message")' + '/' + clickedId);
            
            }
Unfortunately, that did not work...