I have a problem to send my Model into my controller.
I use a button with the ajax to change the page but i need the model who is the first page to the second page.
I would like send my model in my controller but it's not work.
When i come in the page CreateAll, the renderpartial follow works to display Step1 but if i click on the step2 i would like the mainModel to be send to my controller use a partial view with submodel.
My model is:
public class CreateAllStep
{
public CreateStep1 Step1 { get; set; }
public CreateStep2 Step2 { get; set; }
public CreateAllStep(CreateStep1 step1, CreateStep2 step2)
{
this.Step1 = step1;
this.Step2 = step2;
}
}
My controller is(when the page start):
public ActionResult Create()
{
CreateStep1 step1=FillStep1();
CreateStep2 step2 = FillStep2();
CreateAllStep allStep = new CreateAllStep(step1, step2);
return View(allStep);
}
My controller is(when i click on the button, it's here where i would like send the model):
[HttpPost]
public ActionResult Create(String btn, CreateAllStep form)
{
if (Request.IsAjaxRequest())
{
if (btn != null)
{
if (btn == "Step1")
{
return PartialView("Step1",form.Step1);//not work
}
else if (btn == "Step2")
{
return PartialView("Step2");//work
}
else if(btn =="AllStep")
{
return PartialView("AllStep");
}
}
}
return View();
}
And my main view is :
#model SiteWebEmpty.Models.CreateAllStep
#{
ViewBag.Title = "Title";
}
<script type="text/javascript">
$(function () {
$('form').submit(function () {
$.post(this.action, $(this).serialize(), function (data) {
alert(data);
});
return false;
});
});
</script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<h2>Title</h2>
#using (Ajax.BeginForm("Create", //controller action name
"CreateStep", //controller name
new AjaxOptions //ajax options that tell mvc how to perform the replacement
{
UpdateTargetId = "ViewPage", //id of div to update
HttpMethod = "Post" //how to call the controller action
}, new { id = "FormName" }))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Create </legend>
<button type="submit" name="btn" value="Step1" id="Step1">Step 1</button>
<button type="submit" name="btn" value="Step2" id="Step2">Step 2</button>
<button type="submit" name="btn" value="AllStep" id="AllStep">All Step</button>
<div id="ViewPage">
#Html.Partial("Step1", Model)
</div>
</fieldset>
}
My partial view is:
#model SiteWebEmpty.Models.ArticleRequest.CreateArticle.ArticleRequestDisplayCreateAllStep
<fieldset>
<legend>Step 1</legend>
#Html.LabelFor(step1 => step1.Step1.Customer)
#Html.EditorFor(step1 => step1.Step1.Customer)
#Html.ValidationMessageFor(step1 => step1.Step1.Customer)
#Html.LabelFor(articleType => articleType.Step1.ArticleType)
#Html.DropDownList("ArticleType", Model.Step1.ArticleType)
#Html.ValidationMessageFor(articleType => articleType.Step1.ArticleType)
#Html.LabelFor(model => model.Step1.LabelType)
#Html.DropDownList("LabelType", Model.Step1.LabelType)
#Html.ValidationMessageFor(model => model.Step1.LabelType)
</fieldset>
render html:
<script src="/Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>
<h2>Title</h2>
<form action="/CreateStep/Create?Length=13" data-ajax="true" data-ajax-method="Post" data-ajax-mode="replace" data-ajax-update="#ViewPage" id="FormName" method="post"> <fieldset>
<legend>Create </legend>
<button type="submit" name="btn" value="Step1" id="Step1">Step 1</button>
<button type="submit" name="btn" value="Step2" id="Step2">Step 2</button>
<button type="submit" name="btn" value="AllStep" id="AllStep">All Step</button>
<div id="ViewPage">
<fieldset>
<legend>Step 1</legend>
<label for="Customer">Customer</label>
<input class="text-box single-line" data-val="true" data-val-required="Customer is required" id="Customer" name="Customer" type="text" value="" />
<span class="field-validation-valid" data-valmsg-for="Customer" data-valmsg-replace="true"></span>
<label for="ArticleType">Article Type</label>
<select data-val="true" data-val-required="ArticleType is required" id="ArticleType" name="ArticleType"><option value="127">AR1 : New Product</option>
<option value="161">AR2 : Product Modification</option>
</select>
<span class="field-validation-valid" data-valmsg-for="ArticleType" data-valmsg-replace="true"></span>
<label for="LabelType">Label Type</label>
<select data-val="true" data-val-required="LabelType is required" id="LabelType" name="LabelType"><option value="129">Private Label</option>
</select>
<span class="field-validation-valid" data-valmsg-for="LabelType" data-valmsg-replace="true"></span>
</fieldset>
</div>
</fieldset>
</form>
Thanks for your help :) !
Could you post the final HTML?
I think that your #Html.Partial("Step1", Model.Step1) will render a input text with id like Customer or ArticleType instead of Step1.Customer and Step1.ArticleType. What will bind to CreateAllStep.Customer that doesn´t exist.
If you have the Headers sent by the browsers will help too.
Update: Change your partial Step1, to accept a CreateAllStep Model and try again
Try removing your constructor on your ViewModel:
public CreateAllStep(CreateStep1 step1, CreateStep2 step2)
{
this.Step1 = step1;
this.Step2 = step2;
}
And change the controller code to:
public ActionResult Create()
{
CreateAllStep allStep = new CreateAllStep{Step1 = FillStep1(), Step2 = FillStep2()};
return View(allStep);
}
I have run into issues with constructors with parameters when databinding.
Related
I have the following form in a .NET Core application, consisting of a text input field and a "Submit" button.
I'd like the text from the text input field to re-appear in the form after submission, being passed to the controller action from the form and then being passed back to the view.
However, when I test the application, although the inputted values from the view appear when they are bound to the model in the controller, when they are passed back to the view they are wiped and I receive an "Object reference set to null" exception error.
I wondered if there's something missing from my code or what the potential cause of this may be?
Any advice would be great here,
Thanks,
Robert
// This is my view, featuring a simple form
// Values from the view are successfully being passed into the Controller
// This is the exception I receive when the values are passed back to the view:
My code:
#page
#model Models.StringModel
<div class="text-left">
<form asp-controller="Home" asp-action="Alter">
<span class="form-control">
<label asp-for="Name">Alter string:</label>
#if (#Model != null)
{
<input type="text" asp-for="Name" class="changeString" value="#Model.Name"/>
} else
{
<input type="text" asp-for="Name" class="changeString"/>
}
<input class="btn btn-primary" type="submit" value="Update" action="Update" />
</span>
</form>
</div>
StringModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace SplitString.Models
{
public class StringModel
{
public int ID { get; set; }
public string Name { get; set; }
}
}
HomeController.cs
using Microsoft.AspNetCore.Mvc;
using SplitString.Models;
using System.Threading.Tasks;
namespace SplitString.Controllers
{
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Alter([Bind("Id, Name")] StringModel stringModel)
{
stringModel.ID = 1;
return View("~/Pages/Index.cshtml", stringModel);
}
}
}
Thanks,
Robert
It looks like you are using a razor page project,so that you don't need to use mvc in it.You only need to use page handler:
Index.cshtml:
#page
#model IndexModel
<div class="text-left">
<form method="post">
<span class="form-control">
<label asp-for="stringModel.Name">Alter string:</label>
#if (#Model != null)
{
<input type="text" asp-for="stringModel.Name" class="changeString" value="#Model.stringModel.Name"/>
} else
{
<input type="text" asp-for="stringModel.Name" class="changeString"/>
}
<input class="btn btn-primary" type="submit" value="Update" action="Update" />
</span>
</form>
</div>
Index.cshtml.cs:
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
[BindProperty]
public StringModel stringModel { get; set; } = new StringModel();
public IndexModel(ILogger<IndexModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
public void OnPost()
{
stringModel.ID = 1;
//you can do something here
}
}
result:
By looking at this part of your code:
#if (#Model != null)
{
<input type="text" asp-for="Name" class="changeString" value="#Model.Name"/>
}
I saw that you are trying to access the Name property without checking if it has any value.
If you change your code to this it shouldn't throw an exception anymore.
#if (#Model != null && !string.IsNullOrEmpty(Model.Name))
{
<input type="text" asp-for="Name" class="changeString" value="#Model.Name"/>
}
please remove #page from your .cshtml file.
If you use View Engine to render cshtml, please don't use #page.
If you want to use #page, please use razor pages.
// #page
#model Models.StringModel
<div class="text-left">
<form asp-controller="Home" asp-action="Alter">
<span class="form-control">
<label asp-for="Name">Alter string:</label>
#if (#Model != null)
{
<input type="text" asp-for="Name" class="changeString" value="#Model.Name"/>
} else
{
<input type="text" asp-for="Name" class="changeString"/>
}
<input class="btn btn-primary" type="submit" value="Update" action="Update" />
</span>
</form>
</div>
I have a method to add new roles like:
public async Task<IActionResult> CreateRole(ApplicationRoleModel model)
{
try
{
foreach (var role in model.RoleList)
{
var roleExists = await _roleManager.RoleExistsAsync(role.Name);
if (roleExists) continue;
var createRole = _roleManager.CreateAsync(role);
}
return Ok();
}
catch (Exception e)
{
return BadRequest();
}
}
So as you can see I use foreach clause to access model who have IEnumerable of ApplicationRole like:
public class ApplicationRoleModel : ClaimsToRoleModel
{
public IEnumerable<ApplicationRole> RoleList { get; set; }
}
So as you can see in foreach I can access to role.Name of RoleList (ApplicationRole), I tested it with postman and it works, it added new Role successfull, now instead postman I want to create view to create new role so I try:
#page
#model Security.Dto.Models.ApplicationRoleModel
<form asp-controller="security" asp-action="CreateRole" method="post">
<h4>Create new Role</h4>
<hr />
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="RoleList.Name">Role Name</label>
<input asp-for="RoleList.Name" class="form-control" />
</div>
<button type="submit" class="btn btn-default">Create</button>
</form>
But when I try to compile project it return:
'IEnumerable' does not contain a definition for
'Name' and no extension method 'Name' accepting a first argument of
type 'IEnumerable' could be found (are you missing a
using directive or an assembly reference?)
So, how can I access to Name property of ApplicationRole to assign to model from view? Regards
Note: I also try to access it on my view like:
#for(Int32 i = 0; i < this.Model.RoleList.Count; i++ ) {
<div class="form-group">
<label asp-for="RoleList[i].Name">Role Name</label>
<input asp-for="RoleList[i].Name" class="form-control" />
</div>
}
But I get:
Cannot apply indexing with [] to an expression of type
'IEnumerable'
The model in your view is IEnumerable<ApplicationRole> but you attempting to create controls for a single instance of ApplicationRole
You could use List<ApplicationRole> instead of IEnumerable<ApplicationRole>in your model and use jquery to add role lists as below
Model:
public class ApplicationRoleModel : ClaimsToRoleModel
{
public List<ApplicationRole> RoleList { get; set; }
}
View:
#page
#model Security.Dto.Models.ApplicationRoleModel
<form asp-controller="security" asp-action="CreateRole" method="post">
<h4>Create new Role</h4>
<hr />
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group" id="item-list">
<label>Role Name</label>
<input asp-for="RoleList[0].Name" class="form-control items" />
</div>
Add another//click to add
<br />
<button type="submit" class="btn btn-default">Create</button>
</form>
#section Scripts {
<script>
$(function () {
$("#add").click(function (e) {
e.preventDefault();
var i = ($(".items").length);
var n = '<input class="form-control items" name="RoleList[' + i + '].Name" />'
$("#item-list").append(n);
});
});
</script>
}
I have come across a weird issue, I hope someone can explain why the following is happening.
My controller:
MasterModel main = new MasterModel();
public ActionResult Index()
{
return View();
}
[HttpGet]
public ActionResult VehicleDetail()
{
pageSessionSetup();
return PartialView("VehicleDetail", main.Vehicle);
}
[HttpPost]
public ActionResult VehicleDetail(VehicleDetailDisplay model)
{
ModelState.AddModelError("", "Errors occured");
main.Vehicle = model;
pageSessionSetup();
return PartialView("VehicleDetail", main.Vehicle);
}
Updated With View
My View:
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
#using (Ajax.BeginForm("VehicleDetail", "Operator", null, new AjaxOptions
{
UpdateTargetId = "VehicleDetail",
InsertionMode = InsertionMode.Replace,
HttpMethod = "Post"}, new { id = "VehicleDetail" }))
{
#Html.Partial("_ValidationSummary", ViewData.ModelState)
<div class="panel panel-default panel-body">
...
</div>
<div class ="col-lg-7 col-md-7 col-sm-7 col-xs-7 row">
<button type="submit" value="Save" class="btn btn-lg btn-green col-lg-2 col-md-5 col-sm-7 col-xs-7">Save</button>
</div>
}
And on my partial view I have a submit button, but when I click the submit button one time then the form gets submitted more than one time.
UPDATE:
use Html.BeginForm("ActionName", "ControllerName", FormMethod.Post) instead of Ajax.BeginForm() OR check if you have included the jquery.unobtrusive-ajax.min.js twice in your page(s)(in partial views also).
--------------------------------------------------------------------------------------------------------
#using (Html.BeginForm("ActionName", ""ControllerName", FormMethod.Post))
{
<label>SomeLabel</label>
...
<input type="submit" value="Button" /></p>
}
I am working with sample from codeproject http://www.codeproject.com/Tips/1011040/Upload-and-Delete-Video-File-to-Microsoft-Azure-Bl
I have created an index.cshtml in the way of
that is
#model List<string>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm("Add", "Blob", FormMethod.Post, new
{enctype = "multipart/form-data" }))
{
<div>
<input type="file" name="pic" id="pic" />
<input type="submit" value="Upload Now" id="s1" />
</div>
}
<ul>
#foreach (var item in Model)
{
<li>
<input type="button" name="b1" id="b1"
value="Delete"
onclick="Remove('#item')" />
<video src="#item" height="200" width="200" controls />
</li>
}
</ul>
#section scripts{
<script>
function Remove(x) {
alert(x);
var uri = "/Blob/remove";
$.post(uri, { name: x }, function (y) {
window.location.href = "/blob/index";
alert(y);
});
}
</script>}
and my Controller class is :
public class BlobsController : Controller
{
//
// GET: /Blobs/
BlBlobs objbl = new BlBlobs();
public ActionResult Index()
{
//return View();
return View(objbl.GetBlobList());
}
[HttpPost]
public ActionResult Add(HttpPostedFileBase pic)
{
objbl.AddBlob(pic);
return RedirectToAction("Index");
}
[HttpPost]
public string Remove(string name)
{
objbl.DeleteBlob(name);
return "Blob Removed Successfully";
}
}
That give me pretty nice browse/upload form, but fails on upload click with 404 error. The question is - how to call the add method correctly in this index.cshtml file?
Your controller is called BlobsController so that would give you a route of /blobs/{action} with the default route, however in your view your actions are looking for a controller called blob. Either change the name of your controller
public class BlobController : Controller
{
//...
}
Or update your views to use the correct controller name.
Html.BeginForm("Add", "Blobs", FormMethod.Post, new
{enctype = "multipart/form-data" }))
This is my form
#using (Html.BeginForm("EditPayments", "BookingPathLabelsCms"))
{
if (#Model.DisplayName == "Payment Labels")
{
<textarea id="seeit" name="seeit" rows="5" cols="10"></textarea>
<textarea id="seeitNoSelect" name="seeitNoSelect" rows="5" cols="10"></textarea>
<div class="cmsButtonContainer">
Cancel it
<input type="submit" name="Save" value="Save it"#* onmouseover="copyto();"*# />
</div>
}
}
And this is my controller action
public ActionResult EditPayments(BookingPathLabelsCmsViewModel model)
{
string txtarea = Request.Form["seeit"];
return RedirectToAction("Index");
}
Am not getting the values of textareas here,but values in the breakpoint ,see image.
Your code should looks like:
#using (Html.BeginForm("EditPayments", "BookingPathLabelsCms"))
{
if (#Model.DisplayName == "Payment Labels")
{
#Html.TextBoxFor(m => m.SeeIt)
#Html.TextBoxFor(m => m.SeeItNoSelect)
<div class="cmsButtonContainer">
Cancel it
<input type="submit" name="Save" value="Save it"#* onmouseover="copyto();"*# />
</div>
}
}
Of course, your ViewModel BookingPathLabelsCmsViewModel should have SeeIt and SeeItNoSelect properties. After that, MVC will bind correctly entered data.
First create a class with property.
public class TextAreaProperty
{
public string MyTextAreaValue { get; set; }
}
Use on the view declare like:
#model <project_name>.Models.<Class_name>
In this case:
#model MvcApplication1.Models.TextAreaProperty
Use this textArea Razor
#Html.TextAreaFor(x=> x.MyTextAreaValue)
On method post receiving parameter type TextAreaProperty
[HttpPost]
public ActionResult Index(TextAreaProperty textAreaProperty)
{
return View();
}
You will get the value from textAreProperty.