I've a MVC application, whose SharedLayout view(Master Page) gives user capability to search. They could search their order by Order No or By Bill no. So there are two option buttons the Shared View along with the textbox. Code is somewhat like this
#using (Html.BeginForm("Track", "Tracking", FormMethod.Post))
{
<div style="text-align: center">
<textarea cols="20" id="txtNo" name="txtOrderNo" rows="2" ></textarea>
</div>
<div style="text-align: center">
<input type="radio" name="optOrderNo" checked="checked" value="tracking" />Order No <input type="radio" name="optRefNo" value="tracking" />Ref No
</div>
<div style="text-align: center">
<input type="submit" value="Track" />
</div>
}
So it'll go to TrackingController and Track Method in it and return the view. It works fine for a single search as a View is associated with a controller's methods. It works fine but how could i conditionally return the other view based on the radio button selection.
What i come up with is this
[HttpPost]
public ActionResult Track(FormCollection form)
{
string refNo = null;
if (form["optRefNo"] == null)
{
string OrderNo = form["txtOrderNo"];
var manager = new TrackingManager();
var a = manager.ConsignmentTracking(OrderNo);
var model = new TrackingModel();
if (OrderNo != null)
model.SetModelForConsNo(a, consNo);
return View(model);
}
refNo = form["txtConsNo"];
return TrackByRef(refNo);
}
public ActionResult TrackByRef(string refNo)
{
//what ever i want to do with reference no
return View();
}
Kindly guide.
Thanks
View has an overload where the first parameter is a string. This is the name (or path) to the view you want to use, rather than the default (which is a view that matches the action's name).
public ActionResult TrackByRef(string refNo)
{
//what ever i want to do with reference no
return View("Track");
// or, if you want to supply a model to Track:
// return View("Track", myModel);
}
Related
I've been struggling with this for a while now. I'm constructing this view:
But when I hit the 'Update' button after do some changes the web refreshes to show the original values.
About the view: I get this view using an IEnumerable and looping thru each item in the model inside a form. Then, inside the form, there is a table that contains only 1 row. I do this in order to wrap all the items of the record in one form. This is part of code:
#foreach (var item in Model)
{
<form asp-action="Test" asp-route-id="#item.Id">
<table class="table">
<tbody>
<tr>
<td>
<input type="hidden" asp-for="#item.Id" />
<div class="form-group">
<div class="col-md-10">
<input asp-for="#item.MchName" readonly class="form-control" />
<span asp-validation-for="#item.MchName" class="text-danger"></span>
</div>
</div>
</td>
//more fields
<td>
<input type="submit" value="Update" class="btn btn-default" />
</td>
</tr>
</tbody>
</table>
</form>}
I declare an asp-action and a asp-route-id:
<form asp-action="Test" asp-route-id="#item.Id">
Question: Is this good enough? Is there something missing?
This is the Get Method:
public async Task<IActionResult> Test()
{
PopulateMachineTypeDropDownListStore();
return View(await _context.Machines.AsNoTracking().ToListAsync());
}
Question: I'm not passing any argument to the controller, yet the view will list the items following the given structure using an IEnumerable. Should I pass anything to the Get Method or is it fine as it is?
This is the Post Method:
#model IEnumerable<Application.Models.Machine>
[HttpPost, ActionName("Test")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> TestPost(int? id)
{
if (id == null)
{
return NotFound();
}
var machinetoUpdate = await _context.Machines
.SingleOrDefaultAsync(s => s.Id == id);
if (await TryUpdateModelAsync(
machinetoUpdate,
"",
s => s.MchName, s => s.StoreID, s => s.PUnit, s => s.Status))
{
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException)
{
ModelState.AddModelError("", "Unable to save changes. " +
"Try again, and if the problem persists, " +
"see your system administrator.");
}
return RedirectToAction("Test");
}
PopulateMachineTypeDropDownListStore();
return View(await _context.Machines.AsNoTracking().ToListAsync());
}
Question: I don't know if because the entity I retrieve the id from (and that I use to update the model thru TryUpdateModelAsync()) is also being used to compare to the model that thru the view this might not been working properly.
Thanks in advance for any help.
This question already has an answer here:
Submit same Partial View called multiple times data to controller?
(1 answer)
Closed 6 years ago.
Here is my scenario:
public class ComplexObject
{
public int SomeProperty {get;set;}
public List<SimpleObject> Object {get;set;}
}
public class SimpleObject
{
public string FirstName {get;set;}
public string LastName {get;set;}
}
I created a strongly typed partial view for SimpleObject
#model SimpleObject
<div>
<input type="button" value="Button" name="btn" />
<div>
<div>
#Html.TextBoxFor(Model => Model.FirstName, new { #class = "", #maxlength = "50" })
</div>
<div>
#Html.TextBoxFor(Model => Model.LastName, new { #class = "", #maxlength = "50" })
</div>
Now I want to Render this partial view inside another view (MainView). The idea is that a user can click SimpleObject partial view button and
generate the same partial view again on the MainView . SO here is how it looks :
MainView
SimpleView -> Add
SimpleView -> Add
I can create an ajax action and generate the simple view and append it to mainview but the problem is that simpleobject is NOT binding to the ComplexObject.
This is how I render partialview in MainView.
#Html.Partial("_PartialView", Model.SimpleObject, new ViewDataDictionary(ViewData)
{
TemplateInfo = new System.Web.Mvc.TemplateInfo
{
HtmlFieldPrefix = "Simple"
}
})
The MainView calls a controller action on submit click and the entire ComplexObject is submitted. Here my List of SimpleObject is always NULL.
public ActionResult CreateComplex(ComplexObject object)
{
// HERE LIST<SIMPLEOBJECT> is always NULL
}
Any ideas what am I doing wrong here ?
The first time you render the partial view you will have something like this:
<div>
<input type="text" name="FirstName" maxlength="50" />
</div>
<div>
<input type="text" name="LasttName" maxlength="50" />
</div>
When you add more than one partial view to the page, at the end only 2 text boxes will be posted to the server because they all have the same name.
To fix this issue, you have to change your partial view to make the input boxes like an array, you can add a property to your model and set it from the action
assuming you added a property called Index to your model, your code should look like this
#model SimpleObject
<div>
<input type="button" value="Button" name="btn" />
<div>
<div>
#Html.TextBox("FirstName["+Model.Index+"]", new { #class = "", #maxlength = "50" })
</div>
<div>
#Html.TextBox("LastName["+Model.Index+"]", new { #class = "", #maxlength = "50" })
</div>
With each button submit, you increment the Index and render the view.
Another solution, is to remove the partial view and add the input boxes using JavaScript, you can use Knockout
have a look at this article that explains how to do it: http://knockoutjs.com/examples/grid.html
Here are the changes that I did to code posted in original question to bind list of SimpleObjects to ComplexObject.
#Html.Partial("_PartialView")
The class looks like this :
public class ComplexObject
{
public int SomeProperty {get;set;}
public List<SimpleObject> Objects {get;set;}
}
and the partialview starts with BeginCollectionItem
#model AZSolutions.Framework.Model.SimpleObject
#using (Html.BeginCollectionItem("Objects")) {
...
}
I have project on ASP MVC 5. I have a model "Article". This model have HashSet and ICollection of Author. Author - second model:
public partial class Article
{
public Article()
{
Authors = new HashSet<Author>();
}
[DisplayName("Авторы")]
public virtual ICollection<Author> Authors { get; set; }
I need to add page of creating Article, on which you can increase the number of authors(using AJAX), and each author to register the fields. I decided to use partial view of Author's model, without "Create" button(Create button used only view of creating Article). I need in unlimited adding new partial views, and after fill them - get all data from them. How make it? I newbie in MVC, and can't imagine how it will works.
http://i.stack.imgur.com/0RHD0.png - an illustration of how it should look
Is there a need to use partials? wouldnt it be easier to write a small script that would instead clone the first author enclosing element and just change the names of the elements involved to create a new author?
<div id="enclosingDiv" data-count="x">
<div class="someClass" data-index='x1' >
Author1 name Aurthor1 Textboxname="CollectionList[Index].Property"...
</div>
Now when creating a new Authouther, you can just create:
<script>
function createNewAuthor()
{
//clone first author
var count = $('encolsingDiv').attr('data-count');
//var count = $('encolsingDiv').children().length;
var author = $('enclosingDiv').first().clone();
//change name and id,etc using data-count
author.find('*[name$='value'])attr('name','ListCollection[count + 1]");
author.find('*[name$='value'])attr('id',....);
author.attr('data-index',count +1)
$('enclosingDiv').append(author);
$('enclosingDiv').attr('data-count',count + 1 to it);//makes life easier
}
function deleteAuthor(authourIndex)
{
//assumes that an author can be removed
$('div[data-index="'+authorIndex+'"]").remove();
$('enclosingDiv').children.each(function()
{
//if delete functionality exists, change the names of the element indices using the count variable
change all indices of element properties concerned
$(this).find('*[name$='value']).attr('name','ListCollection['+count+'].sumproperty");
count++;
});
}
</script>
So you can use that for create and delete methods, you don't need partials for that.
The code might need some work as what I show is the concept
It is not that hard. Your partial views will be posted as a collection.
Suppose that your partial view has 2 values, FirstName and LastName. It should be something like this:
#{
Guid index = Guid.NewGuid();
}
<input type="hidden" name="People.index" value="#index" />
<input type="text" name="People[#index].FirstName" value="" />
<input type="text" name="People[#index].LastName" value="" />
The final output would be:
<input type="hidden" name="People.index" value="B756DAD8-5D5D-449E-A4B4-E61F75C1562C" />
<input type="text" name="People[B756DAD8-5D5D-449E-A4B4-E61F75C1562C].FirstName" value="" />
<input type="text" name="People[B756DAD8-5D5D-449E-A4B4-E61F75C1562C].LastName" value="" />
<input type="hidden" name="People.index" value="B78B7BBC-EB0E-41CB-BE18-C1E3F7526F32" />
<input type="text" name="People[B78B7BBC-EB0E-41CB-BE18-C1E3F7526F32].FirstName" value="" />
<input type="text" name="People[B78B7BBC-EB0E-41CB-BE18-C1E3F7526F32].LastName" value="" />
Your model must have a collection People object.
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Article
{
//other properties...
public ICollection<Person> People { get; set; }
}
Your Controller:
public ActionResult YourAction (Article model)
{
//...
}
Untested code, but it should work fine.
I have a form in ASP.Net and razor.
I need to have two ways of submitting said form: one that goes through the Edit action, and another that goes through the Validate action.
How should I go about doing this?
I don't mind using JavaScript for this.
EDIT:
Using the custom attribute I get this error.
The current request for action 'Resultados' on controller type 'InspecoesController' is ambiguous between the following action methods:
System.Web.Mvc.ActionResult Validar(System.Collections.Generic.ICollection1[Waveform.IEP.Intus.Server.Web.ViewModels.ResultadoViewModel]) on type Waveform.IEP.Intus.Server.Web.Controllers.InspecoesController
System.Web.Mvc.ActionResult Resultados(System.Collections.Generic.ICollection1[Waveform.IEP.Intus.Server.Web.ViewModels.ResultadoViewModel]) on type Waveform.IEP.Intus.Server.Web.Controllers.InspecoesController
That's what we have in our applications:
Attribute
public class HttpParamActionAttribute : ActionNameSelectorAttribute
{
public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
{
if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase))
return true;
var request = controllerContext.RequestContext.HttpContext.Request;
return request[methodInfo.Name] != null;
}
}
Actions decorated with it:
[HttpParamAction]
public ActionResult Save(MyModel model)
{
// ...
}
[HttpParamAction]
public ActionResult Publish(MyModel model)
{
// ...
}
HTML/Razor
#using (#Html.BeginForm())
{
<!-- form content here -->
<input type="submit" name="Save" value="Save" />
<input type="submit" name="Publish" value="Publish" />
}
name attribute of submit button should match action/method name
This way you do not have to hard-code urls in javascript
You can do it with jquery, just put two methods to submit for to diffrent urls, for example with this form:
<form id="myForm">
<%-- form data inputs here ---%>
<button id="edit">Edit</button>
<button id="validate">Validate</button>
</form>
you can use this script (make sure it is located in the View, in order to use the Url.Action attribute):
<script type="text/javascript">
$("#edit").click(function() {
var form = $("form#myForm");
form.attr("action", "#Url.Action("Edit","MyController")");
form.submit();
});
$("#validate").click(function() {
var form = $("form#myForm");
form.attr("action", "#Url.Action("Validate","MyController")");
form.submit();
});
</script>
If you are working in asp.net with razor, and you want to control multiple submit button event.then this answer will guide you. Lets for example we have two button, one button will redirect us to "PageA.cshtml" and other will redirect us to "PageB.cshtml".
#{
if (IsPost)
{
if(Request["btn"].Equals("button_A"))
{
Response.Redirect("PageA.cshtml");
}
if(Request["btn"].Equals("button_B"))
{
Response.Redirect("PageB.cshtml");
}
}
}
<form method="post">
<input type="submit" value="button_A" name="btn"/>;
<input type="submit" value="button_B" name="btn"/>;
</form>
Here is a good eplanation:
ASP.NET MVC – Multiple buttons in the same form
In 2 words:
you may analize value of submitted button in yout action
or
make separate actions with your version of ActionMethodSelectorAttribute (which I personaly prefer and suggest).
With HTML5 you can use button[formaction]:
<form action="Edit">
<button type="submit">Submit</button> <!-- Will post to default action "Edit" -->
<button type="submit" formaction="Validate">Validate</button> <!-- Will override default action and post to "Validate -->
</form>
<input type="submit" value="Create" name="button"/>
<input type="submit" value="Reset" name="button" />
write the following code in Controler.
[HttpPost]
public ActionResult Login(string button)
{
switch (button)
{
case "Create":
return RedirectToAction("Deshboard", "Home");
break;
case "Reset":
return RedirectToAction("Login", "Home");
break;
}
return View();
}
We can have this in 2 ways,
Either have 2 form submissions within the same View and having 2 Action methods at the controller but you will need to have the required fields to be submitted with the form to be placed within
ex is given here with code Multiple forms in view asp.net mvc with multiple submit buttons
Or
Have 2 or multiple submit buttons say btnSubmit1 and btnSubmit2 and check on the Action method which button was clicked using the code
if (Request.Form["btnSubmit1"] != null)
{
//
}
if (Request.Form["btnSubmit2"] != null)
{
//
}
have been struggling with this. Tried everything I can think of. Im using javascript to pass data to db, works fine with ints on another page but now with strings it wont work :s
#using (Html.BeginForm(null, null, FormMethod.Post, new{#id="manageForm"}))
{
#Html.AntiForgeryToken()
<span class="actions">
#T(User.Id.ToString()) #T(" ") #T(ViewData["Tag"].ToString())
<input type="hidden" name="tag" value="fr" />
<input type="hidden" name="id" value="3" />
#T("Follow")
</span>
}
Javascript
<script type="text/javascript">
function followTag() {
$('#manageForm').attr('action', '#(Url.Action("FollowTag"))').submit();
return false;
}
</script>
Controller
[RequireAuthorization]
[HttpPost]
public ActionResult FollowTag(int id, string tag)
{
_service.FollowTag(id, tag);
return RedirectToAction("TagPage","Detail", new
{
});
}
Data Access
public void FollowTag(int id, string tag)
{
DbCommand comm = GetCommand("SPTagFollow");
//user id
comm.AddParameter<int>(this.Factory, "id", id);
//id to follow
comm.AddParameter<string>(this.Factory, "tag", tag);
comm.SafeExecuteNonQuery();
}
route is setup fine and sql(stored procedure) executes perfect. Hopefully one of you can see something obvious
cheers
I think is a problem of mistyping, check your last <a> tag, you typed following.() in the onclick event, see that your javascript function is called followTag.
If that doesn't fix it, then get rid of that foolowTag function, you can specify the action and the controller in the form itself, like this:
#using (Html.BeginForm("FollowTag", "YourControllerName", FormMethod.Post)) {
...
//Delete this line
//#T("Follow")
//This submit button will do the job
<input type='submit' value='#T("Follow")' />
}
That should do it. If you are using the anchor tag just for styling that's ok, otherwise you should use the other way, I think is clearer and besides it takes advantage of razor's great features.