Wednesday, July 11, 2012

How to Add Attribute ID to Telerik MVC Window When Creating in Javascript

In my previous post I mostly explained how to open a Telerik window in javascript. I use this function in generic format from all over the application, I simply set url, title and id to pass as arguments and rest is the same. Using ViewInPopup for function name also.

 You may need an id for this popup window since you open it via javascript and in some cases manually closing may be needed. For these cases we will just add .attr('id','id-to-give'); to our window element and the last version of our function will be like,



    function ViewInPopup(url, id, title) {
        $.ajax({
            type: 'POST',
            url: url,
            data: { Id: id },
            dataType: 'html',
            success: function (htmlData) {
                var windowElement = $.telerik.window.create({
                    title: title,
                    html: htmlData,
                    contentUrl: "",
                    actions: ["Maximize", "Close"],
                    modal: true,
                    width: 500,
                    height: 500,
                    resizable: false,
                    draggable: true,
                    scrollable: true,
                    onClose: function () { }
                });
                windowElement.attr('id', 'popupWindow');
                var win = $(windowElement).data('tWindow');
                win.center().open();
            }
        })
    }



Now you can access this window by id. One more thing to mention, you can close window but you may also  need to destroy it.



    function closeWindow(id) {
        $("#" + id).data('tWindow').close();
        $("#" + id).data('tWindow').destroy(); 
    }


If there are any mistakes, let me know.

Regards,
Mehmet.

Tuesday, July 10, 2012

Telerik MVC Treeview, How to Add CRUD (Edit Create Delete) Buttons, With Popup Window

Telerik MVC users may have known this issue but Treeview absolutely needs some modifications to look like rest of the telerik components. So we have decided to add Edit and Delete button like Grid control on each line. Then we will add Create button on the toolbar. And both Create and Edit will work in popup window.

EDIT: Treeview does not include window.js so we need to register it manually.

<%: Html.Telerik().ScriptRegistrar().jQuery(false).DefaultGroup(group => group.Add("telerik.window.min.js").Add("telerik.draganddrop.min.js"))%>

Adding Edit and Delete buttons on each row is a javascript trick, written by Umut Yıldırım. We simply get each item and append button html before or after text div. Normal Treeview item has following <li> structure,



     <li class="t-item">
          <div class="t-mid">
               <span class="t-in">Item Text</span>
               <input class="t-input" name="itemValue" type="hidden" value="7" />
          </div>
     </li>


What we need to do is adding <a> tags before input or before span. If we add before span then icons will appear at the beginning of ItemText, if we add before input then icons will appear at the end each line.

We first add an onLoad event to Treeview,

     events.OnLoad("TreeView_OnLoad");

Then the javascript function which adds our html-to-add before span so it will be at the beginning of item.



     function TreeView_OnLoad(e) {
          var allNodes = $("li", getTreeView().element);
          allNodes.each(function (index) {
               var item = allNodes[index];
               var text = getTreeView().getItemText(item);
               var value = getTreeView().getItemValue(item);
               $(this).find("span:first").before("html-to-add");
          });
     }

If we add before input then it will be at the end, and javascript is as follows,


     function TreeView_OnLoad(e) {
          var allNodes = $("li", getTreeView().element);
          allNodes.each(function (index) {
               var item = allNodes[index];
               var text = getTreeView().getItemText(item);
               var value = getTreeView().getItemValue(item);
               $(this).find("input:first").before("html-to-add");
          });
     }

Then our html-to-add will be as follows, (I changed the classes wrt Gridview button classes so buttons will be same as gridview buttons.)

     <a href="href-address" class="t-button"><span class="t-icon t-edit"></span></a>


     <a href='#' class="t-button" onclick="..."><span class="t-icon t-delete"></span></a>

As you can see the <a> elements are similar but spans make the difference. If span has class t-edit then it will be edit icon, if it has t-delete then it will be delete icon.
You can modify href or onclick attributes as you desired. If we are going to open a window then we need to put href as "javascript:functionName(arguments)". But for delete button just onClick function is also enough.

For Delete, you can use following javascript function, just a simple function that posts to urlm with given Id. You can change Id and add more parameters, of course method in urlm has to have same parameters and return JsonResult with here Message value. In success part, we remove node with javascript so you will not need to post page again.


     function Delete(argument) {
        var con = confirm("...");
        if (con == true) {
            $.ajax({
                type: "POST",
                url: urlm,
                data: { Id:  argument },
                success: function (response) {
                    var treeView = getTreeView();
                    var node = treeView.findByValue( argument );
                    treeView.remove(node);
                    alert(response.Message);
                },
                error: function (xhr, status, error) {
                    alert(error);
                }
            });
        }
    }

For Edit, we need a little more complicated process since we need to open a popup first then load Partial View with given model.
Followint ViewInPopup function opens a telerik window and then post to the given url with given parameters. Then we will load partial view in the given url. Given arguments can be changed but the names have to match with target url's arguments.



    function ViewInPopup(url, id, title) {
        $.ajax({
            type: 'POST',
            url: url,
            data: { Id: id },
            dataType: 'html',
            success: function (htmlData) {
                var windowElement = $.telerik.window.create({
                    title: title,
                    html: htmlData,
                    contentUrl: "",
                    actions: ["Maximize", "Close"],
                    modal: true,
                    width: 500,
                    height: 500,
                    resizable: false,
                    draggable: true,
                    scrollable: true,
                    onClose: function () { }
                });
                var win = $(windowElement).data('tWindow');
                win.center().open();
            }
        })
    }

For edit, we can give url like /Controller/OpenEditPopup to ViewInPopup function and it posts to OpenEditPopup action which is as follows. As you may noticed naming convention of Id is same. We can get model with Id and we will pass to PartialView which expects that type of model.

    public ActionResult OpenEditPopup(int Id)
    {
        ...Get model here and pass to Partialview
        return PartialView("PartialViewName", model);
    }

Above code snippet will load PartialView in our window element.Then you can modify your partial view as you like.

Then we will add Grid-like toolbar and Create button. To achieve this you can inspect Gridview element, and the html tags are as follows. We put this just above Html.Telerik().TreeView().


     <div class="t-widget t-grid" id="GridBox">
            <div class="t-toolbar t-grid-toolbar t-grid-top">
                <a class="t-button t-button-icontext t-grid-add" href="#" onclick="AddNew();">
                    <span  class="t-icon t-add" style="margin-left: 0"></span>Add New</a>
     </div>

Then we close the open div right after treeview by </div>.
Here in toolbar we just added Add New button which will look just the same as normal telerik create button. The <a> element and its inner elements are for creating button. The rest is just for toolbar.

In create, the structure will be like Edit and you can give any function as you wish to onclick event. If you want to open in new window, you can use ViewInPopup and direct it to your OpenCreatePopup function which will load your partial view.

So, I have just explained how to put CRUD operations to Telerik MVC Treeview and how to open Create and Edit in popup with partial view.

If there is any typing errors or any mistakes let me know.

Regards,
Mehmet.

ExecuteNonQuery requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized.

In a transactional connection you might get the error mentioned above. It has a simple solution but we encountered it when switching from Oracle connection to Sql connection.

Oracle Data Access component (ODP Dot Net) actually runs very well without setting command transaction. The following code will work fine with an oracle database (just demonstration, syntax may change)

     using(OracleCommand = oracleConnection.CreateCommand())
     {

          oracleConnection.Open();
          OracleTransaction =  oracleConnection .BeginTransaction();


           OracleCommand.CommandText = "Procedure Name";
           OracleCommand.CommandType = CommandType.StoredProcedure;
           OracleCommand.Parameters.Clear();
           OracleCommand.Parameters.Add(...Add Parameters...);
           OracleCommand.ExecuteNonQuery();
     }

But in sql connection, we get "ExecuteNonQuery requires the command to have a transaction when the connection assigned to the command is in a pending local transaction.  The Transaction property of the command has not been initialized." error, since we actually did not set the transaction property.

OdpDotNet actually handles this but SqlConnection and SqlCommand can not. So we change our Sql code block with transaction version. Which is as follows,



     using (SqlConnection conn = new SqlConnection(connectionAddress))
     {
          SqlTransaction trans = null;
          try
          {
               conn.Open();
               trans = conn.BeginTransaction();
               using (SqlCommand comm = conn.CreateCommand())
               {
                    comm.CommandText = item.Sql;
                    comm.Transaction = trans;
                    comm.CommandType = CommandType.StoredProcedure;
                    comm.Parameters.Clear();
                    comm.Parameters.AddWithValue(parametreItem.Key, parametreItem.Value);
                    comm.ExecuteNonQuery();
               }
               trans.Commit();
          }
          catch (Exception ex)
          {
               trans.Rollback();
               throw ex;
          }
          finally
          {
               trans.Dispose();
               conn.Close();
          }
     }


If there is any mistakes let me know, so I can fix :)

Regards,
Mehmet.