Wrong Function Being Called From MVC View - asp.net-mvc

I have an MVC view, which is launched by a function in the controller. That view has a button that I want to use to submit data to a different function in that same controller, but it always go back to the function that launched it instead.
The controller is called, the ViewForPrepare view is launched from PrepareList, I hit the button on ViewForPrepare, and it submits to PrepareList again instead of RunList.
In the controller I have:
public ActionResult PrepareList(int Key)
{
return "ViewForPrepare";
}
public ActionResult RunList(int Key)
{
return "OtherView";
}
Then in the View:
<input type="button" value="Submit Report" id="submit">
<script type="text/javascript">
$(document).ready(function () {
$('#submit').click(function () { window.location ='#Url.RouteUrl("RunList", new { Key = #Model.caseNumber })' });
});
</script>
So I press the button to go to RunList, but it keeps going to PrepareList. I've checked the routing and it looks OK. What do I need to do to get the button to submit to RunList?

You're code right now basically says "When I click the submit button. Change the window's location to something else." If that is what you want, try using
#Url.Action("RunList", new { Key = Model.caseNumber })
instead of
#Url.RouteUrl("RunList", new { Key = #Model.caseNumber })
and try using a <button> element instead of an <input> element.
If what you want is to post the data from the form, you should wrap your button in a form tag (make sure to replace "ControllerName" below with your actual controller.)
#Html.BeginForm("RunList","ControllerName", new { Key = Model.caseNumber })
{
<input type="submit" value="Submit Report" id="submit">
}
and get rid of the javascript altogether as it isn't necessary in this case. Also you will have to mark your RunList action as HttpPost for this to work.
[HttpPost]
public ActionResult RunList(int Key)
{
return "OtherView";
}

Why dont you just use a RouteLink instead of the Input?
#Html.RouteLink("Submit Report", "RunList", new { Key = Model.caseNumber }, new {#class="btn" })
not sure if you're using bootstrap or jquery ui but there are css classes to make links look like buttons.
ActionLink works the same way.
#Html.ActionLink("Submit Report", "RunList", "ViewForPrepare ", new { Key = Model.caseNumber }, new { #class = "btn" })

Using VS2015 Pro I created a project using the MVC template.
HomeController.cs added:
public ActionResult PrepareList(int Key)
{
return View();
}
public ActionResult RunList(int Key)
{
return View(); ;
}
Index.cshtml added:
#Html.ActionLink("Submit Report", "RunList", new { Key = 4 }, new { #class = "btn" })
Put a break point in "RunList" and it worked!
Using
<input type="button" value="Submit Report" id="submit">
#section script{
<script type="text/javascript">
$(document).ready(function () {
$('#submit').click(function () { window.location ='#Url.RouteUrl("RunList", new { Key = 4 })' });
});
</script>
}
I got the meessage
A route named 'RunList' could not be found in the route collection.

when you need to send data, you must add the attribute HttpPost to this action:
[HttpPost]
public ActionResult RunList(int Key)
{
return "OtherView";
}

Related

MVC 5 Layout page

I have an MVC site, and I use the same "_layout page" for all the view.
In _layout page, I have a select control.
What I want is to read the selected value of the control from the other pages.
Can you help me understand how to do?
Edit:
_Layout.cshtml
<div class="col-sm-4 col-xs-6">
<label class="col-sm-2 control-label" for="slt_Aziende">Azienda:</label>
<select id="mySharedSelectControl">
<option value="1">value 1</option>
<option value="2">value 2</option>
</select>
</div>
Index.cshtlm (using _Layout.cshtml)
#model IEnumerable<MySite.Models.MyModel>
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
MyModelController
public class MyModelController : Controller
{
public ActionResult Index()
{
//get value from mySharedSelectControl from Layout page
var selectedValueFromLayoutPage;
//do something
return View();
}
}
Based on what #Mairaj said is right i.e you can't directly read values of controls in your controller.
What you can do is create a JavaScript function like this:
$(document).ready(function () {
$("#mySharedSelectControl").change(function () {
var dropdownValue = $(this).val();
$.ajax({
url: "#Url.Action("PutValueinSession", "MyModel")", //Action method on which you want to send this dropdown value
data: { id: dropdownValue },
success: function (e) {
window.location = window.location;
}
});
});
});
You can create a method in which you can put this value in session and used across your whole page like below:
public JsonResult PutValueinSession(int id)
{
Session["DropdownControlValue"] = id;
return Json(new { Result = "" }, JsonRequestBehavior.AllowGet);
}
Now you can access this value on any page:
public ActionResult Index()
{
//get value from mySharedSelectControl from Layout page
var selectedValueFromLayoutPage=Session["DropdownControlValue"];
//do something
return View();
}
You can't directly read value of controls in Controller, you need to send the value of dropdown to the controller and than process what you want.
Or you can directly read value of dropdown from JavaScript in other views and do your processing.

Controller code gets called twice

I have an MVC view which will have menu and detail sections. As items are clicked on the menu, I would like the detail section to get updated. The menu and detail would be PartialViews.
My main view is layed out like this (so far):
#model WorkflowData.ProjectWorkflow
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="form-horizontal">
<h4>Project Workflow</h4>
<hr />
<div>
#{Html.RenderPartial(
"_WorkflowSteps",
Model.ProjectWorkflowSteps.ToList());
}
</div>
<div id="StepDetail"></div>
</div>
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section scripts{
#Scripts.Render("~/Scripts/jquery.unobtrusive-ajax.min.js")
<script>
$(function () {
$('.workflow-step').on('click', function (e) {
$.get($(this).prop('href'), function (response) {
$('#StepDetail').html(response)
});
});
});
</script>
}
The '_WorkflowSteps' partial view renders links using this:
#Html.ActionLink(
item.StepName,
"Step",
new { id = item.ProjectworkflowPages.FirstOrDefault().ProjectWorkflowPageId },
new { #class = "workflow-step" });
My controller action for Step is:
public ActionResult Step(int id)
{
if (id == null)
return RedirectToAction("Index");
using (var _db = new MarkTestDbEntities())
{
var stepPage = (from s in _db.ProjectworkflowPages
where s.ProjectWorkflowPageId == id
select s).FirstOrDefault();
var projectModel = new Project
{
ProjectWorkflowId = stepPage.ProjectWorkflowStep.ProjectWorkflowId
};
return PartialView(string.Format("../{0}/{1}",stepPage.Controller, stepPage.CreateAction)
, projectModel);
}
return View();
}
What is happening now is I see the div get populated with the partial view, then the page refreshes with just the partial view from Step. Debugging I see that the Step action is actually called twice, but when I look at the rendered source, I don't see why. Any thoughts?
Your elements with class="workflow-step" are links which make a GET call to your Step() method. You are handling the .click() event of those elements and making a ajax call, but your not cancelling the default redirect so its doing both, the $.get() followed by the redirect. You need to cancel the default action by including return false; in the script
$('.workflow-step').on('click', function (e) {
$.get($(this).prop('href'), function (response) {
$('#StepDetail').html(response)
});
return false; // add this
});

Can I forward to a HttpPost method without a BeginForm?

I'm new to MVC and still haven't found a way to do this.
In the view I have this Clone button:
<a href="#Url.Action("Clone", "Game", new { pModelId = Model.Id })" class="btn btn-default btn-xs">
<i class="fa fa-plus"></i>Clone Game</a>
And in my Controller this:
[HttpPost]
public ActionResult Clone(int pGameId)
{
int lClonedGameId = mGameRepository.CloneGame(pGameId);
return RedirectToAction("Show", new { id = lClonedGameId, message = "Your game was cloned succesfully" });
}
I'm getting a 404 due to the [HttpPost] but I don't want to make it [HttpGet] since it writes to the DB. Is there a way to make that button go to the HttpPost method without a BeginForm or something like that?
If this is only a matter of having link instead of button to submit the form I suggest you adding a form and using javascript to submit a form when the link is pressed (below code assumes you are using jQuery):
#using (Html.BeginForm("Clone", "Game", FormMethod.Post, new {id = "form1"}))
{
//Your other elements go here
CloneGame
}
And hook the script:
$(function() {
$("a.cloneGameSubmit").click(function () {
$("#form1").submit();
});
});

Can you just update a partial view instead of full page post?

Is there a way to submit a partial view form in asp.net mvc without reloading the parent page, but reloading the partial view only to its new state? Similar to how knockout.js updates using data-bind.
My data table renders with a variable number of columns/names so I don't think knockout.js is an option for this one, so I am trying to use a partial view instead.
Not without jQuery.
What you would have to do is put your Partial in a div, something like:
<div id="partial">
#Html.Partial("YourPartial")
</div>
Then, to update (for example clicking a button with the id button), you could do:
$("#button").click(function () {
$.ajax({
url: "YourController/GetData",
type: "get",
data: $("form").serialize(), //if you need to post Model data, use this
success: function (result) {
$("#partial").html(result);
}
});
})
Then your action would look something like:
public ActionResult GetData(YourModel model) //that's if you need the model
{
//do whatever
return View(model);
}
Actually, if your Partial has a child action method, you can post (or even use an anchor link) directly to the child action and get an Ajax-like affect. We do this in several Views.
The syntax is
#Html.Action("MyPartial")
The Child Action is
public ActionResult MyPartial()
{
return PartialView(Model);
}
If your form posts to the child action
#using (Html.BeginForm("MyPartial"))
{
    ...
}
The Partial View will be updated with the partial view returned from the child action.
Jquery is still a legitimate way to update a partial. But technically, the answer to your question is YES.
As normal what I find when looking for things like this is people give too limited information so I will attempt to help here. The key is to set up a div with an ID you can append the return html to. Also when hitting your controller make sure it returns the partial. There are some potential problems with this method but on a good day it should work.
<div id="CategoryList" class="widget">
#{
Html.RenderPartial("WidgetCategories.cshtml");
}
</div>
function DeleteCategory(CategoryID) {
$.get('/Dashboard/DeleteWidgetCategory?CategoryID=' + CategoryID,
function (data) {
if (data == "No") {
alert('The Category has report widgets assigned to it and cannot be deleted.');
}
else {
$('#CategoryList').html(data);
}
}
);
}
[HttpGet("DeleteWidgetCategory")]
[HttpPost("DeleteWidgetCategory")]
public IActionResult DeleteWidgetCategory(string CategoryID)
{
string Deleted = CategoryModel.DeleteCategory(CategoryID);
if (Deleted == "Yes")
{
return PartialView("WidgetCategories");
}
else
{
return this.Json("No");
}
}
I would use the Ajax Form helper for such scenarios using a partial view and #html.RenderPartial("partialName")
partial helpers
In your Main View
<div id=SearchResult>
#Html.Partial("_NameOfPartialView", Model)
</div>
<input type="button" id="btnSubmit" value="Submit">
In your Javascript file
$('#btnSubmit').click(function () {
GetData(Id);
});
function GetData(Id){
$.ajax({
url: "/Home/GetEmployee/",
type: "get",
data: { Id:Id },
success: function (result) {
$('#SearchResult').html(result);
}
});
}
In your Home Controller
public ActionResult GetEmployee(int Id)
{
var employee= context.Employee.Where(x=> x.EmployeeId == Id)
return this.PartialView("_NameOfPartialView", employee);
}

how to get partialview data in controller

I am using three partialview on a single view, I have a submit button on clicking of which I want to send information to database, I have to retrieve data from all the partialview.
Can You please provide me correct information to do it.
Darin I m using L2S so when I drag my stored procedure, I get code some thing like this in
[global::System.Data.Linq.Mapping.FunctionAttribute(Name="SP_Name")]
public int SP_Name(
[global::System.Data.Linq.Mapping.ParameterAttribute(Name="EmployeeID", DbType="Int")] System.Nullable<int> EmployeeID
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), EmployeeID);
encounterID = ((System.Nullable<int>)(result.GetParameterValue(293)));
return ((int)(result.ReturnValue));
}
}
Updated
<script language="javascript" type="text/javascript">
$(function () {
$('#Form1').submit(function () {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (data) {
var message = data.Result;
$('#Result').html(message);
}
});
return false;
});
});
</script>
In my Controller I am using
public ActionResult Index(FormCollection frm)
{
My Code ---------------------
return Json(new { Result = "Success" });
}
When I return this I m getting a file in post back and it ask me to save it.
I have checked using flidder, in URL it shows me that the path as / only
where as If I fill any particular partialview It shows something like /Controller Name/Partialview
Can You help me with this problem
Well, sending data to a controller action is usually done by performing an HTTP request to this controller action. There are different ways of performing an HTTP request:
Use a <form> tag pointing to this action
Use AJAX
So if you go with the first approach you could have a single <form> wrapping all the partials which would have multiple submit buttons (with different names). Then when you click on one submit buttons all the input fields will be sent to the controller action and then inside the controller action you could process the data based on which submit button was clicked.
If you use the second option, well, then simply harvest the values you need to be sent uipon button click and send them along the AJAX request.
UPDATE:
As requested in the comments section here's how the first technique could be put into action. It uses two partials instead of three but it could be easily extrapolated.
As always you start by defining a view model which will represent the data you would like to work with on this particular view:
public class MyViewModel
{
public Partial1ViewModel Model1 { get; set; }
public Partial2ViewModel Model2 { get; set; }
}
public class Partial1ViewModel
{
public string Foo { get; set; }
}
public class Partial2ViewModel
{
public string Bar { get; set; }
}
Then a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
Model1 = new Partial1ViewModel { Foo = "foo" },
Model2 = new Partial2ViewModel { Bar = "bar" },
};
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
// Here you have access to model.Model1.Foo and model.Model2.Bar =>
var button = "";
if (!string.IsNullOrEmpty(Request["submit1"]))
{
// submit1 button was used
button = "submit1";
}
else if (!string.IsNullOrEmpty(Request["submit2"]))
{
// submit2 button was used
button = "submit2";
}
var result = string.Format("thanks for submitting using {0}", button);
return Content(result, "text/plain");
}
}
and then a main view (~/Views/Home/Index.cshtml):
#model MyViewModel
#using (Html.BeginForm())
{
#Html.EditorFor(x => x.Model1)
#Html.EditorFor(x => x.Model2)
}
and the two corresponding editor templates (or partials if you will):
~/Views/Home/EditorTemplates/Partial1ViewModel.cshtml:
#model Partial1ViewModel
<h2>Partial 1</h2>
<div>
#Html.LabelFor(x => x.Foo)
#Html.EditorFor(x => x.Foo)
<input type="submit" value="Submit me!" name="submit1" />
</div>
~/Views/Home/EditorTemplates/Partial2ViewModel.cshtml:
#model Partial2ViewModel
<h2>Partial 2</h2>
<div>
#Html.LabelFor(x => x.Bar)
#Html.EditorFor(x => x.Bar)
<input type="submit" value="Submit me!" name="submit2" />
</div>

Resources