How to link 2 actions to 1 form - c#

I'm not sure if what I'm asking is even possible. I have a form with a checkbox list and button above it. The user selects from the list and then clicks the button and it writes to the db. Now i would like to add a second button that will do something different to the selection. How would I go about about linking this second button to a different action?
current code:
#using (Html.BeginForm("RemoveFromAvailable", "GroupPlayManager", new { id = Model.Id, slug = Model.Slug, innerid = Model.GroupPlayManagerId }, FormMethod.Post, null))
{
<div class="hMarginBottom15">
<input type="hidden" class="groupPlay-id" name="GroupPlayId" value="#Model.GroupPlayInput.Id" />
<input type="hidden" name="GroupPlayManagerId" value="#Model.GroupPlayManagerId" />
<input type="hidden" name="GroupPlayDateTime" value="#Model.GroupPlayInput.GroupPlayDate" />
<button name="RemoveFromAvailable" id="unavailableButton" class="btn btn-danger" disabled="disabled">Remove</button>
</div>
#Html.EditorFor(
m => m.AvailablePlayers,
"BootstrapHorizontalCheckboxList",
new
{
data = Model.AvailablePlayersDates.Select(tm => new SelectListItem
{
Text = tm.Name,
Value = tm.Id,
}).ToList(),
chunksize = 1,
isRequired = true,
displaylabel = false,
cssClass = "col-md-12"
})
}

Name your buttons and then branch in your action accordingly. For example:
<button type="submit" name="_Save">Save</button>
<button type="submit" name="_SomethingElse">Something Else</button>
Then, in your action:
if (Request["_Save"] != null))
{
// save
}
else if (Request["_SomethingElse"] != null))
{
// do something else
}
The key will only be present if the user clicked that particular button.

Related

How to let a button disappear after an action and reappear after another action

i have a code that can allow a button to be visible if some values have been saved to a database or in this case has been bookmarked and becomes visible in the front end if it has been deleted from the database.ie has not been bookmarked
verseModel.Verses = verses;
var bookmarksForCurrentChapter = _context.Bookmarks.Where(x => x.ChapterId == id).ToList();
foreach (var verse in verses)
{
foreach (Bookmark bookmark in bookmarksForCurrentChapter)
{
if (bookmark.VerseId == verse.VerseId)
{
verse.IsBookmarked = true;
}
}
}
This is the code to check for if the values have been bookmarked or saved in the database
#if (!verse.IsBookmarked)
{
<td>
<form asp-action="SaveBookmark" method="post">
<input type="hidden" name="id" value="#verse.VerseId" />
<input type="hidden" name="text" value="#verse.VerseText" />
<input type="hidden" name="chapterid" value="#Model.ChapterId" />
<button class="btn btn-outline-primary btn-sm">Save</button>
</form>
</td>
this is the frontend section that makes the button visible when the values are not bookmarked or saved in the database.
So my question is that i want to be add a delete button to this page so that if the value is bookmarked or saved in the database it becomes visible while the save button disappears and if the value has been deleted from the database from this page or from the database directly the delete button will disappear whiles the save button will reappear
else
{
<td>
<form asp-action = "DeleteBookmark" >
<input type = "hidden" name= "id" value = "#verse.VerseId"/>
<button class = "btn btn-danger btn-sm">Delete</button>
</form>
</td>
}
this is what i attempted to do but the button does not work when clicked and if the values are deleted from the database it does not affect the page at all

Passing values to controller

In my controller i have IActionResult, which takes 3 strings
public IActionResult DeviceDetails(string idDetails, string begindate, string enddate)
{....}
I like to pas this strings from web page, where user can chose begin and end date from datepicker, so i have:
<input id="begindate" type="date" class="btn btn-default"/>
<input id="enddate" type="date" class="btn btn-default" />
<button type="submit" value="show data" class="btn btn-default">#Html.ActionLink("Show data", "DeviceDetails", new { idDetails = ViewBag.DeviceName, begindate ="begindate", enddate = "enddate" }) </button>
How can i pass values from id="begindate" and id="enddate" to Html.ActionLink (idDetails works fine)?
Or, how can i pass this two string to controller in different way?
You can generate ActionLink using temporary placeholder values inside routeValues and put an ID to anchor element:
<button type="submit" value="show data" class="btn btn-default">#Html.ActionLink("Show data", "DeviceDetails", new { idDetails = ViewBag.DeviceName, begindate = "xxxx", enddate = "yyyy" }, new { id = "showdata" })</button>
Then, use plain JS/jQuery to handle click client-side event which replaces temporary placeholder values into real values from date input (below is using jQuery):
$('#showdata').click(function(e) {
var beginDate = $('#begindate').val();
var endDate = $('#enddate').val();
var tempValue = $(this).prop('href');
var realValue = tempValue.replace("xxxx", beginDate)
.replace("yyyy", endDate);
location.href = realValue; // redirect
return false; // cancel default redirect
});
As a side note, better to use a strongly-typed viewmodel and pass input values to controller action method using viewmodel properties rather than building large amount of query strings.
Live example: DotNET Fiddle
Try this:
ActionLink (default):
#Html.ActionLink("YourAction", "YourController", new { id = item.ID })
ActionLink (using Button):
<button onclick="location.href='#Url.Action("YourAction", "YourController",
new { Model.ProductID })';return false;">Details</button>
or
<input type="button" title="Details" value="Details" onclick="location.href=
'#Url.Action("YourAction", "YourController", new { id = item.ID })'" />

Incorrect List Model Binding indices when using HTML Helpers

this is a tricky one to explain, so I'll try bullet pointing.
Issue:
Dynamic rows (collection) available to user on View (add/delete)
User deletes row and saves (POST)
Collection passed back to controller with non-sequential indices
Stepping through code, everything looks fine, collection items, indices etc.
Once the page is rendered, items are not displaying correctly - They are all out by 1 and therefore duplicating the top item at the new 0 location.
What I've found:
This happens ONLY when using the HTML Helpers in Razor code.
If I use the traditional <input> elements (not ideal), it works fine.
Question:
Has anyone ever run into this issue before? Or does anyone know why this is happening, or what I'm doing wrong?
Please check out my code below and thanks for checking my question!
Controller:
[HttpGet]
public ActionResult Index()
{
List<Car> cars = new List<Car>
{
new Car { ID = 1, Make = "BMW 1", Model = "325" },
new Car { ID = 2, Make = "Land Rover 2", Model = "Range Rover" },
new Car { ID = 3, Make = "Audi 3", Model = "A3" },
new Car { ID = 4, Make = "Honda 4", Model = "Civic" }
};
CarModel model = new CarModel();
model.Cars = cars;
return View(model);
}
[HttpPost]
public ActionResult Index(CarModel model)
{
// This is for debugging purposes only
List<Car> savedCars = model.Cars;
return View(model);
}
Index.cshtml:
As you can see, I have "Make" and "Actual Make" inputs. One being a HTML Helper and the other a traditional HTML Input, respectively.
#using (Html.BeginForm())
{
<div class="col-md-4">
#for (int i = 0; i < Model.Cars.Count; i++)
{
<div id="car-row-#i" class="form-group row">
<br />
<hr />
<label class="control-label">Make (#i)</label>
#Html.TextBoxFor(m => m.Cars[i].Make, new { #id = "car-make-" + i, #class = "form-control" })
<label class="control-label">Actual Make</label>
<input class="form-control" id="car-make-#i" name="Cars[#i].Make" type="text" value="#Model.Cars[i].Make" />
<div>
<input type="hidden" name="Cars.Index" value="#i" />
</div>
<br />
<button id="delete-btn-#i" type="button" class="btn btn-sm btn-danger" onclick="DeleteCarRow(#i)">Delete Entry</button>
</div>
}
<div class="form-group">
<input type="submit" class="btn btn-sm btn-success" value="Submit" />
</div>
</div>
}
Javascript Delete Function
function DeleteCarRow(id) {
$("#car-row-" + id).remove();
}
What's happening in the UI:
Step 1 (delete row)
Step 2 (Submit form)
Step 3 (results)
The reason for this behavior is that the HtmlHelper methods use the value from ModelState (if one exists) to set the value attribute rather that the actual model value. The reason for this behavior is explained in the answer to TextBoxFor displaying initial value, not the value updated from code.
In your case, when you submit, the following values are added to ModelState
Cars[1].Make: Land Rover 2
Cars[2].Make: Audi 3
Cars[3].Make: Honda 4
Note that there is no value for Cars[0].Make because you deleted the first item in the view.
When you return the view, the collection now contains
Cars[0].Make: Land Rover 2
Cars[1].Make: Audi 3
Cars[2].Make: Honda 4
So in the first iteration of the loop, the TextBoxFor() method checks ModelState for a match, does not find one, and generates value="Land Rover 2" (i.e. the model value) and your manual input also reads the model value and sets value="Land Rover 2"
In the second iteration, the TextBoxFor() does find a match for Cars[1]Make in ModelState so it sets value="Land Rover 2" and manual inputs reads the model value and sets value="Audi 3".
I'm assuming this question is just to explain the behavior (in reality, you would save the data and then redirect to the GET method to display the new list), but you can generate the correct output when you return the view by calling ModelState.Clear() which will clear all ModelState values so that the TextBoxFor() generates the value attribute based on the model value.
Side note:You view contains a lot of bad practice, including polluting your markup with behavior (use Unobtrusive JavaScript), creating label element that do not behave as labels (clicking on them will not set focus to the associated control), unnecessary use of <br/> elements (use css to style your elements with margins etc) and unnecessary use of new { #id = "car-make-" + i }. The code in your loop can be
#for (int i = 0; i < Model.Cars.Count; i++)
{
<div class="form-group row">
<hr />
#Html.LabelFor(m => m.Cars[i].Make, "Make (#i)")
#Html.TextBoxFor(m => m.Cars[i].Make, new { #class = "form-control" })
....
<input type="hidden" name="Cars.Index" value="#i" />
<button type="button" class="btn btn-sm btn-danger delete">Delete Entry</button>
</div>
}
$('.delete').click(function() {
$(this).closest('.form-group').remove();
}

Last input values passed to action in MVC

I want to generate table with, for example, 4 columns. In last column i need link to remove user whitch is in that row. When i am using form tag like this:
#foreach (var item in Model.Approvers)
{
<tr>
<td>#item.FullName</td>
<td>#item.Email</td>
<td>#item.AdAccount</td>
<td>
<form id="removeApproverRoleForm" action="~/Admin/RemoveRole" method="post">
#Html.AntiForgeryToken()
<input type="text" id="userId" name="userId" value="#item.Id" />
<input type="text" id="role" name="role" value="Approver" />
Remove
</form>
</td>
</tr>
}
It passes last value of userId and role to RemoveRole method. It have to be POST method so this whould not work:
#Html.ActionLink(Remove, "RemoveRole", "Admin", new { role = "Approver", userid = item.Id }, new { onclick = "return removeRole();" })
Even if i place form tag above that, the parameters are still visible in the link.
So i need somehow use new { role = "Approver", userid = item.Id } but send it as a POST and hide those values.
Any ideas?
Thank you for help!
It is a popular problem, so you can find detailed solution here
Short answer is:
use <input type="submit">Remove</input> inside the form
OR use
#Ajax.ActionLink("Remove, "RemoveRole", "Admin", new { role = "Approver", userid = item.Id }, new AjaxOptions { HttpMethod = "POST" })
to be able to create ActionLink with controlling the method parameter.

How To Hide Input Fields Based On Enum Radio Button Selection .NET MVC

I have developed a page in C# using the MVC Razor technique,My code is following
<div class="col-md-4">
<label for="" class="control-label">
IDMS Reference <font color="red">*</font></label><br />
<div class="radio col-md-4">
#Html.EnumRadioButtonFor(m => m.enumIDMSReference, false).DisableIf(() =>
Model.IdmsRef == 2)
</div>
<div class="col-md-4">
<label for="" class="control-label">
IDMS Reference Number <font color="red">*</font></label><br />
#Html.TextBoxFor(m => m.IdmsRefNo, new { #class = "form-control"
}).DisableIf(() => Model.InwardBranch == true)
</div>
And my Enum class is following,
public enum enumIDMSReference
{
[Description("Applicable")]
Applicable = 1,
[Description("Not Applicable")]
NotApplicable = 2,
}
Here if we click the Not Applicable radio button, then the IDMS Reference Number input field should be disable and the input IdmsRefNo field should enable only for the applicable radio button so how to do it in JQuery or any other solution?.
Please anybody help
If I understood your question right, you want to disable a field based on the selected radio option. You can bind the change event of your radio buttons and disable/enable your textbox accordingly. [.NET FIDDLE]
$('input[name="enumIDMSReference"]').change(function() {
if ($(this).is(':checked') && $(this).val() == 'NotApplicable') {
$('#IdmsRefNo').attr('disabled', 'disabled');
} else {
$('#IdmsRefNo').removeAttr('disabled');
}
});
You can iterate across your enum values like so (I'm not checking for nulls, which you can do on your own):
#foreach (var value in Enum.GetValues(Model.enumIDMSReference.GetType()))
{
var memInfo = Model.enumIDMSReference.GetType().GetMember(value.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
var description = ((DescriptionAttribute)attributes[0]).Description;
#Html.RadioButtonFor(m => m.enumIDMSReference, value);
#Html.Label(description);
#Html.Raw("<br />");
}
You can expand this further by disabling/enabling the textbox by default server-side depending on the value of enumIDMSReference.

Categories