views:

1294

answers:

2

I have a ListView that contains playlists. If the user wants to edit an album, they click the edit link and it allows them to remove or add songs to the playlist. If the user wants to Save a new playlist while keeping the original one, the would click a Save As Button. Here is what should happen:

If the user clicks Save As and they have not changed the name, I want to display an alert telling them they must change the name.

If the user clicks the Save As and they have changed the name, I want to display an a confirmation that they actually want to save it.

Currently, what is happening is that if I put something like the following in my code behind, the script does not register until the second click and whatever script was registered stays registered meaning that if I end up changing the name and the alert script was registered before, it will display the alert instead of the confirmation. Here is the code:

if (newname == oldname)
{
    btnSaveAs.OnClientClick =
  "javascript:alert('Save As requires you to change the name of the playlist. Please
   change the name and try again.');";
}
else
{
    btnSaveAs.OnClientClick = "javascript:confirm('Are you sure you want to save the
    playlist" + newname + "?');";
}

I also tried adding the return false so it would not do a postback, but if I do that, then it does not doesn't actually do anything when I click OK on the confirmation.

+1  A: 

The OnClientClick property is a Javascript string, not a URI. Therefore, you should not begin it with javascript:.

To handle the confirm correctly, write OnClientClick = "return confirm('Are you sure?');";

Also, you're misunderstanding the ASP.Net page model.

Your C# code-behind event handler only runs after the user clicks the button and after the OnClientClick callback. You need to write all of that in Javascript and call it in OnClientClick.

SLaks
Can you elaborate by what you mean "Call it in OnClientClick", with an example. Thanks.
Xaisoft
+3  A: 

What SLaks said is correct, you're misunderstanding the page lifecycle. The javascript code needs to be in place on the page before you click Save As. In your example as described, the user makes changes to the title/name and clicks Save As, after which the javascript code is applied to the button. The second time they click Save As, the validation results from the previous example pop up.

Option 1: Use a validator control

The simplest way to solve this is to use a RegularExpressionValidator control to compare the values.

Markup snippet:

<asp:Label ID="lblName" runat="server" Text="Name: " />
<asp:TextBox ID="txtName" runat="server" />
<asp:RegularExpressionvalidator ID="valName" runat="server" ControlToValidate="txtName" ErrorMessage="You must change the name before saving" Display="Dynamic" />

<asp:Button ID="btnSaveAs" runat="server" OnClick="btnSaveAs_Click" Text="Save As" CausesValidation="True" />

In your code-behind once the form fields (album name, etc.) are bound, run this:

valName.ValidationExpression = string.Format("[^{0}]", Regex.Escape(lblName.Text));

The above regular expression will be valid for any input except what was there to begin with. If the user changes the text for the album name, the save button will validate correctly. If they do not, the validator will kick in and display a message on the page saying they have to change it.

Then handle the OnClick event of the save button only for saving the values, because it will only fire if the page was validated:

protected void btnSaveAs_Click(object sender, EventArgs e)
{
    if (Page.IsValid)
    {
        //do you save actions as needed
    }
}

You can also still use your confirm box as you wanted, by doing:

protected void Page_Load(object sender, EventArgs e)
{
    btnSave.OnClientClick = "return confirm('Are you sure you wish to change the name?');";
}

The above should work just fine. An alternate approach is listed below:

Option 2: Use a clientside validation function

If you wanted to do the validation completely client side, you could but it will be far more complicated. What you'd need to do, is register a completely clientside validation function.

In your code behind during Page_PreRender:

protected void Page_PreRender(object sender, EventArgs e)
{
    //define the script
    string script = @"

    function validateAlbumName(oldName, textBoxId) {

        //get the textbox and its new name
        var newName = document.GetElementById(textBoxId).value;

        //compare the values 
        if (newName === oldName) {
            //if the name hasn't changed, 
            alert('You must change the name of the album');
            return false;
        }

        return confirm ('Are you sure you want to save the playlist ' + newName);  
    }

    ";

    //register the client script, so that it is available during the first page render
    Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "SaveAsValidation", script);

    //add the on client click event, which will validate the form fields on click the first time.
    btnSaveAs.OnClickClick = string.Format("return validateAlbumName('{0}','{1}');", txtAlbumName.Text, txtAlbumName.ClientID);

}

Hope this helps. There are likely some syntax errors in the above as I just threw it together quickly..

KP
I should note, I'm definitely no Regex guru so my regular expression above may be flawed. The concept would work though. The other option would be to use a asp:CompareValidator with a hidden field to track the old and new values.
KP
Your regex is incorrect; it will match any string that does not begin with any character in the original string.
SLaks
Will this still work if I am trying to access a TextBox that is an ItemTemplate of a ListView?
Xaisoft
@SLaks: Yeah as I said I'm not good with Regex. The concept is sound though.@Xaisoft: Yes it should still work fine. Each server-side control will have a unique ClientID. If it's inside the ItemTemplate you'll need to use ListView.FindControl method in the code-behind to get the control. You then have access to the clientID via the .ClientID property as usual.
KP