tags:

views:

42

answers:

4

I'd like to have X number of Ajax panels on my list page which is inside a master Page for site consistency.

The tutorials I'm coming across on ASP.NET Ajax seem to imply I need a <form><asp:ScriptManager ID="asm" runat="server"/></form> around my <table></table> layout. I would think for this function (each code being an individual Ajax element) that each <tr></tr> would be a form unto itself. So that actions specific to a code only trigger an Ajax Async postback of that piece. Here's what I imagine the proper layout would look like:

<table>
    <thead>
        <tr>
            <th>
                Code
            </th>
            <th>
                Description
            </th>
            <th>
                Document
            </th>
            <th>
                Customer Contact Required for Resolution
            </th>
            <th>
                Associate
            </th>
            <th>
                Shareholder
            </th>
            <th>
                Customer
            </th>
            <th>
                Regulatory
            </th>
            <th>
                Root Cause
            </th>
            <th>
                Investor Requirements
            </th>
        </tr>
    </thead>

    <tbody>
        <% foreach (var item in GetCodes())
        { %>
            <tr>
               <form><asp:ScriptManager ID="asm" runat="server"/>
                 <asp:UpdatePanel runat="server">
                   <td><%=item.Code %></td><td>item.Description</td><td><%=item.Document %></td>
                   <td><asp:ListBox ID="lbAssociate" /></td>
                   <td><asp:ListBox ID="lbShareholder" /></td>
                   <td><asp:ListBox ID="lbCustomer" /></td>
                   <td><asp:ListBox ID="lbRegulatory" /></td>
                   <td><asp:dropdownlist ID="ddlRoot" /></td>
                   <td><asp:CheckBox 
                         ID="_ckbAllInvestorRequirements" 
                         runat="server" 
                         Text="All" 
                         onclick="AllInvestorClicked()" />
                       <asp:CheckBoxList 
                         ID="_cblInvestorRequirements" 
                         runat="server">
                       </asp:CheckBoxList></td>
                   <td><asp:Button ID="Submit" Text="Submit" runat="server" /></td>
                 </asp:UpdatePanel>
               </form>
            </tr>
        <% } %>
    </tbody>
</table>

Is this the proper layout for iterative Ajax mini-forms? It appears XHTML doesn't like the idea of a <table> having <form> inside it so how could I lay this out? I would think wrapping the whole table in a form would result in all the items being reloaded on each request instead of a single line item.

A: 

Unfortunately you need to wrap the entire table in the UpdatePanel to get this to work. If you're afraid it'll be slow, try it first. I've always been pleasantly surprised when I've wrapped tables in UpdatePanels at the refresh rate.

You may also want to take a look at ASP.NET Dynamic Data, which offers the functionality you're looking for.

Chris Pebble
so then the whole table would be refreshed every time instead of a single tr?
Maslow
Correct. I've updated my post with a link to Microsoft's Dynamic Data release which may be exactly what you're looking for. There are also some jQuery plugins that may help you, but I would really suggest trying to wrap the whole table and checking performance before you try anything more complicated.
Chris Pebble
Is there a way to just send some data back to the server without a `<form>` ? Be it jQuery or javascript or something?
Maslow
Yes, take a look at jGrid (http://www.trirand.com/blog/). It's a lot of work compared to an UpdatePanel though.
Chris Pebble
A: 

Depending on the strength of your CSS-fu, you might be able to accomplish a similar layout using CSS with DIV tags around your form values. It would be something like this:

<% foreach (var item in GetCodes())
   { %>
<form>
  <asp:ScriptManager ID="asm" runat="server"/>
    <asp:UpdatePanel runat="server">
      <div id="Row">
      <div id="Associate"><asp:ListBox ID="lbAssociate" /></div>
      <div id="Shareholder">... etc.
    </div>
  </asp:UpdatePanel>
</form>
<% } %>

Try that path if the global UpdatePanel doesn't give you the performance you're looking for.

iandisme
While performance is a concern, My primary motivator is layout and not having to send the state of other marked controls back and forth on each reload. If someone clicks something on one of the other rows then tries to save the row they are working on via a trip to the server. I don't want the other row traffic nor their values lost.
Maslow
I see - it should be possible to achieve the same layout without tables, and if that's whats boning up your AJAX calls, a CSS-based layout may be your best bet. You may have to play with the xhtml code though, I just whipped that up in the answer editor.
iandisme
this sounds like a good solution, i've just got to research and figure out how to implement it.
Maslow
apparently things inside the UpdatePanel can't access the item iterator from the foreach, any ideas on how to populate the static text fields that are different for each row but still live inside the UpdatePanel?
Maslow
I couldn't figure out how to get the `updatepanel` initialization to access the `item` variable and it's properties.
Maslow
A: 

If you want every section of your page to have its own state, you should look up ISCriptControl and javascript WebRequests. It's not as easy as updatepanels, but it's exponentially faster to the user and will let you achive your intent.

Your masterpage will have many controls on it that inherit IScriptControl. If you do this right, they will all be their own little independent world, sans user data and the like. Every control will have a javascript file associated with it if you implement IScriptControl correctly, tied to one of that control's dom elements.

That javascript file will behave like an object and be tied to an individual dom element. You can perform javascript webrequests to an aspx page to send and retrieve data for just that section and not have to worry about the rest of the page.

The aspx page the javascript calls can override render so it only sends back the necessary parts after processing the request data.

You can then get the html back from the server and only update that indvidual dom element. You'll know the data is back because there will be a javascript event you can catch.

diadem
A: 

I wound up using jQuery Ajax to directly call a PageMethod on my page. Using this method, I did not need a <form> or an <asp:UpdatePanel>.

<script type="text/javascript">
//<![CDATA[
   function submitAjax(controls) {
       //$("#ajaxResult").text("submitCalled:" + code);
       function quoteOrNull(value) {
           if (typeof value == "undefined" ||  value == null)
               return "null";
           else
               return "'" + value + "'";
       };
        var all = controls.All.attr('checked');
         var investors = [];
       controls.Boxes.each(function(index,item) {
           if (item.checked || all)
               investors.push(item.value);
       });
       var message = "{'code':'" + controls.Code
                + "','associate':" + quoteOrNull(controls.Associate.val())
                 + ",'shareholder':" + quoteOrNull(controls.Shareholder.val())
                 + ",'customer':" + quoteOrNull(controls.Customer.val())
                 + ",'regulatory':" + quoteOrNull(controls.Regulatory.val())
                  + ",'rootCause':" +quoteOrNull( controls.Rootcause.val())
                  + ",'investors':[" + investors +"]"
                 + "}";
       $.fn.wait = function(time, type) {
           time = time || 1000;
           type = type || "fx";
           return this.queue(type, function() {
               var self = this;
               setTimeout(function() {
                   $(self).dequeue();
               }, time);
           });
       };

       $.ajax({
           type: "POST",
           url: "List.aspx/Save",
           data: message, //Get form values 
           contentType: "application/json; charset=utf-8",
           dataType: "json",
           success: function(msg) {

               var value = msg.d;
               if (msg.d.HasError == false) {
                   $("#ajaxResult").text("Ajax success").removeClass("errormsg");
                   controls.Row.addClass("complete");
                   controls.Button.val("Edit");
                   controls.Result.text("Success").removeClass("errormsg");
                   controls.Result.show().wait(2000).fadeOut("slow");
                   if (controls.Associate.val() && controls.Shareholder.val() && controls.Customer.val()
                        && controls.Regulatory.val()) {
                       var value = parseInt(controls.Associate.val(), 10) + parseInt(controls.Shareholder.val(), 10)
                       + parseInt(controls.Customer.val(), 10)
                        + parseInt(controls.Regulatory.val(), 10);
                       controls.Severity.text("Severity: " + (value / 4)).fadeIn("slow");

                   }
                   // else controls.Severity.text("Incomplete").fadeIn("slow").wait(1500).fadeOut("slow");
                   function disable(item) { item.attr("disabled", "disabled"); }
                   disable(controls.Associate);
                   disable(controls.Shareholder);
                   disable(controls.Customer);
                   disable(controls.Regulatory);
                   disable(controls.Rootcause);
                   disable(controls.All);
                   disable(controls.Boxes);
               }
               else {
                   controls.Result.text("Creation failure:" + msg.d.ErrorMessage).addClass("errormsg").show();
                   $("#ajaxResult").text("Ajax success, creation failure:" + msg.d.ErrorMessage).addClass("errormsg");
               }

               //  span.attr("style", "color:White");
               //span.text("Ajax success:" + msg.d).show().wait().fadeOut("slow");
           },
           error: function(request, textStatus, errorThrown) {
               // var span = $(formSelector + " div.submit span");
               controls.Result.text("Ajax failure").addClass("errormsg").show().wait(3500).fadeOut("slow");
               $("#ajaxResult").text("Ajax failure:" + request.statusText).addClass("errormsg");
               // span.attr("style", "color:Red");
               // span.text("*" + request.statusText).show().wait().fadeOut("slow");

           }
       });
   };
   //]]>
</script>

then the submit button looks like this:

<input type="button" value="<%=defect.Assessment==null?"Save":"Edit" %>" name="submit" onclick="codeButton('<%=CurrentDefect.Code %>');" />
Maslow

related questions