Ajax.BeginForm is loading a new page even with UpdateTargetId - c#

I did this right here:
#using (Ajax.BeginForm("UserProjMetric", "Users", new AjaxOptions { UpdateTargetId = "dailyMetric" }))
{
<input type="hidden" id="id" name="id" value="#Model.Id"/>
<span class=""><input type="text" class="startDate dates" placeholder="Start Date" id="startDate" name="startDate"></span>
<span class=""><input type="text" class="endDate dates" placeholder="End Date" id="endDate" name="endDate"></span>
<input class="btn btn-small" type="submit" value="Submit" />
}
But instead of updating the target id it just takes the entire partial and loads it on a new page. I really just want the specific div on the page updated not the entire page.
I am returning a partial view:
return PartialView("_UserProjMetric", model);

Related

ERROR 404 MVC ASP.NET Application server error '/'

I have a question about .Net MVC, because Visual Studio shows me the application server error in the following form?
Server error in application '/'. The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its
dependencies) may have been removed, renamed, or temporarily
unavailable. Please review the URL below and make sure it is spelled
correctly.
Requested URL: / Register
<form action="Account/Registra" method="post">
<input class="form-control" type="number" name="id" value="" placeholder="Id" required/>
<input class="form-control" type="text" name="nombre" value="" placeholder="Nombre" required/>
<input class="form-control" type="text" name="correo" value="" placeholder="Correo" required/>
<input class="form-control" type="password" name="contrasena" value="" placeholder="ContraseƱa"/>
<input class="form-control" type="text" name="direccion" value="" placeholder="Direccion" required/>
<input class="form-control btn btn-primary" type="submit" name="btn" value="Registrar" />
</form>
And this one that has the same action text "controller / action" but does this work correctly for me.
<form action="Account/Validar" method="get">
<input type="text" name="correo" value="" placeholder="Correo" required class="form-control"/>
<input type="password" name="contrasena" value="" placeholder="ContraseƱa" required class="form-control"/>
<input type="submit" name="btn" value="Ingresar" class="btn btn-primary form-control"/>
</form>
They both have their respective existing methods and views. Any solution or opinion about this error?
public ActionResult Registra()
{
return View();
}
[HttpPost]
public ActionResult Registra(MUsuario usuario)
{
HttpClient _http = new HttpClient();
_http.BaseAddress = new Uri("http://localhost:60467/");
var request = _http.PostAsJsonAsync("api/Values",usuario).Result;
if (request.IsSuccessStatusCode)
{
return RedirectToAction("Index","Account");
}
else
{
return RedirectToAction("Registro", "Account");
}
}

Upload multiple files with parameters in ASP.NET Core

My view model:
public class FileInfo
{
[Required]
[StringLength(50, ErrorMessage = "TitleErrorMessage", MinimumLength = 2)]
public string Title { get; set; }
[Required]
[StringLength(100, ErrorMessage = "DesErrorMessage", MinimumLength = 3)]
public string Description { get; set; }
[Required]
[DataType(DataType.Upload)]
public IFormFile File { get; set; }
}
The following is _UploadForm partial view file:
#model SessionStateTest.Models.FileInfo
<div class="form-group">
<label>Title</label>
<input class="form-control" asp-for="Title" />
</div>
<div class="form-group">
<label>Description</label>
<input class="form-control" asp-for="Description" />
</div>
<div class="form-group">
<label></label>
<input type="file" asp-for="File" />
</div>
That is used in another View with this code:
<form asp-action="AddUploadForm" asp-controller="Home" method="Post">
<input type="submit" value="Add another file" class="btn btn-sm btn-primary" />
</form>
<form asp-action="Upload" asp-controller="Home" method="Post" enctype="multipart/form-data">
#foreach (var item in Model.Upload)
{
#(await Html.PartialAsync("_UploadForm", item))
}
<div class="col-xs-12">
<input type="submit" value="Upload" class="btn btn-sm btn-info" />
</div>
</form>
Basically AddUploadForm action adds a new view model of type FileInfo to Model.Upload which is my main view model.
The problem is that the list List<FileInfo> vm in Upload action below is totally empty:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Upload(List<FileInfo> vm)
{
.... some other logic
return View();
}
I don't want to use multiple attribute because I would like to force user to provide a title and description for every file.
Any help is kindly appreciated!
Your approach with using _UploadForm generates the following html (let's focus on input's only since this is the most important part)
<input class="form-control" name="Title" />
<input class="form-control" name="Description" />
<input type="file" name="File" />
...
<input class="form-control" name="Title" />
<input class="form-control" name="Description" />
<input type="file" name="File" />
... and so on
So name attributes contains only FileInfo model's properties names without indexes and this is only suitable for the case when your controller expects single model
public IActionResult Upload(FileInfo vm)
And in order to make your html work with your current controller with list of models
public IActionResult Upload(List<FileInfo> vm)
It should look like this
<!-- version 1 -->
<input class="form-control" name="[0].Title" />
<input class="form-control" name="[0].Description" />
<input type="file" name="[0].File" />
...
<input class="form-control" name="[1].Title" />
<input class="form-control" name="[1].Description" />
<input type="file" name="[1].File" />
... and so on
Or
<!-- version 2 -->
<!-- the name before index must match parameter name in controller -->
<input class="form-control" name="vm[0].Title" />
<input class="form-control" name="vm[0].Description" />
<input type="file" name="vm[0].File" />
...
<input class="form-control" name="[1].Title" />
<input class="form-control" name="[1].Description" />
<input type="file" name="vm[1].File" />
... and so on
This is possible to accomplish using tag helpers and partial view in slightly different way. All you need to do is turn partial view's model to list and update asp-for expressions.
_UploadForm.cshtml
#model List<SessionStateTest.Models.FileInfo>
#for (int i = 0; i < Model.Count; i++)
{
<div class="form-group">
<label>Title</label>
<input class="form-control" asp-for="#Model[i].Title" />
</div>
<div class="form-group">
<label>Description</label>
<input class="form-control" asp-for="#Model[i].Description" />
</div>
<div class="form-group">
<label></label>
<input type="file" asp-for="#Model[i].File" />
</div>
}
View
<form asp-action="Upload" asp-controller="Home" method="Post" enctype="multipart/form-data">
#await Html.PartialAsync("_UploadForm", Model.Upload)
<div class="col-xs-12">
<input type="submit" value="Upload" class="btn btn-sm btn-info" />
</div>
</form>
It will generate html like in version 1.

Add antiforgery token in handlebars template

I have changed a razor view to a handlebars template.
In the razor view:
using (Html.BeginForm("Start", "Form", FormMethod.Post, new { formTypeId = #Model.TypeId, organizationId = #Model.OrganizationId }))
{
#Html.AntiForgeryToken()
<input type="hidden" name="formTypeId" value="#Model.TypeId" />
<input type="hidden" name="organizationId" value="#Model.OrganizationId" />
<button class="btn btn-primary btn-block" type="submit">Start</button>
}
In the handlebars template:
<form action="{{StartLink}}" method="post">
<input type="hidden" name="formTypeId" value="{{TypeId}}" />
<input type="hidden" name="organizationId" value="{{OrganizationId}}" />
<button class="btn btn-primary btn-block" style="margin-bottom: 5px;" type="submit">Start</button>
</form>
I am unsure how to add the antiforgery token to the handlebars form.
ok here is what I came up with.
in my index.cshtml I pass an antiforgery token to the js that creates the handlebars template.
#section scripts {
<script>
$(function () {
window.formListBuilder = new app.components.FormListBuilder({
container: '#forms-container',
baseUrl: '#baseUrl.ToString()',
antiForgeryToken: '#Html.AntiForgeryToken()',
currentUser: JSON.parse('#Html.Raw(Json.Serialize(currentUser))')
})
});
</script>
}
then in the handlebars template I use the antiforgery token.
<form action="{{StartLink}}" method="post">
{{{antiForgeryToken}}}
<input type="hidden" name="formTypeId" value="{{TypeId}}" />
<input type="hidden" name="organizationId" value="{{OrganizationId}}" />
<button class="btn btn-primary btn-block" style="margin-bottom: 5px;" type="submit">Start</button>
</form>
is that an acceptable solution or does that bypass security in some way?

How to bind list of objects in ASP.NET MVC when one item in between is deleted

I have an issue while Binding model To A List in MVC. My page has a functionality to add and delete text-box dynamically. My page HTML will be
<form id="prdt">
<div id="div_0"> <input type="text" name="products[0].Name" value="Coffee"/><button id="0" onclick="return DeleteLocation(this.id)">Delete</button></div>
<div id="div_1"> <input type="text" name="products[1].Name" value="Tea" /><button id="1" onclick="return DeleteLocation(this.id)">Delete</button></div>
<div id="div_2"> <input type="text" name="products[2].Name" value="Cola" /><button id="2" onclick="return DeleteLocation(this.id)">Delete</button></div>
<div id="div_3"> <input type="text" name="products[3].Name" value="Pepsi" /><button id="3" onclick="return DeleteLocation(this.id)">Delete</button></div>
</form>
Below is the code to delete the textbox
<script type="text/javascript">
function DeleteLocation(id) {
$("#div_" + id).remove();
}
</script>
But when I delete "Cola" text-box and do an ajax post I am getting only Coffee and Tea in my list(Controller Action Post). i.e last one is omitted in the list
Similarly when I delete "Tea" text-box and do an ajax post I am getting Coffee only. i.e other three values are excluded in the list.
I think list is binding with on List index. Is there any way to get all values even if any item in between is deleted.
It can be done by adding special field named products.Index with the value of what next index will be. You need to repeat that for each new index:
<form id="prdt">
<div id="div_0">
<input type="hidden" name="products.Index" value="0" />
<input type="text" name="products[0].Name" value="Coffee"/>
<button id="0" onclick="return DeleteLocation(this.id)">Delete</button>
</div>
<div id="div_1">
<input type="hidden" name="products.Index" value="1" />
<input type="text" name="products[1].Name" value="Tea" />
<button id="1" onclick="return DeleteLocation(this.id)">Delete</button>
</div>
<div id="div_2">
<input type="hidden" name="products.Index" value="2" />
<input type="text" name="products[2].Name" value="Cola" />
<button id="2" onclick="return DeleteLocation(this.id)">Delete</button>
</div>
<div id="div_3">
<input type="hidden" name="products.Index" value="3" />
<input type="text" name="products[3].Name" value="Pepsi" />
<button id="3" onclick="return DeleteLocation(this.id)">Delete</button>
</div>
</form>
You can find more info in this article, section 'Non-Sequential Indices'
You can extend your javascript function to give the proper names to your products collection:
<form id="prdt">
<div id="div_0">
<input type="text" name="products[0].Name" class="product" value="Coffee"/>
<button id="0" onclick="return DeleteLocation(this.id)">Delete</button>
</div>
<div id="div_1">
<input type="text" name="products[1].Name" class="product" value="Tea" />
<button id="1" onclick="return DeleteLocation(this.id)">Delete</button>
</div>
<div id="div_2">
<input type="text" name="products[2].Name" class="product" value="Cola" />
<button id="2" onclick="return DeleteLocation(this.id)">Delete</button>
</div>
<div id="div_3">
<input type="text" name="products[3].Name" class="product" value="Pepsi" />
<button id="3" onclick="return DeleteLocation(this.id)">Delete</button>
</div>
<script type="text/javascript">
function DeleteLocation(id) {
$("#div_" + id).remove();
$(".product").each(function(i){
$(this).prop('name',"products["+i+"].Name" );
});
};
</script>
Here's the result after deleting 'Tea' product and post to a controller action.

MVC BeginForm No Data Posted

I am using MVC BeginForm with code below, i cannot get the value fpr input controls in my controller. am i doing anytyhing wrong here?
using (Ajax.BeginForm("CreateApp", "App",
new AjaxOptions { UpdateTargetId = "my-modal-dialog", OnBegin = "Dialog.Closing()", OnSuccess = "Dialog.Close()" },
new
{
#class = "appform"
}
))
{
<input id="newAppName" type="text" size="35" value="" />
#Html.TextBoxFor(model => model.Application.AppName);
<input type="submit" value="Start App" class="demo-button ui-state-default ui-corner-all" />
}
My Controller looks like this
[HttpPost]
public ActionResult CreateApp(AppContent app, string newAppName)
{
}
try changing
<input id="newAppName" type="text" size="35" value="" />
to
<input name="newAppName" type="text" size="35" value="" />

Categories