1

In my .Net MVC app using twitter bootstrap, I have a View that draws many fields. The value of each field is a shortened string 100 characters long. The original string is always over 1000 characters long (sometimes 100k characters long).

string long = result[i]; // really long string that's over 1000 characters long
string short = long.Substring(0, 99);
<section>
    <div class="row-fluid">
        <div class="span12">@short</div>
    </div>    
</section>

For each field that I draw, I need to have a link that the user can click to show a modal window in which I display the non shortened text.

So I may want to have 100 links to modal windows on the same page and each modal window will display its own text.

Something like this: http://jqueryui.com/dialog/

But my problems are:

1) I will have a lot of modal dialogs on the same page, so I guess I'll need an unique ID for each one.

2) I will have to pass the long text ("string long") to each modal dialog. Maybe I can do that when I draw them in the client code, or maybe I can do that by sending the long text to my Controller. I'm not sure what the best approach would be.

I have been looking at this: ASP.NET MVC modal dialog/popup best practice but I don't quite understand what the checked answer is referring to ("Lunchy's dialog suggestion"?).

Community
  • 1
  • 1
doosh
  • 875
  • 3
  • 9
  • 13

2 Answers2

2

A potential strategy would be to have the html for only one modal dialog, and have all the long versions of the string in some sort of javascript data structure, like a hash array or something. This will save your page being bloated by the HTML for hundreds of modal dialogs

Then, when the user clicks the 'show me the long version' link - you have some query that replaces the inner text within the modal dialog with the appropriate 'long version' of the string which it retrieves from the hash array and then displays that dialog.

If you wanted to get fancier - you would only load the short version of the string in the page, and when the user clicked the link, it would retrieve the 'long version' of the string via AJAX.

Twitter Bootstrap comes with a Modal Dialog see here, and JQuery has some methods for inserting HTML into elements - see here.

If you look at the documentation for the Twitter Bootstrap Modal Dialog, you will see that it can optionally load data remotely via AJAX using the remote: option.

Here is a rough example of how you could make use of Twitter bootstrap to do this via AJAX

The controller

public ActionResult Index()
{
    var model = GetLongStrings(); 
    return View(model);
}

public ActionResult FindLongString(string shortString)
{
    var longStrings = GetLongStrings();
    var longStringToReturn = longStrings
                            .FirstOrDefault(x => x.StartsWith(shortString));

    return Content(longStringToReturn);
}

Then, your view would look something like this

@foreach (var result in results)
{
    var shortString = result.Substring(0, 5);
    <section>
        <div class="row-fluid">
            <div class="span12">@shortString</div>
            @Html.ActionLink("See long version", "FindLongString", 
                             new { shortString = shortString }, 
                             new { data_toggle = "modal", 
                                   data_target = "#myModal", 
                                   aria_hidden = "true" })
        </div>
    </section>
}

<div id="myModal" class="modal hide fade">
    <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
        <h3>Modal header</h3>
    </div>
    <div class="modal-body">
    </div>
    <div class="modal-footer">
        <a href="#" class="btn"  data-dismiss="modal">Close</a>
    </div>
</div>

The data attributes in the ActionLink are important, as they instruct Twitter Bootstrap what options to use for your dialog.

The code example could be improved if each string had an ID - the FindLongString could accept an `int as a parameter, meaning you could just pass this in the ActionLink.

StanK
  • 4,750
  • 2
  • 22
  • 46
  • Looks good. Thanks. I already have the "longString" when I call the Controller through the ActionLink from the View, so I don't see the reason why I can't just pass the longString to the Controller instead of having a function in my Controller that tries to find the longString. – doosh Mar 27 '13 at 08:09
  • I tried this and instead of passing the shortstring I passed the longstring (because I already have that when I create the ActionLink so I don't see why I should fetch it in the Controller), but I get an HTTP error because the string is too long: "The request filtering module is configured to deny a request where the query string is too long.". The URL is http://localhost/MyView/FindLongString?longstring=... and then the entire long string of >1000 characters. So that's too long unfortunately. I'm thinking of just opening another view and showing it there instead. – doosh Mar 27 '13 at 13:22
  • You should not pass the long string as a parameter. The whole point of that "FindLongString" action is that you don't need to send all the long texts through the wire unnecessarily. What you intended to do sends all the long strings in the first response. – vinczemarton Mar 27 '13 at 16:11
  • 1
    My code was just a rough sample to give you some ideas. The point is that you shouldn't fill up your html with 100s of 'long strings' that you may never need. Fill it up with the 'short strings' instead, and request the 'long string' from the server via AJAX only when you need it. My method relied on your passing the 'short string' to the server to get the 'long string' which is not ideal - but I hoped would demostrate the concept. It would be better to assign each string an `int` ID and pass that to the server, as per the answer from @SoonDead. – StanK Mar 27 '13 at 20:02
1

StanK's answer is what you need, so if it is helpful to you don't hesitate to accept it.

I just have an observation though: It is not really dependable to retrieve the long string by the short string. I mean in theory all the strings can start with the same 100 characters ( all the strings can even be the same :) ). If there are 2 strings starting with the same 100 characters, only the first one will be returned no matter which short string were clicked.

A much more dependable method would be to provide a unique ident for each strings. This can be anything as long as they are unique. It depends on your server side logic.

  • If the strings come from a relational database, you can usually use the primary key of the table (or any unique keys. It is a good practice to have a unique increment id on most of the tables). This method also results in pretty fast and clean database queries. But keep that in mind that this way you can reveal more from your database structure that you might want.
  • If the strings are in an ordered list and the order is fixed, you can use the index of the element.

So taking StanK's example code and introducing a database connection to it (Entity Framework in my case, but this can be anything):

The controller actions:

public ActionResult Index()
{
    using (Context ctx = new MyEntities())
    {
        var model = ctx.Strings.Select(o => new { Id = o.Id, longString = o.String });
        return View(model);
    }

}

public ActionResult FindLongString(string id)
{
    using (Context ctx = new MyEntities())
    {
        var record = ctx.Strings.SingleOrDefault(o => o.Id == id);
        if (record == null)
        {
            throw new HttpException(404, "The long string cannot be found");
        }
        else
        {
            return record.String;
        }
    }
}

The View:

@foreach (var result in results)
{
    var shortString = result.String.Substring(0, 99);
    <section>
        <div class="row-fluid">
            <div class="span12">@shortString</div>
            @Html.ActionLink("See long version", "FindLongString", 
                             new { id = result.Id }, 
                             new { data_toggle = "modal", 
                                   data_target = "#myModal", 
                                   aria_hidden = "true" })
        </div>
    </section>
}

<div id="myModal" class="modal hide fade">
    <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
        <h3>Modal header</h3>
    </div>
    <div class="modal-body">
    </div>
    <div class="modal-footer">
        <a href="#" class="btn"  data-dismiss="modal">Close</a>
    </div>
</div>
vinczemarton
  • 7,756
  • 6
  • 54
  • 86