Send List of IDs from List of Object From View to Controller C# - asp.net-core

I have a view with a list of objects as its model
#model List<Users>
Inside that view, I have a form and button to submit the form in ASP.NET Core MVC:
<input class="btn btn-success ml-2" style=" width: 100px;"
type="submit" value="#localizer["Save"]" />
I need another button to cancel form submission and redirect to another method but I need to pass the list of Users with redirection at cancel button
I tried
<a asp-controller="User" asp-action="cancel" asp-route-ids="#Model.Select(x => x.id);">Cancel</a>
but it didn't work, the list is empty

If you use asp-route-somekey to set the query, your target list name was recognized as value of the key "Ids",you could see the result as below:
If you do want to pass list to the query,you could try:
<a asp-controller="User" asp-action="Cancel" asp-all-route-data="#(new Dictionary<string, string> { { "Ids[0]", "1" },{ "Ids[1]", "2" } })">Cancel</a>
The result:
However the length of url is limited, it may cause some errors

Related

How can I post the same data to two different handlers depending on the button clicked?

[See updates at bottom]
I have a Razor page with a form on it. I want to have two buttons on that form, that perform a slightly different action - both using the same posted form data.
I tried using the asp-page-handler helper on the second button, but it doesn't seem to add anything to the HTML (I would expect it to add a formaction attribute to the <button> element, but it doesn't add anything at all).
Here's an example page:
#page "{id?}"
#model IndexModel
#tagHelperPrefix x:
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<p>Current value is #Model.Foo</p>
<x:form method="post">
<input type="text" name="foo" />
<button type="submit">Default</button>
<button type="submit" x:asp-page-handler="Alternative">Alternative</button>
</x:form>
... and here's the corresponding page model:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace MyWebApplication.Pages
{
public class IndexModel : PageModel
{
[BindProperty]
public string Foo { get; set; }
public void OnGet(int? id)
{
}
public void OnPostAsync(string foo)
{
Foo = foo;
}
public void OnPostAlternativeAsync(string foo)
{
Foo = foo.ToUpper();
}
}
}
This is rendered as:
...where the generated HTML for the form is:
<form method="post">
<input type="text" name="foo" />
<button type="submit">Default</button>
<button type="submit" x:asp-page-handler="Alternative">Alternative</button>
</form>
The fact that the x:asp-page-handler attribute is still in the generated HTML makes me think that the Razor engine hasn't recognized it. I've tried taking off the x: prefix, but that didn't help.
What am I doing wrong?
UPDATE
OK, I tried removing the tag prefix and removing the #tagHelperPrefix line, and that made a difference. A formaction is added to the second <button> element as expected.
However:
that's really annoying - the #tagHelperPrefix is not something I want to lose, and
now both buttons are triggering the "Alternative" action, even though only one of them has the formaction!
Here's the new generated HTML:
<form method="post">
<input type="text" name="foo" />
<button type="submit">Default</button>
<button type="submit" formaction="/?handler=Alternative">Alternative</button>
</form>
SECOND UPDATE
OK, so If I put asp-page-handler="" on the "default" button, then each button goes to the correct handler, which is fine.
The last question that remains, then, is: how can I make this work with the tag helper prefix?
[Answering my own question in case this helps others.]
It turns out that:
The tag-helper-prefix only applies to elements, not attributes, so it should be asp-page-handler="..." rather than x:asp-page-handler="..." even if the tag-helper-prefix is x:.
Those asp- attributes are only recognized within a tag that is tag-helper-enabled - which is all elements when no tag-helper-prefix is specified, or only elements with the tag-helper-prefix where one is specified. In my case, I had to change <button ...> to <x:button ...>.
If you specify asp-page-handler for one button, you need to specify it on all the buttons, even if you specify it as "" to get the default action.

How to create two Action Results in Controller form the same view MVC?

I would like to have two buttons in my view (called Create), one that submits the form and takes the user back to home page if they are finished and one that submits the form but reloads the rating page to be able to add additional ratings.
Here is the problem that I have right now-
Currently I have one button that has an action result in my controller:
public ActionResult Create(Rating rating)
{
if (ModelState.IsValid)
{
db.Ratings.Add(rating);
db.SaveChanges();
return RedirectToAction("Index");
}
**Additional code that is irrelevant here
}
The problem that I am faced with is that this ActionResult has a Redirect in it to the homepage so when I submit my other button and use this same ActionResult class it is being redirected to the homepage. I am using the javascript onclick event in the view to redirect to the Ratings page when the button is clicked and the form is submitted but if I use this same Action Result class for both buttons it redirects the button I want to keep me on the page to the index page.
How do I create two Action Result classes from the same view, one for each submit button?
Well, how do you determine what the user wants to do?
Both buttons submit the form, so they may as well still use the same action. But you need to differentiate somehow. You can do that with the buttons.
Let's say you have these two buttons:
<input type="submit" name="redirect" value="true" />
<input type="submit" name="redirect" value="false" />
Then you can bind that in your action method:
public ActionResult Create(Rating rating, bool redirect)
{
// other logic
if (redirect)
return RedirectToAction("Index");
else
return View(rating);
}
If you are ever going to have more than two possible options then you might use a string instead of a boolean. Something like:
<input type="submit" name="action" value="redirect" />
<input type="submit" name="action" value="reload" />
And then in the controller:
public ActionResult Create(Rating rating, string action)
{
// other logic
if (action.Equals("redirect"))
return RedirectToAction("Index");
else if (action.Equals("reload"))
return View(rating);
else if //...
//... and so on
}
The point is that the client-side code needs to tell the server-side code what to do somehow. Including that on the form submission itself makes the form submission self-describing and allows the server-side code to handle it easily.
Example of how it use
Html, inside form:
<button type="submit" name="TaskSubmitAction" value="ActionReject" class="btn btn-danger pull-left">Reject</button>
<button type="submit" name="TaskSubmitAction" value="ActionSubmit" class="btn btn-success">Accept</button>
Controller:
public ActionResult TaskSubmit(int? id, string TaskSubmitAction)
{
switch (TaskSubmitAction)
{
case "ActionSubmit":
break;
case "ActionReject":
break;
default: throw new Exception();
}
In your html give both buttons the same 'name' attribute but assign two different values.
<button name="submitBtn" value="valueX"> Button 1 </button>
<button name="submitBtn" value="valueY"> Button 2 </button>
In your server side code get the value of the input button and based on this value carry out different actions
String choice = request.getParamter("submitBtn");
if(choice.equals("valueX"))
//do something
else if(choice.equals("valueY"))
//do something else

Calling Post method using HTML.ActionLink

I have read multiple posts on similar issue but did not work.
I have fixed footer buttons and facing issue in calling "Post" version Edit action in Project controller. Here is what I'm trying to do
Let me know if question needs further explaination.
(I tried using Ajax.ActionLink which is suggested in multiple posts too but did not work out.
Similar Question
Finally I managed to fix it by some workarounds. Posting solution here to help someone.
Like I said earlier, I tried using Ajax.ActionLink but I was not able to achieve the same. Instead I looked for Calling Form Submit action from outside of form that's what I actually need here.
Form: Name your Form something, say "editProjDetailsForm"
#using (Html.BeginForm(null, null, FormMethod.Post,
new { #class = "form-horizontal",
name = "editProjDetailsForm" }))
Footer: Call this method from the footer button.
<input type="button" onclick="document.editProjDetailsForm.submit();"
class="btn btn-primary"
value="Save Changes" />
I tried this one too in footer but it did not workout:
#Ajax.ActionLink("Save Changes", "Edit", new { id = Model.ProjectId },
new AjaxOptions { HttpMethod = "POST" })
Helpful Posts
Naming A form using Begin Form
Submit Button outside HTML.BeginForm
Submit Button outside HTML.BeginForm (another link)
ASP.net ActionLink and POST Method
Error in case you have parameterized constructor in ViewModel and
did not declare parameterless constructor
Display Issue if you are using bootstrap In footer I had one input type = button and one action link with class= button. Both nested in one btn-group but there height were appearing different as visible in following snapshot:
Fix: Found that it is a known issue and there is one suggested solution but did not work out much for me (i.e. for Internet Explorer).
input type=submit and anchor button in btn-group appear as different sizes
Solution: add .btn { line-height:normal!important; } or if you want to do only for a specific button lets say the above input button then do this:
<input type="button" onclick="document.editProjDetailsForm.submit();"
class="btn btn-primary"
value="Save Changes"
style="line-height:normal!important;" />

Pass text box value to a dojo grid's query parameter

I am trying to pass the value in a text box as a query parameter in a dojo data grid and would like to get clarified on two questions listed below. The dojo grid initiates a call to the server with the query params to initiate a search and bring back results (that is diplayed on the data grid)
Is it possible to reload the gird based on the value in the text by invoking refresh (dijit.byId("mygrid").refresh
If yes, how can I pass the value of the text box as a query parameter to the data grid.
Listed below is my relevant code
function reload(){
dijit.byId("mygrid").refresh;
}
<div class="test">
<input id="searchParam" >
<button dojoType="dijit.form.Button" type="submit" onclick=reload()>
Search
</button>
</div>
<div dojoType="dojox.grid.DataGrid"
id="mygrid"
jsid="mygrid"
store="dojox.data.JsonRestStore"
target="<c:url value='members' />">
query="{
searchCriteria: ? TODO How to pass value of text box here?,
}"
rowsPerPage="1000"
autoWidth="true"
autoHeight="true"
selectionMode="single"
selectable="true"
errorMessage="Error loading data"
noDataMessage="<span class='dojoxGridNoData'>No members found.</span>">
</div>
You should be able do something like the following:
function reload() {
var val = dojo.byId('searchParam').attr('value');
dijit.byId("mygrid").setQuery({ propName: val });
}
You will need to properly build the query { propName: val }.

Handle button action in a list

I am trying to develop an iphone application using sencha framework .I need to show a list of items in a list.Each cell in the list holds a button also.If the user clicks on a button in a particular index, then a popover needs to be displayer near to the button .I am using the following code to do this
itemTpl : '<div class="div1"><label class = "tag-name-hdr"> {tagnamehdr} </label> <label class = "tag-name-value" style="width:55px;"> value </label> <input type="text" class ="tag-name-text" name="lname" /> <label class = "unit-name" > unit </label> <select class = "unit-name_dropdown" > <option>mg/dr</option> <option>gm/dr</option> <option>m/dr</option> </select> <input type="image" id="popupbtn" class="template_popup_button" src="Images/arrow_more_orange.png" > </div>',
listeners : {
//itemtap : function(list, index, item, e, popupbtn) {
itemtap : function(list, index, item, evt) {
if(evt.getTarget('.template_popup_button')) {
alert(item);
alert(index);
showOverlay(item, evt, index);
}
}
}
Now my issue is that the popover is showing for the selected cell.I need to show the popover near to the clicked button.Is there any way to get the clicked button object to show the overlay/popover near to that.Now I am passing clicked item cell object as parameter to "showOverlay",i need to pass clicked button object
Thanks in advance..
The evt variable holds information about the event. You could check if evt.target is a button (or the button you want to act upon).
Note that if all you want is a single button per cell, you could use the onItemDisclosure config option, that will add a button for you with a handler.