Jo G
Jo G

Reputation: 65

ReplaceWith function not working with Clone

I am new to JQuery. I am trying to use ReplaceWith and Clone to quickly restore the data in text boxes to their original state if the user clicks a Cancel button. When the user clicks Edit, the Edit button disappear and is replaced with a Save and a Cancel button and the text boxes are enabled. If they press Cancel, I want this to be reversed, with the original text restored if it has been changed.

I am attempting to Clone to store the div contents when the Edit button is clicked and RestoreWith to cancel changes when Cancel is clicked. Both the CloneContent and the RestoreContent functions are called as expected (all the alerts in the code below appear as expected), but nothing changes on the screen when Cancel is clicked. What am I doing wrong?

script -

 var divClone;

 function CloneContent(mydiv) {
     alert('cloning');
     divClone = $(mydiv).clone(true, true);
     alert('finished cloning');
 }

 function RestoreContent(mydiv) {
     alert('restoring');
     $(mydiv).replaceWith($(divClone));
     alert('finished restoring');
     return false;
 }

and the asp code -

<asp:panel ID="pnlNames" runat="server">

    <asp:LinkButton ID="lnkEditNames" runat="server" 
        OnClientClick="CloneContent('<%=pnlNames.ClientID%>')" 
        OnCommand="lnkEdit_Click" Text="Edit" />

    <asp:LinkButton ID="lnkUpdateNames" runat="server" 
        OnCommand="lnkUpdate_Click" Text="Save" Visible="false" />

    <asp:LinkButton id="lnkCancelEditNames" runat="server" 
        onclientclick="RestoreContent('<%=pnlNames.ClientID%>')" 
        Text="Cancel" Visible="false" /> 

    <asp:TextBox runat="server" MaxLength="50" ID="txtLastName" Enabled="false" />


</asp:panel>

Upvotes: 0

Views: 716

Answers (3)

Jo G
Jo G

Reputation: 65

Thanks to Tomalak's answer for putting me on the right track, but I didn't want the code to be dependent on the hierarchy of the divs or the number of input elements within the editable div. I use a classname to identify the containing div instead of "parent()".

First the html. Testing for a two text boxes, a drop down list and a checkbox.

<div id="divNames" name="divNames" class="LPCEditGroup memNames">

    <a id="lnkEditNames" name="lnkEditNames" onclick="SaveDefault(this)" class="editbutton memNames" href="#/">Edit</a>

    <asp:LinkButton ID="lnkUpdateNames" runat="server" OnCommand="lnkUpdate_Click" Text="Save" style="display:none;" class="updatebutton memNames"/>
    <a id="lnkCancelEditNames" name="lnkCancelEditNames" onclick="RestoreDefault(this)" style="display:none" class="cancelbutton memNames" href="#/">Cancel</a>
    <br />     
    <asp:TextBox runat="server" MaxLength="50" ID="txtLastName" CSSClass="myinput memNames"  Enabled="false" />
      <asp:TextBox runat="server" MaxLength="50" ID="TextBox1" CSSClass="myinput memNames"  Enabled="false" />
         <asp:DropDownList runat="server" ID="dd" CssClass="myinput memNames"      >
             <asp:ListItem Text ="One" Value="1"/>
             <asp:ListItem Text ="Two" Value="2" />
             <asp:ListItem Text ="Three" Value="3" />

         </asp:DropDownList>
<asp:CheckBox ID="chk" runat="server" Checked="true"  CssClass="myinput memNames"  />
</div>

And the script:

    <script type="text/javascript">
        $(document).ready(function(){

            $('.editbutton').click(function() {
            //remove the class name 'editbutton' from the class string which will leave us with the classname shared by the group of elements we want to edit
             var editClass = $(this).attr('class').replace('editbutton', '').replace(' ', ''); 

            var mydiv = $('div.LPCEditGroup.' + editClass).get(0);

            //replace the class name to change the panel to look selected
            $('#' + mydiv.id).attr('class', 'LPCEditGroupEditing ' + editClass);

            //get all elements sharing the edit group classname & store the default values
            $(mydiv).find('.myinput').each(function (curIdx, curO) {
                $(curO).attr('default-value', $(curO).val());
            });

            $('div#' + mydiv.id).find('.editbutton').hide();
            $('div#' + mydiv.id).find('.updatebutton').show();
            $('div#' + mydiv.id).find('.cancelbutton').show();

            //enable everything in the panel that the edit button is in
            $('div#' + mydiv.id).find(':input').prop('disabled', false);

            return true;
        })
         $( '.cancelbutton' ).click(function() {

            //restore default for all items where edit group class name is for the current edit group

             var editClass = $(this).attr('class').replace('cancelbutton', '').replace(' ', ''); 
             var mydiv = $('div.LPCEditGroupEditing.' + editClass).get(0);


             //replace the class name to change the panel to look unselected
             $('#' + mydiv.id).attr('class', 'LPCEditGroup ' + editClass);


             $(mydiv).find('.myinput').each(function (curIdx, curO) {
                $(curO).val($(curO).attr('default-value'));
            });

             $('div#' + mydiv.id).find('.editbutton').show();
             $('div#' + mydiv.id).find('.updatebutton').hide();
             $('div#' + mydiv.id).find('.cancelbutton').hide();

             //disable everything in the panel that the edit button is in
             $('div#' + mydiv.id).find(':input').prop('disabled', true);

            return true;
            });
        });

Upvotes: 0

Tomalak
Tomalak

Reputation: 338326

To restore the original data when the user clicks "Cancel" you don't need to use Clone and ReplaceWith at all.

Just save the current value on edit, and reset the field to the saved value on cancel.

Also, don't use onclick or similar inline event handlers when you are working with jQuery. Try to avoid element IDs, too. Use CSS classes instead. This way the same JavaScript code can be used for all the input fields on your page.

ASP.NET:

<asp:panel ID="pnlNames" runat="server">
    <asp:LinkButton CssClass="edit" Text="Edit" />
    <asp:LinkButton CssClass="save" Text="Save" Visible="false" />
    <asp:LinkButton CssClass="cancel" Text="Cancel" Visible="false" />
    <asp:TextBox MaxLength="50" ID="txtLastName" Enabled="false" />
</asp:panel>

Corresponding JS:

$(".edit").on("click", function () {
    var $textBox = $(this).parent().find(":text"),

    // hide and show buttons    
    $(this).hide();
    $(this).parent().find(".save").show();
    $(this).parent().find(".cancel").show();

    // save current value into jQuery data for the textbox
    $textBox.data("oldValue", $textBox.val())
});

$(".cancel").on("click", function () {
    var $textBox = $(this).parent().find(":text"),

    // hide and show buttons    
    $(this).hide();
    $(this).parent().find(".save").hide();
    $(this).parent().find(".edit").show();

    // restore textbox value from jQuery data
    $textBox.val( $textBox.data("oldValue") );
});

$(".save").on("click", function () {
    // hide and show buttons    
    $(this).hide();
    $(this).parent().find(".cancel").hide();
    $(this).parent().find(".edit").show();
});

Upvotes: 2

Arcturus
Arcturus

Reputation: 27065

Not tested yet.. but you are passing the clientID directly into jQuery? I think you need to prefix it with # in order to look up the element by id.

Secondly, I don't think you need to pass the div in the $ anymore when replacing

updated code:

 var divClone;

 function CloneContent(mydiv) {
     alert('cloning');
     divClone = $('#' + mydiv).clone(true, true);
     alert('finished cloning');
 }

 function RestoreContent(mydiv) {
     alert('restoring');
     $('#' + mydiv).replaceWith(divClone);
     alert('finished restoring');
     return false;
 }

Upvotes: 1

Related Questions