Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

Is there some easy way to handle multiple submit buttons from the same form? Example:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" value="Send" />
<input type="submit" value="Cancel" />
<% Html.EndForm(); %>

Any idea how to do this in ASP.NET Framework Beta? All examples I've googled for have single buttons in them.

share|improve this question

23 Answers

up vote 88 down vote accepted

You can check the name in the action as has been mentioned, but you might consider whether or not this is good design. It is a good idea to consider the responsibility of the action and not couple this design too much to UI aspects like button names. So consider using 2 forms and 2 actions:

<% Html.BeginForm("Send", "MyController", FormMethod.Post); %>
<input type="submit" name="button" value="Send" />
<% Html.EndForm(); %>

<% Html.BeginForm("Cancel", "MyController", FormMethod.Post); %>
<input type="submit" name="button" value="Cancel" />
<% Html.EndForm(); %>

Also, in the case of "Cancel", you are usually just not processing the form and are going to a new URL. In this case you do not need to submit the form at all and just need a link:

<%=Html.ActionLink("Cancel", "List", "MyController") %>
share|improve this answer
40  
This is ok when you dont need same form data for every submit button. If you need all data in common form than Dylan Beattie is the way to go. Is there any more elegant way to do this? – zidane Sep 28 '09 at 9:30
3  
About visual presentation, how in this case have the "Send" button next to the "Cancel" button ? – Kris-I Mar 9 '11 at 4:49
1  
Dylan: Well for a cancel button you don't need to submit the data at all and it is bad practice to couple the controller to the UI elements. However if you can make a more or less generic "command" then I think it is ok, but I would not tie it to "submitButton" as that is the name of a UI element. – Trevor de Koekkoek Mar 16 '11 at 15:08
1  
@Kris: you can position your buttons with CSS and they can still reside in 2 different form sections. – Trevor de Koekkoek Mar 16 '11 at 15:10
5  
seriously? does that not smell to anyone but me?! – iwayneo Nov 24 '11 at 11:48
show 2 more comments

This script allows to specify a data-form-action attribute which will work as the HTML5 formaction attribute in all browsers (in an unobtrusive way):

$(document).on('click', '[type="submit"][data-form-action]', function(event) {
    var $this = $(this),
    var formAction = $this.attr('data-form-action'),
    $form = $($this.closest('form'));
    $form.attr('action', formAction);             
});

The form containing the button will be posted to the URL specified in the data-form-action attribute:

<button type="submit" data-form-action="different/url">Submit</button>   

This requires jQuery 1.7. For previous versions you should use live() instead of on().

share|improve this answer
//model
    public class input_element
        {
         public string Btn { get; set; }
        }   

//views--submit btn can be input type also...
    @using (Html.BeginForm())
    {
            <button type="submit" name="btn" value="verify">
             Verify data</button>
            <button type="submit" name="btn" value="save">
             Save data</button>    
            <button type="submit" name="btn" value="redirect">
                 Redirect</button>
    }

//controller

    public ActionResult About()
        {
            ViewBag.Message = "Your app description page.";
            return View();
        }

        [HttpPost]
        public ActionResult About(input_element model)
        {
                if (model.Btn == "verify")
                {
                // the Verify button was clicked
                }
                else if (model.Btn == "save")
                {
                // the Save button was clicked
                } 
                else if (model.Btn == "redirect")
                {
                // the Redirect button was clicked
                } 
                return View();
        }
share|improve this answer
You may not have realized it, but this same answer was posted quite a few times to this question already. – Andrew Barber Feb 26 at 5:39
Also, you seem to post answers that only contain code, with no explanation. Would you consider adding some narrative to explain why the code works, and what makes it an answer to the question? This would be very helpful to the person asking the question, and anyone else who comes along. – Andrew Barber Feb 26 at 5:41
i have tested this and its working fine.. – SHAURAJ SINGH Feb 26 at 5:47
Sure, it works fine. But that answer has already been given by others, a long time ago. And they included explanations about why it works, too. – Andrew Barber Feb 26 at 5:49

Here is a mostly clean attribute-based solution to the multiple submit button issue based heavily on the post and comments from Maartin Balliauw.

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class MultipleButtonAttribute : ActionNameSelectorAttribute
{
    public string Name { get; set; }
    public string Argument { get; set; }

    public override bool IsValidName(ControllerContext controllerContext,
string actionName, MethodInfo methodInfo)
    {
        bool isValidName = false;
        string keyValue = string.Format("{0}:{1}", Name, Argument);
        var value = controllerContext.Controller.ValueProvider.GetValue(keyValue);
        if (value != null)
        {
            controllerContext.Controller.ControllerContext.RouteData.Values[Name] = Argument;
            isValidName = true;
        }

        return isValidName;
    }
}

razor:

<form action="" method="post">
 <input type="submit" value="Save" name="action:Save" />
 <input type="submit" value="Send" name="action:Send" />
</form>

and controller:

    [HttpPost]
    [MultipleButton(Name = "action", Argument = "Send")]
    public ActionResult Send(MessageModel mm) { ... }

    [HttpPost]
    [MultipleButton(Name = "action", Argument = "Save")]
    public ActionResult Save(MessageModel mm) { ... }
share|improve this answer
2  
I found this solution to be the happy marriage of the other techniques used. Works perfectly and doesn't effect localization. – nameEqualsPNamePrubeGoldberg Nov 29 '11 at 22:33
6  
+1 This is very good. – Dommer Jan 9 '12 at 18:31
6  
Great solution!! Much nore useful than those top scored answers – Oleksandr Pshenychnyy Feb 16 '12 at 17:23
Awesome, Thank @mkozicki – Frank Myat Thu May 24 '12 at 5:00
what is the line 'value = new ValueProviderResult(Argument, Argument, null);' used for? It seems redundant. – Junto Jan 9 at 13:48
show 4 more comments

I don't have enough rep to comment in the correct place, but I spent all day on this so want to share.

While trying to implement the "MultipleButtonAttribute" solution ValueProvider.GetValue(keyValue) would incorrectly come back null.

It turned out I was referencing System.Web.MVC version 3.0 when it should have been 4.0 (other assemblies are 4.0). I don't know why my project didn't upgrade correctly and I had no other obvious problems.

So if your ActionNameSelectorAttribute is not working... check that.

share|improve this answer

Just written a post about that: Multiple submit buttons with ASP.NET MVC :

Basically, instead of using ActionMethodSelectorAttribute, I am using ActionNameSelectorAttribute, which allows me to pretend the action name is whatever I want it to be. Fortunately, ActionNameSelectorAttribute does not just make me specify action name, instead I can choose whether the current action matches request. So there is my class (btw I am not too fond of the name):

public class HttpParamActionAttribute : ActionNameSelectorAttribute {
    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) {
        if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase))
            return true;

        if (!actionName.Equals("Action", StringComparison.InvariantCultureIgnoreCase))
            return false;

        var request = controllerContext.RequestContext.HttpContext.Request;
        return request[methodInfo.Name] != null;
    } } 

How to use it? Just have a form similar to this:

<% using

(Html.BeginForm("Action", "Post")) { %>   <!— …form fields… -->   <input type="submit" name="saveDraft" value="Save Draft" />   <input type="submit" name="publish" value="Publish" /> <% } %> 

and controller with two methods

public class PostController : Controller {
    [HttpParamAction]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult SaveDraft(…) {
        //…
    }

    [HttpParamAction]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Publish(…) {
        //…
    } }

As you see, the attribute does not require you to specify anything at all. Also, name of the buttons are translated directly to the method names. Additionally (I haven’t tried that) these should work as normal actions as well, so you can post to any of them directly. There is some room for improvements (hardcoded “action” as a default action name), but in general I’m satisfied with this solution.

share|improve this answer
1  
Beautiful! I think this is the most elegant solution. It eliminates the value of the submit tag from consideration, which is ideal since it is a pure-UI attribute that should have no bearing on the control-flow. Instead, the unique name attribute of each submit tag translates directly into a discrete action method on your controller. – Kirk Woll Oct 26 '11 at 4:29
+1 For me, it's by far the best solution for this problem. Since I implemented it, I notice that a lot of traffic pass throught the HttpParamActionAttribut but compared to all other things that Asp.Net MVC have to do while processing a request, it's totally acceptable. To only hack I have to do is put an empty 'Action' named in my controller to prevent Resharper warning me that the action 'Action' don't exist. Thank you very much! – Samuel Jan 18 at 18:39

In View the code is:

<script language="javascript" type="text/javascript">
    function SubmeterForm(id)
    {
        if (id=='btnOk')
            document.forms[0].submit(id);
        else
            document.forms[1].submit(id);
    }
</script>


<% Html.BeginForm("ObterNomeBotaoClicado/1", "Teste01", FormMethod.Post); %>
<input id="btnOk" type="button" value="Ok" onclick="javascript:SubmeterForm('btnOk')" />
<% Html.EndForm(); %>
<% Html.BeginForm("ObterNomeBotaoClicado/2", "Teste01", FormMethod.Post); %>
<input id="btnCancelar" type="button" value="Cancelar" onclick="javascript:SubmeterForm('btnCancelar')" />
<% Html.EndForm(); %>

In Controller the code is:

public ActionResult ObterNomeBotaoClicado(string id)
{
    if (id=="1")
        btnOkFunction(...);
    else
        btnCancelarFunction(...);
    return View();
}
share|improve this answer

I've tried to make a synthesis of all solutions and created a [ButtenHandler] attribute that makes it easy to handle multiple buttons on a form.

I've described it on CodeProject Multiple parameterized (localizable) form buttons in ASP.NET MVC.

To handle the simple case of this button:

<button type="submit" name="AddDepartment">Add Department</button>

You'll have something like the following action method:

[ButtonHandler()]
public ActionResult AddDepartment(Company model)
{
    model.Departments.Add(new Department());
    return View(model);
}

Notice how the name of the button matches the name of the action method. The article also describes how to have buttons with values and buttons with indexes.

share|improve this answer

For each submit button just add:

$('#btnSelector').click(function () {

    $('form').attr('action', "/Your/Action/);
    $('form').submit();

});
share|improve this answer

My Solution was to use 2 asp panels:

<asp:Panel ID=”..” DefaultButton=”ID_OF_SHIPPING_SUBMIT_BUTTON”….></asp:Panel>

share|improve this answer

Here is what works best for me:

<input type="submit" value="Delete" name="onDelete" />
<input type="submit" value="Save" name="onSave" />


public ActionResult Practice(MyModel model, string onSave, string onDelete)
{
    if (onDelete != null)
    {
        // Delete the object
        ...
        return EmptyResult();
    }

    // Save the object
    ...
    return EmptyResult();
}
share|improve this answer
I get null value for onDelete and onSave in the controller method. Do you know why? – Diganta Kumar Jan 24 at 2:30
Either one won't be null if you click the according button. Which button do you click getting the null? – Sergey Jul 8 at 17:50

this is the best way that i have found:

http://blogs.sonatribe.com/wayne/2011/08/15/acceptparameterattribute-update/

Here is the code:

    /// <summary>
    /// ActionMethodSelector to enable submit buttons to execute specific action methods.
    /// </summary>
    public class AcceptParameterAttribute : ActionMethodSelectorAttribute
   {
        /// <summary>
        /// Gets or sets the value to use to inject the index into
        /// </summary>
       public string TargetArgument { get; set; }

       /// <summary>
       /// Gets or sets the value to use in submit button to identify which method to select. This must be unique in each controller.
       /// </summary>
       public string Action { get; set; }

       /// <summary>
       /// Gets or sets the regular expression to match the action.
       /// </summary>
       public string ActionRegex { get; set; }

       /// <summary>
       /// Determines whether the action method selection is valid for the specified controller context.
       /// </summary>
       /// <param name="controllerContext">The controller context.</param>
       /// <param name="methodInfo">Information about the action method.</param>
       /// <returns>true if the action method selection is valid for the specified controller context; otherwise, false.</returns>
       public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
       {

           if (controllerContext == null)
           {
               throw new ArgumentNullException("controllerContext");
           }

           Func<NameValueCollection> formGetter;
           Func<NameValueCollection> queryStringGetter;

           ValidationUtility.GetUnvalidatedCollections(HttpContext.Current, out formGetter, out queryStringGetter);

           var form = formGetter();
           var queryString = queryStringGetter();

           var req = form.AllKeys.Any() ? form : queryString;

           if (!string.IsNullOrEmpty(this.ActionRegex))
           {
               foreach (var key in req.AllKeys.Where(k => k.StartsWith(Action, true, System.Threading.Thread.CurrentThread.CurrentCulture)))
               {
                   if (key.Contains(":"))
                   {
                       if (key.Split(':').Count() == this.ActionRegex.Split(':').Count())
                       {
                           bool match = false;
                           for (int i = 0; i < key.Split(':').Count(); i++)
                           {
                               if (Regex.IsMatch(key.Split(':')[0], this.ActionRegex.Split(':')[0]))
                               {
                                   match = true;
                               }
                               else
                               {
                                   match = false;
                                   break;
                               }
                           }

                           if (match)
                           {
                               return !string.IsNullOrEmpty(req[key]);
                           }
                       }
                   }
                   else
                   {
                       if (Regex.IsMatch(key, this.Action + this.ActionRegex))
                       {
                           return !string.IsNullOrEmpty(req[key]);
                       }
                   }

               }
               return false;
           }
           else
           {
               return req.AllKeys.Contains(this.Action);
           }
       }
   }

Enjoy a code-smell-less multi submit button future.

thank you

share|improve this answer

If you do not have restrictions on the use of HTML 5, you can use the <button> tag with formaction Attribute:

<form action="demo_form.asp" method="get">
   First name: <input type="text" name="fname" /><br />
   Last name: <input type="text" name="lname" /><br />
   <button type="submit">Submit</button><br />
   <button type="submit" formaction="demo_admin.asp">Submit as admin</button>
</form>

Reference: http://www.w3schools.com/html5/att_button_formaction.asp

share|improve this answer

My JQuery approach using an extension method:

public static MvcHtmlString SubmitButtonFor<TController>(this HtmlHelper helper, Expression<Action<TController>> action, string value) where TController : Controller
{
    RouteValueDictionary routingValues = Microsoft.Web.Mvc.Internal.ExpressionHelper.GetRouteValuesFromExpression(action);

    var onclick = string.Format("$('form').first().attr('action', '/{0}')", string.Join("/", routingValues.Values.ToArray().Where(x => x != null).Select(x => x.ToString()).ToArray()));
    var html = "<input type=\"submit\" value=\"" + value + "\" onclick=\"" + onclick + "\" />";

    return MvcHtmlString.Create(html);
}

You can use it like this:

@(Html.SubmitButtonFor<FooController>(c => c.Save(null), "Save"))

And it renders like this:

<input type="submit" value="Save" onclick="$('form').first().attr('action', '/Foo/Save')" >
share|improve this answer

Here's an extension method I wrote to handle multiple image and/or text buttons.

Here's the HTML for an image button:

<input id="btnJoin" name="Join" src="/content/images/buttons/btnJoin.png" 
       type="image">

or for a text submit button :

<input type="submit" class="ui-button green" name="Submit_Join" value="Add to cart"  />
<input type="submit" class="ui-button red" name="Submit_Skip" value="Not today"  />

Here is the extension method you call from the controller with form.GetSubmitButtonName(). For image buttons it looks for a form parameter with .x (which indicates an image button was clicked) and extracts the name. For regular input buttons it looks for a name beginning with Submit_ and extracts the command from afterwards. Because I'm abstracting away the logic of determining the 'command' you can switch between image + text buttons on the client without changing the server side code.

public static class FormCollectionExtensions
{
    public static string GetSubmitButtonName(this FormCollection formCollection)
    {
        return GetSubmitButtonName(formCollection, true);
    }

    public static string GetSubmitButtonName(this FormCollection formCollection, bool throwOnError)
    {
        var imageButton = formCollection.Keys.OfType<string>().Where(x => x.EndsWith(".x")).SingleOrDefault();
        var textButton = formCollection.Keys.OfType<string>().Where(x => x.StartsWith("Submit_")).SingleOrDefault();

        if (textButton != null)
        {
            return textButton.Substring("Submit_".Length);
        }

        // we got something like AddToCart.x
        if (imageButton != null)
        {
            return imageButton.Substring(0, imageButton.Length - 2);
        }

        if (throwOnError)
        {
            throw new ApplicationException("No button found");
        }
        else
        {
            return null;
        }
    }
}

Note: For text buttons you have to prefix the name with Submit_. I prefer this way becuase it means you can change the text (display) value without having to change the code. Unlike SELECT elements, an INPUT button has only a 'value' and no separate 'text' attribute. My buttons say different things under different contexts - but map to the same 'command'. I much prefer extracting the name this way than having to code for == "Add to cart".

share|improve this answer
I like checking the name as an alternative because you can't always check for the value for eg. you have a list of items and each has a "Delete" button. – Max Aug 26 '11 at 11:09

Give your submit buttons a name, and then inspect the submitted value in your controller method:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="submitButton" value="Send" />
<input type="submit" name="submitButton" value="Cancel" />
<% Html.EndForm(); %>

posting to

public class MyController : Controller {
    public ActionResult MyAction(string submitButton) {
        switch(submitButton) {
            case "Send":
                // delegate sending to another controller action
                return(Send());
            case "Cancel":
                // call another action to perform the cancellation
                return(Cancel());
            default:
                // If they've submitted the form without a submitButton, 
                // just return the view again.
                return(View());
        }
    }

    private ActionResult Cancel() {
        // process the cancellation request here.
        return(View("Cancelled"));
    }

    private ActionResult Send() {
        // perform the actual send operation here.
        return(View("SendConfirmed"));
    }

}

EDIT:

To extend this approach to work with localized sites, isolate your messages somewhere else (e.g. compiling a resource file to a strongly-typed resource class)

Then modify the code so it works like:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="submitButton" value="<%= Html.Encode(Resources.Messages.Send)%>" />
<input type="submit" name="submitButton" value="<%=Html.Encode(Resources.Messages.Cancel)%>" />
<% Html.EndForm(); %>

and your controller should look like this:

// Note that the localized resources aren't constants, so 
// we can't use a switch statement.

if (submitButton == Resources.Messages.Send) { 
    // delegate sending to another controller action
    return(Send());

} else if (submitButton == Resources.Messages.Cancel) {
     // call another action to perform the cancellation
     return(Cancel());
}
share|improve this answer
This is what I was looking for here: stackoverflow.com/questions/649513/… - thanks – paulwhit Mar 17 '09 at 2:44
Just what I needed ... thanks – jalchr Jan 10 '10 at 12:13
10  
too bad you depend on the text displayed on the button, it's kinda tricky with a multilanguage user interface – Omu Apr 22 '10 at 11:52
2  
Switch/case only works with constants, so the localized version can't use switch/case. You need to switch to if else or some other dispatch method. – mcl Nov 1 '10 at 20:58
1  
blogs.sonatribe.com/wayne/2011/03/03/… this is how i do it. – iwayneo Apr 13 '11 at 8:39
show 10 more comments

I would suggest interested parties have a look at a solution i think is very elegant here >> http://blog.maartenballiauw.be/post/2009/11/26/Supporting-multiple-submit-buttons-on-an-ASPNET-MVC-view.aspx

In case the link dissapears its using the MultiButton attribute applied to a controller action to indicate which button click that action should relate to.

share|improve this answer
1  
+1 Lovely solution .. quite crisp and clean! – Rashmi Pandit Aug 23 '10 at 5:53
This is the solution we are using now and its very neat. Is it MVC 2 only though? – Simon Keep Nov 2 '10 at 15:30
This is beautiful! I'd not seen this before! While I agree that you may want to redesign any solution that is using multiple submits to only use one button, I'm in a spot where I'm hamstrung and must do this. This answer should have won! – Rikon Sep 30 '11 at 14:19
This is a great solution. Very clean – Arnej65 Oct 24 '11 at 13:42
1  
Agree this should win. – daddywoodland Nov 15 '11 at 12:20
show 1 more comment

This is the technique I'd use and I don't see it here yet. The link (posted by Saajid Ismail ) that inspires this solution is http://weblogs.asp.net/dfindley/archive/2009/05/31/asp-net-mvc-multiple-buttons-in-the-same-form.aspx). It adapts Dylan Beattie's answer to do localization without any problems.

In the View:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<button name="button" value="send"><%: Resources.Messages.Send %></button>
<button name="button" value="cancel"><%: Resources.Messages.Cancel %></button>
<% Html.EndForm(); %>

In the Controller:

public class MyController : Controller 
{
    public ActionResult MyAction(string button)
    {
         switch(button)
         {
             case "send":
                 this.DoSend();
                 break;
             case "cancel":
                 this.DoCancel();
                 break;
         }
    }
}
share|improve this answer
Looks like the solution Ironicnet provided. – XIII Nov 2 '10 at 15:02
Certainly similar, but this shows both localization and the controller code, which is something I didn't see done this way in this thread. I found this thread while looking for how to do this and wanted to document what I came up with for anyone else who might be in the same boat. – mcl Nov 3 '10 at 11:56
1  
In fact, it's not the same as Ironicnet's beyond that. He uses <input> elements. I use <button>, which is required to do the localization without having variable value attributes. – mcl Nov 3 '10 at 11:59

You could write:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="button" value="Send" />
<input type="submit" name="button" value="Cancel" />
<% Html.EndForm(); %>

And then in the page check if the name == "Send" or name == "Cancel"...

share|improve this answer
Although this is working, but I think it's wrong practice to have two elements with the same name. – Péter Jul 5 at 11:25

David Findley writes about 3 different options you have for doing this, on his ASP.Net weblog.

Read the article multiple buttons in the same form to see his solutions, and the advantages and disadvantages of each. IMHO he provides a very elegant solution which makes use of attributes that you decorate your action with.

share|improve this answer

Eilon suggests you can do it like this:

If you have more than one button you can distinguish between them by giving each button a name:

<input type="submit" name="SaveButton" value="Save data" />
<input type="submit" name="CancelButton" value="Cancel and go back to main page" />

In your controller action method you can add parameters named after the HTML input tag names:

public ActionResult DoSomeStuff(string saveButton, string
cancelButton, ... other parameters ...)
{ ... }

If any value gets posted to one of those parameters, that means that button was the one that got clicked. The web browser will only post a value for the one button that got clicked. All other values will be null.

if (saveButton != null) { /* do save logic */ }
if (cancelButton != null) { /* do cancel logic */ }

I like this method as it does not rely on the value property of the submit buttons which is more likely to change than the assigned names and doesn't require javascript to be enabled

See: http://forums.asp.net/p/1369617/2865166.aspx#2865166

share|improve this answer
If anyone comes across this old question, this is the cleanest answer if you don't wan't to use HTML5 <button> elements. If you don't mind HTML5 then use <button> with value attribute. – Kugel Jun 12 at 1:28

I'm not yet familiar with the framework, but generally I would use javascript. Something along the lines (syntax will likely be wrong):

<script type ="text/javascript">
function sendTo(url)
{
  document.myForm.action = url;
  document.myForm.submit();
}
</script>

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="button" value="Send to page 1" onclick="javascript:sendTo('page1')"/>
<input type="button" value="Send to page 2" onclick="javascript:sendTo('page2')" />
<% Html.EndForm(); %>
share|improve this answer
hmm... what is so wrong with this solution? – ya23 Jan 15 '09 at 8:58
2  
MyAction and MyController define what the form gets submitted to. If you do javascript on it, you would lose things like model mapping to the controller action. – paulwhit Mar 17 '09 at 2:33

You should be able to name the buttons and give them a value; then map this name as an argument to the action. Alternatively, use 2 separate action-links or 2 forms.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.