Today I needed to load a massive amount of text into dropped-down section on the page. And it was unlikely that users will expand that section, so no point in loading a huge load of data until it is needed. That is AJAX is for, isn’t it?

Here is the HTML for the Accordion:

<div class="accordion-ajax" data-url='/path/to/get/text/from'>
    <div class='accordion-head'>
       This is visible text to be presented for clicking
    </div>
    <div><!--This is required: it will be filled in with body of accordion when it is expanded--></div>
</div>

And here is the JavaScript code:

    $('.accordion-ajax').accordion({
        collapsible: true,
        active: false,
        clearStyle: true,
        autoHeight: false,
        header: '.accordion-head',          // point to the class that is used as a header
        heightStyle: 'content',
        icons: false,
        beforeActivate: function (event, ui) {
            var self = $(this); 

            // this bit is tricky. Make sure you have no empty space in the body of drop-down 
            if (ui.newPanel.html() == '') {         
                // taking data-url parameter from accordion header div
                // and load the returned contents into the accordion body.
                // presuming HTML is returned. 
                ui.newPanel.load(self.data('url'));
            }
        }
    }); 

See more details on API in jQuery Accordion API

UPDATE 31 Jan 2013: We have encountered this issue after we have updated our MVC3 project to MVC5. A year ago we have moved MVC3 to MVC4. And suddenly Chrome started to insist on incorrect date format, but everywhere else we have set Globalise locale to be en-Gb. The only other alternative was to disable date validations which can also work – I trust server side validation more than I trust JavaScript ;-)


Today I came across the magical problem in Chrome – it ignores locale information for date format. So it always uses US format: “mm/dd/yyyy”. But largest part of the world is not using this messed up month-first approach (wink-wink).

Continue reading

Sometimes you would like to shorten your long text in the HTML table. Here is the way to go with css and jQuery: css:

<table>
  <tr>
    <td class="ellipsis">
      Some very long text that you would like to be shortened
    </td>
  </tr>
</table>

CSS:

td.ellipsis {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 300px
}

jQuery:

$('.ellipsis').each(function (index) {
    var $this = $(this);
    var titleVal = $this.text();
    if (titleVal != '') {
        $this.attr('title', $.trim(titleVal));
    }
});

I did spend quite a time figuring out jQuery verbs to do just what I needed. So I’ll share this with my blog and possible readers. On my view I had a model written out, some other stuff, but here I’m only interested in DropDown and JavaScript bits:

@Html.DropDownListFor(m => model.tagId, new SelectList(ViewBag.Tags, "Value", "Text", model.tagId), new {@class = "document-category", data_id = model.modelId})

where

ViewBag.Tags was populated in controller like this:

ViewBag.Tags = _tagRepository.All
    .OrderBy(t => t.Name)
    .Select(t => new { Text = t.Name, Value = t.TagId.ToString() })
    .OrderBy(t => t.Text)
    .ToList();

Back to the view. Added JavaScript like this one:

$(document).on("change", ".document-category", function () {
    var select = $(this);
    $.ajax({
        type: "POST",
        url: "@(Url.Action("Action", "Controller"))",
        data: { id: select.data("id"), 
        tagId: $("option:selected", select).val()},
        error: function () {
            select.after("Error occurred");
        },
        success: function (data) {
            if (data.Success === true) {
                select.after(function () {
                    return $('<div> Saved </div>').delay(1000).fadeOut(1000);
                });
            } else {
                select.after("Error occurred");
            }
        }
    });
});

The very first line can be replaced by $(".document-category").change(function(){ but this time I had to deal with other java-script library that was stripping-bare my stuff. On the other end of the ajax request you need to put controller action:

[HttpPost]
public virtual JsonResult Action(int id, int? tagId)
{
        //blah, do some update stuff
    return Json(new {Success = true, Message = "Updated"});
}