Last input values passed to action in MVC - c#

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.

Related

Passing same parameter to an action on clicking two different buttons

I have a View which displays a list of file names. Also i have two buttons called View and Release. When I select a file name from the list and click on view, it navigates to the appropriate action method along with the file name selected as a parameter and performs the functionality as required.
But when i click on Release after selecting a file name, it does navigates to the appropriate action method, but does not passes the file name as a parameter to the action method. It shows as null.
Please note that View and Release directs to a single controller having different action methods.
How can i get to pass the filename as a parameter when i click on release?
Please see the code below:
public class HoldFilesController : Controller
{
// GET: HoldFiles
string holdpath = ConfigurationManager.AppSettings["HoldPath"].ToString();
public ActionResult Index()
{
DirectoryInfo dirInfo = new DirectoryInfo(holdpath);
List<FileInfo> files = dirInfo.GetFiles().ToList();
return View("Index",files);
}
}
[HttpPost]
public ActionResult ViewFile(string[] Name)
{
byte[] ImageData = null;
for (int i = 0; i < Name.Length; i++)
{
string filepath = holdpath + #"\" + Name[i];
FileStream fs = new FileStream(filepath, FileMode.Open,
FileAccess.ReadWrite);
ImageData = new byte[fs.Length];
fs.Read(ImageData, 0, System.Convert.ToInt32(fs.Length));
fs.Close();
}
return File(ImageData,"application/pdf");
}
[HttpPost]
public ActionResult ReleaseFile(string[] Name)
{
for(int i=0; i<Name.Length;i++)
{
string sourcefilepath= holdpath + #"\" + Name[i];
string Destinationfilepath =
ConfigurationManager.AppSettings["ReleaseFolderPath"].ToString();
string ReleaseFilePath = Destinationfilepath + #"\" + Name[i];
if (Directory.Exists(Destinationfilepath))
{
System.IO.File.Move(sourcefilepath, ReleaseFilePath);
}
}
return RedirectToAction("Index");
}
Here's the code for my view:
#model IEnumerable<FileInfo>
#{
ViewBag.Title = "files";
}
<h2>Held files</h2>
#using (Html.BeginForm())
{
<div style="border:solid;width:100%;overflow-x:auto;">
<table align="center" style="width:100%">
<thead>
<tr>
<th>File Name</th>
<th>Action</th>
</tr>
</thead>
<tbody>
#foreach (FileInfo file in Model)
{
<tr>
<td>
<input type="checkbox" name="Name" value="#file.Name" />
#file.Name
</td>
</tr>
}
</tbody>
</table>
</div>
<input type="submit" id="Held" name="Held file" value="View" />
<input type="submit" id="Release" name="release" value="Release" />
}
Just to avoid confusion, the View button redirects to the ViewFile method
and the Release button redirects to Releasefile method.
You have multiple options to do this.
You can hijack the submit button click and update the form action attribute value based on what button is clicked and do the form submit using javascript.
You can keep the url to the 2 action methods in html5 data attributes on the button.
<input type="submit" data-myaction="#Url.Action("View")" value="View"/>
<input type="submit" data-myaction="#Url.Action("Release")" value="Release"/>
Using the Url.Action method to generate the correct relative path to the action method is a safe practice. Let the method worry about generating the correct path for you.
And the javascript
$(function () {
$("input[data-myaction]").click(function(e) {
e.preventDefault(); // stop the normal form submit
// read the data attribute and update the forms action and do a submit
$(this).closest("form").attr('action', $(this).data('myaction')).submit();
});
});
Another option is using html5 formaction which does not need any javascript hijacking. When you specify a formaction attribute value, it will override the parent form's action attribute. this is very useful when you have more than one submit button with 2 different action methods to submit to (your use case)
<input type="submit" formaction="#Url.Action("View")" value="View"/>
<input type="submit" formaction="#Url.Action("Release")" value="Release"/>
1-HTML5 formaction and formmethod attributes
<input type="submit" name="view" value="view" formaction="ViewFile" formmethod="post" />
<input type="submit" name="Release" value="Release" formaction="ReleaseFile" formmethod="post" />
2-jQuery / JavaScript code
$(document).ready(function () {
$("#Held").click(function () {
$("form").attr("action", "/HoldFiles/ViewFile");
});
$("#Release").click(function () {
$("form").attr("action", "/HoldFiles/ReleaseFile");
});
});

Filter records in database according to the selected checkboxes using MVC

I have a Ajax.BeginForm in my razor view. I want to have 3 check boxes.
Begineer
Intemidiate
advance
checkoxes can select for any combination. When I clicked submit button bellow method in my controller will triggered.
public PartialViewResult SearchCourseCriteria(){
var courses = from s in db.CourseCategories
select s;
return PartialView("_Courses", courses);
}
This is my view
#using (Ajax.BeginForm("SearchCourseCriteria", new AjaxOptions
{
UpdateTargetId = "CourseList",
InsertionMode = InsertionMode.Replace,
HttpMethod = "GET"
}))
{
td>
#Html.CheckBoxFor()
</td>
<td>
<input type="submit" value="Search" class="btn " />
</td>
}
In my model there is field called CourseLevel. I want to know How to filter courses according to the selected checkboxes.
EX : If I select begineer and Intermidiate checkboex. I want to get all courseCategories from that levels. I dont know how to get that result. Help please.
In you view, generate 3 checkboxes for each value
<label>
<input type="checkbox" name="courselevel" value="Begineer" /> // Beginner?
<span>Begineer</span>
<label>
<label>
<input type="checkbox" name="courselevel" value="Intemidiate" /> // Intermediate?
<span>Intemidiate</span>
<label>
... // ditto for advance
Then add a parameter to the method
public PartialViewResult SearchCourseCriteria(string[] CourseLevel)
The value of CourseLevel will be an array of the selected checkboxes, for example [ "Begineer", "advance" ] if you checked the first and third checkboxes
You can then modify you query to
var courses = from s in db.CourseCategories
where CourseLevel.Contains(s.CourseLevel)
select s;
or
var courses= db.CourseCategories.Where(c => CourseLevel.Contains(c.CourseLevel));
Side note: I would recommend you use an enum to define the values for CourseLevel

MVC Delete not hitting HttpPost Method

I'm using MVC3. I learned that its a bad practice to delete an item using HttpGet Method as any one can browse to the url and deletes an item. So I want to perform delete operation on HttpPost Method.
The problem is that when I click delete button, it gets hit on HttpGet method only but not on HttpPost method.
I've used webgrid and its the index.cshtml file
<div id="DataTable">
#grid.GetHtml(htmlAttributes: new {id="gvMovies" },
columns:grid.Columns(
grid.Column("Title","Movie Title",canSort:true),
grid.Column("Director","Film Maker",canSort:false),
grid.Column(header:"Action",
format:#<text>
Edit
#using (Html.BeginForm("Delete", "Movies", new { id = #item.id }, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.ActionLink("Delete", "Delete", new { id = #item.id }, new { onclick = "return confirm('Are you sure you wish to delete this article?');" })
}
</text>)))
</div>
The controller page is as follows
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Delete(int id)
{
return RedirectToAction("Index");
}
Conceptually it's not correct to use the POST verb for delete. POST - is intended for posting information. The correct way would be to to just remove the attribute from the Delete method, and let it go with the GET verb.
Now if you really really really need to use the POST, your first mistake is that you create a link, instead of a submit button that will submit the form. Replace
#Html.ActionLink("Delete", "De...
with:
<input type="submit" value="Delete">
you must add submit button instead of link so you must change
#Html.ActionLink("Delete" to <input type=submit value="del" >
if you want send id in the post you can add hidden input in the form so you can add some thing like this before your submit button in the form
<input type="hidden" value=#item.Id name="itemid" >
so i think this code will work
#using (Html.BeginForm("Delete", "Movies", new { id = #item.id }, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="hidden" value=#item.Id name="itemid" >
<input type=submit value="del" >
}

Event Asp Mvc Redirect

I am beginner in asp.net mvc. I have in the view Home.cshtml
<button name ="del" style="width:150px; height:30px;text-decoration:none;color:white;text-align:center;background-color:darkcyan;padding:5px;border-style:outset;border-width:2px;border-color:darkcyan" onclick="#Url.Action("Delete", "Super",1)">Supprimer</button>
<button name ="edit"style="width:150px; height:30px;text-decoration:none;color:white;text-align:center;background-color:darkcyan;padding:5px;border-style:outset;border-width:2px;border-color:darkcyan" onclick="#Url.Action("Edit", "Super","val")">Editer</button>
When i click into the two buttons nothing is gone and the redirection didn't work.
why?
How can i change it to be correct?
You don't want to be creating links like this in MVC. Try using ActionLink:
#Html.ActionLink("Delete", "Edit", "Super");
#Html.ActionLink("Edit", "Edit", "Super");
http://msdn.microsoft.com/en-us/library/system.web.mvc.html.linkextensions.actionlink(v=vs.108).aspx
For a button:
<input type="button" value="Supprimer" onclick="window.location.href='#Url.Action("Delete", "Super")';" />
To specify parameters:
<input type="button" value="Supprimer" onclick="window.location.href='#Url.Action("Delete", "Super", new { Id = 1 })';" />
You can use JQuery in this case to improve the current quality of code as below
<input id="supprimer" type="button" value="Supprimer" />
$('#supprimer').click(function(){
window.location.href = '#Url.Action("Delete", "Super")';
});
And in the best version, try to module that code with the AMD pattern
The problem is that the onclick is a javascript event, and thus requires javascript code. You are just setting it as a URL, which will do nothing.
One option (and I am not saying it is the best) would be to change it to:
onclick="window.location = '#Url.Action("Delete", "Super", new { id = 1 })';"
I found this solution :
<a type="button" style="width:150px; height:30px;text-decoration:none;color:white;text-align:center;background-color:darkcyan;padding:5px;border-style:outset;border-width:2px;border-color:darkcyan;margin-left:25px" href="#Url.Action("Delete", "Super",new { Id = 1 })">Supprimer</a>
<a type="button" style="width:150px; height:30px;text-decoration:none;color:white;text-align:center;background-color:darkcyan;padding:5px;border-style:outset;border-width:2px;border-color:darkcyan" href="#Url.Action("Edit", "Super",new { Id = 1 })">Editer</a>
In the controller:
public ActionResult Edit(int id)
{
int id2 = id;
return RedirectToAction("Edit", "Admin", new {id = id2});
}

Using jQuery to post back to Controller

In my web page, I have a series of tables that basically just contain rows of information. Each of these is given an id in a for loop and I'm trying to reference them from outside that. I added classes to both the table and a 'Save Changes' button.
Essentially, my goal is for the user to be able to drag and drop rows around, thereby changing the order. Then they can click the 'Save Changes' button and this will post back to the server with the relevant information.
I am having trouble matching up the button to the relevant table and thereby submitting the id's of each row back to the server in an array. I have written the code to be able to be able to get the ids from each of the tables and their current order, but I don't know how to assign this to an array from within the button click jQuery.
Here is the View:
#foreach (var collection in Model.Collections)
{
<h2>#collection.Season</h2>
#Html.ActionLink("Delete Collection", "DeleteCollection", new { controller = "Edit", brand = collection.Brand.Name, season = collection.Season })
#Html.ActionLink("Edit Collection", "EditCollection", new { controller = "Edit", brand = collection.Brand.Name, season = collection.Season })
#Html.ActionLink("Add Image", "CreateImages", new { controller = "Edit", season = collection.Season })
<p>
To change the ordering of images, drag and drop to your desired position and then click the Save Changes button on the appropriate collection.
</p>
<table class="table-collection" id="table-#collection.Id">
<tr class="nodrop nodrag">
<th>
Id
</th>
<th>
Description
</th>
<th>
Image
</th>
<th>
Options
</th>
</tr>
#foreach (var image in collection.Images)
{
<tr id="#collection.Id-#image.Id">
<td class="dragHandle showDragHandle">
#image.Id
</td>
<td>
#image.Description
</td>
<td>
<img src="#Url.Content("~/" + image.Location)" alt="#image.Description" />
</td>
<td>
<ul>
<li>
#Html.ActionLink("Edit", "EditImage", new { controller = "Edit", brand = image.Collection.Brand.Name,
season = image.Collection.Season, imageId = #image.Id } )
</li>
<li>
#Html.ActionLink("Delete", "DeleteImage", new
{
controller = "Edit",
brand = image.Collection.Brand.Name,
season = image.Collection.Season,
imageId = #image.Id
})
</li>
</ul>
</td>
</tr>
}
</table>
<p>
<input type="submit" value="Save Changes" class="save-order" id="saveTable-#collection.Id"/>
</p>
}
Here is the jQuery so far:
$(document).ready(function () {
$(".table-collection").tableDnD();
$(".save-order").click(function (e) {
e.preventDefault();
$.ajax({ url: window.location.href,
type: 'POST',
data: { ids: $("--ASSIGN ARRAY HERE--"
});
The jQuery to iterate through each row is essentially this:
function(table, row) {
var rows = table.tBodies[0].rows;
var debugStr = "Row dropped was "+row.id+". New order: ";
for (var i=0; i<rows.length; i++) {
debugStr += rows[i].id+" ";
}
I see you are using input type submit which is exclusively used to postback forms. What you need to do is wrap every table up in a form with something like this:
#using(Html.BeginForm("Action", "Controller", new{ collectionId = collection.Id }))
{
<input type="submit" value="Save Changes" class="save-order" />
}
Note that this will cause a 'post-back' of the form to Action, Controller. Specify the collection id inside the route values to identify the specific collection.
Do note, you need to add input type hidden with the id's value otherwise the ids' won't get serialised - all you have to specify is the name attribute
<td class="dragHandle showDragHandle">
<input type="hidden" name="ids" value="#(image.Id)" />
#image.Id
</td>
Then you can intercept the call then do it via ajax with:
$(".save-order").click(function(e) {
e.preventDefault();
var form = $(this).closest('form');
if(form.validate()) {
$.post(form.attr('action'), form.serialize(), function() {
alert('The new image order has been saved.');
});
}
return false;
});
The accepting controller action method will probably have this signature
public ActionResult Action(int collectionId, int[] ids)
{
//Do stuff here
return Request.IsAjaxRequest() ? null : View();
}
Now it should support graceful degradation if javascript is disabled (does a normal form submit, otherwise does it via ajax)
Hope this helps :)
You can grab all of the IDs with something like this:
var IDs = [];
$("#mydiv").find("span").each(function(){ IDs.push(this.id); });
In your scenerio, do something like this:
$(document).ready(function ()
{
$(".table-collection").tableDnD();
$(".save-order").click(function (e)
{
var IDs = [];
$("#yourtable").find("draggable-tr-class").each(function(){ IDs.push(this.id); });
e.preventDefault();
$.ajax(
{
url: window.location.href,
type: 'POST',
data: { ids: IDs }
);
}
})
i have been create demo in jsfiddle using json
http://jsfiddle.net/viyancs/4ffb3/11/
if you use like that demo in your server must be get parameter `JSONFile' after that parse this json for what do you want.actually the demo not same with your case but i think you can use this by your logic.

Categories