mikejuniper.com

August 7, 2009

Asp.Net MVC + dojo dialog update

Filed under: MVC, dojo — mike @ 9:09 am

I’ve made some changes to the showDialog function I discussed in this post. I’ve made it more generic – it now takes dialogId, href, title, queryString, and onDownloadend (a function). That way I can use it to open any dialog in my application. I’m also now not destroying the dialog if it already exists, I’m just resetting the onDownloadEnd and title properties and using my custom setTitle method:

//extend dojo dialog to have a setTitle method
dojo.extend(dijit.Dialog, {
  setTitle: function(/*string*/title)
  {
     this.titleNode.innerHTML = title || "";
  }
});

Finally, I’m using the href property instead of setHref which is deprecated. Here’s the new showDialog function:

showDialog: function(dialogId, href, title, onDownloadEnd)
{
  //first check if it's there so we don't create a duplicate
  var dialog = dijit.byId(dialogId);
  if (dialog)
  { //it already exists, reset a few properties
    dialog.setTitle(title);
    dialog.onDownloadEnd = onDownloadEnd;
    dialog.href = href;
  }
  else
  { //it doesn't exist yet, so create it
    dialog = new dijit.Dialog({
      refreshOnShow: true,
      id: dialogId,
      href: href,
      title: title,
      onDownloadEnd: onDownloadEnd,
      onDownloadError: dojo.hitch(this, '_dialogDownloadError', dialogId)
    });
  }

  //show it
  dialog.show();
}

August 5, 2009

HtmlHelper methods and dijit widgets

Filed under: .NET, MVC, dojo — mike @ 3:46 pm

This is certainly not earth-shattering but it’s pretty cool. Asp.Net MVC HtmlHelper methods return a string of html and are used to render html elements. They are cool because you can use them to change the way the control is rendered at runtime based on what you’ve got in ViewData or your model. What’s even cooler is that you can pass html attributes (including custom ones like dojoType) to the HtmlAttributes parameter. This allows you to use HtmlHelper methods to render dijit widgets like so:

<%=Html.TextBox("search_StreetAddress",
  Model.Criteria.StreetAddress,
  new { dojoType = "dijit.form.TextBox", trim = "true" })%>

<%= Html.DropDownList("CityId", Model.CitySelectList,
  new { dojoType = "dijit.form.FilteringSelect" })%>

<%= Html.TextBox("Year", Model.Year,
  new { dojoType = "dijit.form.NumberTextBox",
  constraints = "{min:1900, max:2500, pattern:'0000'}",
  required = "true",
  rangeMessage = "A 4 digit year is required",
  invalidMessage = "A 4 digit year is required" })%>

dojo.query – putting it all together

Filed under: .NET, MVC, dojo — mike @ 11:24 am

So I guess this will be the finale to my series of posts on dojo.query. I’m using dojo.query to validate data entered into dojo dialogs. In this post, I discussed getting dialog content from an Asp.Net MVC controller method. In the onDownloadEnd function, I do any setup of the dialog that is necessary including something like this:

var onValueChanged =
        dojo.hitch(this, this.dialogValueChanged, dialogId);
//gotta be keyup -
        //validation is out of sync if you use keydown or keypress
dojo.query('input[type="text"], textarea', dialogId)
        .connect('onkeyup', onValueChanged);
dojo.query('select', dialogId)
        .connect('onchange', onValueChanged);
dojo.query('.dijit', dialogId).widgets()
        .connect('onChange', onValueChanged);

This query’s for input elements in the dialog and connects each element’s appropriate method to the function where I do the validation (dialogValueChanged). Note the use of the widgets method discussed in this post.

Here’s the validation function:

dialogValueChanged: function(dialogId)
{
  //check if everything is valid
  var valid = dojo.query('[widgetid], [widgetId]', dialogId)
    .widgets().every(function(widget)
    {
      if (widget.isValid)
      {
        return widget.isValid();
      }
      //if it is not a widget
      //or does not have an isValid method, return true
      return true;
    });                                

    //enable/ disable the save button based on whether it's valid
    var action = (valid) ? 'removeAttr' : 'attr';
    dojo.query('.dialogSaveBtn', dialogId)
	  [action]('disabled', 'disabled');
}

Here we’re querying for widgets and using our previously discussed widgets method to get the actual widgets (not just the dom nodes). Then we use the every method of NodeList to call the isValid method on each widget. The every method will return false if any of the widgets’ isValid methods returned false. Then we use the value returned from every to set our ‘action’ variable and use query again to enable or disable our save button(s) by adding or removing the disabled attribute. Note the use of the removeAttr method we added to NodeList in this post. Note also that this all depends on all the input elements on the dialog being dijit widgets. This mechanism can be easily extended to handle non-dijit elements too.

February 5, 2009

Asp.Net MVC + dojo dialog

Filed under: MVC, dojo — mike @ 9:15 am

I’ve bee working a ton with dojo and we recently started doing several projects using Asp.Net MVC.

I’ve made fairly extensive use of dojo dialogs (dijit.Dialog) and thus far I’ve usually just declared the dialog in markup because it was easy and most of the samples do it that way. But I was never totally satisfied with that. But last week I realized something cool: you can create a dojo dialog in javascript and set its href property to an Asp.Net mvc controller method that returns a view user control! This is cool for lots of reasons: you can separate the dialog markup from the rest of it, you only create the dialog if you actually need it, and best of all, the view user control can be used to conditionally render the dialog (enable/ disable controls, show different controls, etc) based on what you’ve got in viewdata, your model, or session state.

So I realized this should work in theory but I expected to have to fiddle with it to get it to actually work. Nope, it just works.

Some sample code:

Controller method:

public ActionResult GetDialog()
{
    var model = new RoleDialogModel();

    model.foo = this.foo;

    return View("RoleDialog", model);
}

Pretty straightforward, just create the model, set some properties and return the view, passing it the model. I won’t show you the view – just create a view user control and stick some markup in it.

Javascript:

showDialog: function(title, action, evt)
{
    //first check if it's there so we don't create a duplicate
    var dialog = dijit.byId('fooDialog');
    if (dialog) { dialog.destroyRecursive(); }

    dialog = new dijit.Dialog({
        refreshOnShow: true,
        id: 'fooDialog',
        title: title,
        onDownloadEnd: dojo.hitch(this, this.initializeDialog, action, evt)
    });

    dialog.setHref(this.dialogUrl);

    dialog.show();
}

There are a couple of things to notice here. First, I check if I’ve already created the dialog, dojo will puke if you try to create two objects with the same id. If it’s there I destroy it. I was previously just resetting its properties but the title wouldn’t change. I know I saw a post somewhere about how to do that but for now, I’m just destroying it and re-creating it. I set onDownloadEnd to an initialization function which hooks up ui events, etc. You should do any dijit widget stuff here, to be sure the widgets are there when you go looking for them. The setHref function sets the href of the dialog to the controller method above. I realized after I got this working that setHref is deprecated and you should use the href property instead but it was working so I didn’t want to mess with it.

I think this is a great way to handle dojo dialogs in an Asp.Net MVC app. I plan to continue using this approach and refine it going forward.

Powered by WordPress