Multiple buttons in a form
The first challenge you will face is to have multiple buttons in a form. As you know, you usually have a submit button in a form, but in this case we should have more than one. This is a problem well solved by ASP.Net MVC by using a derived type of ActionNameSelectorAttribute.
Here you can find a possible implementation of this attribute:
As you can see, basically what we are doing is checking the value of the button is the same than the name of the method in case the action was triggered by a button with the name specified in the SubmitButtonActionName property.
To use this attribute we need to make changes in both the controller and the view. Let's see both changes and I will explain them later:
As you can see, in the view we are setting the name and the value of an extra submit button. In the controller we should decorate an action with the MultipleActionButton attribute, setting the SubmitActionName property with the same value that we've specified in the name attribute of the button. The name of the action must be the same as the value of the value attribute of the button.
In our application, we need to tell our backend what ingredient we want to add. Using the previous attribute is not enough, unless we want to end with a lot of actions doing the same thing (wich doesn't seem a very good idea). So we need to somehow pass a parameter to the controller, telling it with ingredient we want to add from the results search or we want to remove from the list of ingredients. Here we have to be more imaginative and combine an ActionNameSelectorAttribute with an ActionFilterAttribute. Let's start taking a look at the view:
What are we doing here is creating a value of the button like UseIngredient-0 for the first item in the list, UseIngredient-1 for the second one, etc. If we do that, we can no longer use the implementation of the ActionNameSelectorAttribute recently explained because we'd need an action called UseIngredient-0, an action called UseIngredient-1, etc. So, we need a new implementation of the attribute that extracts the real name of the action. Something like this:
Basically is the same code than the previous implementation, but we remove the parameter information before doing the comparison.
What problem do we have now? Well, right now our actions don't know anything about the parameter, we need to do something to pass the parameter to the action.
ActionFilters to the rescue
An ActionFilter is a mechanism to add custom behavior before or after an action is executed. In our case what we want is to inject the value of the parameter in the action. To do that we can write an ActionFilter like this one:
In this piece of code we are retrieving the original value of the button which triggered the action (line 11), extracting the value of the parameter (line 12), converting the value (a string) to the appropiate type (line 14) and injecting the value into the action (line 15).
Finally we just have to appy this filter in an action using the appropiate values: