Maybe I'm looking at this the wrong way, maybe the fact that the browser is showing the view as a pop up doesn't change the fact that for MVC this is just a different View with it's own ViewModel. Since this is a form inside a form in a way, maybe there are better ways to do the following;
The initial view (CreateTimeslot.cshtml) is a form with properties of a workshop to be scheduled. name, description,.., And a speaker multiselect list:
#model MDFrontend.Models.Timeslots.TimeslotManagementViewModel
<div class="form-group">
<label asp-for="StartTime" class="control-label"></label>
<input asp-for="StartTime" type="datetime" class="form-control" value="#startTime" />
<span asp-validation-for="StartTime" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="EndTime" class="control-label"></label>
<input asp-for="EndTime" type="datetime" class="form-control" value="#startTime.Add(Model.WorkshopDuration)" readonly />
<span asp-validation-for="EndTime" class="text-danger"></span>
</div>
<!--------------------------------------------------------------SpeakerBox---------------------------------------------------------------------->
<div class="form-group">
<label asp-for="Speakers" class="control-label"></label>
<select asp-for="SpeakerIDs" id="speakerBox" name="SpeakerIDs[]" asp-items="#Model.Speakers" multiple="multiple">
</select>
<span asp-validation-for="SpeakerIDs" class="text-danger"></span> <!--This is not showing, asp-validation-summary does-->
</div>
<button onclick="showFormInPopup('#Url.Action("CreateSpeaker","SpeakerAdmin",Model,Context.Request.Scheme)',
'New Speaker')" type="button" id="btnAddSpeaker" class="btn btn-primary"> #Localizer["Add_Speaker"]
</button>
I'm passing the TimeslotManagementViewModel in the Url.Action method, which I'm mapping to the CreateSpeakerViewModel
public class CreateSpeakerViewModel
{
public string Firstname { get; set; }
public string Lastname { get; set; }
public TimeslotManagementViewModel oldModel { get; set; }
}
This view is shown as a popup:
<!-------------------------------------------Hidden Add Speaker Popup--------------------------------------------------->
<div class="modal" tabindex="-1" role="dialog" id="form-modal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
</div>
</div>
</div>
</div>
<!-------------------------------------------Hidden Add Speaker Popup--------------------------------------------------->
The body of this CreateSpeaker View:
#model MDFrontend.Models.Speakers.CreateSpeakerViewModel
<form asp-action="CreateSpeaker" asp-controller="SpeakerAdmin">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Firstname" class="control-label"></label>
<input asp-for="Firstname" class="form-control" />
<span asp-validation-for="Firstname" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Lastname" class="control-label"></label>
<input asp-for="Lastname" class="form-control" />
<span asp-validation-for="Lastname" class="text-danger"></span>
</div>
<div class="form-group" >
<input type="submit" value="Save" asp-action="CreateSpeaker" asp-controller="SpeakerAdmin"
formmethod="post" class="btn btn-primary" />
</div>
</form>
The CreateSpeaker Post method is receiving this simple form, adding them to the db, redirecting to the initial CreateTimeslot view with an updated multiselect.
[HttpPost]
[Authorize(Roles = RoleConstant.Admin)]
public async Task<IActionResult> CreateSpeaker(CreateSpeakerViewModel vm,
TimeslotManagementViewModel model)
{
//The idea would be to have TimeslotManagementViewModel model posted back with the set values by the user before "AddSpeaker" was clicked.
}
However with this solution the previous set inputs are lost to the user.
So atm I'm thinking either to use map every property of the TimeslotManagementViewModel to the CreateSpeakerViewModel to pass them between controllers or maybe an Ajax call could work or drop the popup all togheter. Or better yet someone here knows a better option?
Many thanks!
After some trail and error realized the best, maybe only solution comes by using some simple Javascript.
function SaveSpeaker(e) {
var firstname = $('#txtFirstname').val();
var lastname = $('#txtLastname').val();
$.ajax({
url: '/SpeakerAdmin/CreateSpeaker',
dataType: 'Json',
type: "POST",
data: { firstname: firstname, lastname: lastname },
success: function (data, status, jqXHR) {
console.log('success');
if (data.valFirstname == false) {
$('#valFirstname').text('Firstname not complete');
}
if (data.valLastname == false) {
$('#valLastname').val('Lastname not complete')
}
if (data.valSpeaker == true) {
$('#form-modal').modal('hide');
$('#valSpeaker').text('Speaker added');
$('#speakerBox').append(new Option(firstname + " " + lastname, data.speakerID))
}
},
error: function (jqXHR, status, err) {
},
complete: function (jqXHR, status) {
}
});
So instead of posting the form just using an Ajax call to post to the controller and return Json to populate the new select option.
Related
I have a partial view that will not show the result that it gets from the controller. This is in ASP.NET Core MVC 2.1.
The base for the code is from here.
Here is the partial view:
#model City
<!-- Modal -->
<div class="modal fade" id="myModal" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Grad</h4>
</div>
<div class="modal-body">
<form asp-controller="City" id="TestForm">
<div class="form-group">
<label class="control-label">Name</label>
<input asp-for="Name" class="form-control" id="CityName" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label class="control-label">Postal Code</label>
<input asp-for="PostalCode" class="form-control" id="PostalCode" onkeypress="return isNumberKey(event)" />
<span asp-validation-for="PostalCode" class="text-danger"></span>
</div>
<div class="form-group">
<label class="control-label">Country TEST</label>
<input type="text" id="txtCounty" name="CountyName"/>
<input type="hidden" id="hfCountry" name="CountyID" />
<span asp-validation-for="CountryID" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-default" id="SaveCity" />
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" id="CloseCity" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
The part in question is:
<div class="form-group">
<label class="control-label">Country TEST</label>
<input type="text" id="txtCounty" name="CountyName"/>
<input type="hidden" id="hfCountry" name="CountyID" />
<span asp-validation-for="CountryID" class="text-danger"></span>
</div>
It does not want to show the result it gets.
The jQuery method I use is, it is inside the Index.cshtml scripts:
$(document).on("focus", "#txtCountry", function (e) {
$("#txtCountry").autocomplete({
source: function (request, response) {
$.ajax({
url: '/City/AutoComplete/',
type: "POST",
data: { "prefix": request.term },
success: function (data) {
response($.map(data, function (item) {
return item;
}))
}
});
},
select: function (e, i) {
$("#hfCountry").val(i.item.val);
},
minLength: 1
});
});
When I put this code:
<input type="text" id="txtCounty" name="CountyName"/>
<input type="hidden" id="hfCountry" name="CountyID" />
outside the partial view it shows the searched for thing.
Here is controller for it:
[HttpPost]
public JsonResult AutoComplete(string prefix)
{
var countries = (from country in this._dbContext.Countries
where country.Name.ToLower().Contains(prefix.ToLower())
select new
{
label = country.Name,
val = country.ID
}).ToList();
return Json(countries);
}
Can anybody help I just can not find the answer.
I found the answer.
The text was showing behind the modal, that is way I could not see it.
<style>
.ui-autocomplete {
z-index: 5000;
}
</style>
Put that inside the _Layout.cshtml file, inside the enviroment.
<environment include="Development">
... some stuff...
<style>
.ui-autocomplete {
z-index: 5000;
}
</style>
... some ,oe stuff...
</environment>
In some viewmodel classes the [Required] attributes works as expected. When submitting the form, the error spans show an error message underneath the fields and the form is not submitted if the required fields do not meet the annotation requirements.
But in the example shared below, the form is submitted even if the required fields are empty (such as CompanyName) and I haven't figured out why, some help would be appreciated please.
Startup.cs
...
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage(); // throw a classic error page is evironment is development
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
...
EditCompanyVM.
public class EditCompanyVM
{
public EditCompanyVM()
{
Contact = new Contact();
Locations = new List<CompanyLocation>();
}
public int CompanyID { get; set; }
[Required(ErrorMessage = "Company name is required.")]
public string CompanyName { get; set; }
[Required(ErrorMessage = "Company description is required.")]
public string CompanyDescription { get; set; }
[Url]
public string CompanyWebsite { get; set; }
public Contact Contact { get; set; }
public List<CompanyLocation> Locations { get; set; }
}
EditCompany.cshtml
#model MyApp.Models.ViewModels.EditCompanyVM
#{
ViewBag.Title = "Edit Company";
}
<div class="col-md-8">
<h4 style="margin:0 0 30px 0;">Edit Company</h4>
<form method="post">
<div class="form-group">
<label asp-for="CompanyID" class="control-label">Company ID</label>
<input asp-for="CompanyID" disabled class="form-control" />
<span asp-validation-for="CompanyID" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CompanyName" class="control-label"></label>
<input asp-for="CompanyName" class="form-control" type="text" />
<span asp-validation-for="CompanyName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CompanyDescription" class="control-label">Company Description</label>
<input asp-for="CompanyDescription" class="form-control" />
<span asp-validation-for="CompanyDescription" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CompanyWebsite" class="control-label">Company Website</label>
<input asp-for="CompanyWebsite" class="form-control" />
<span asp-validation-for="CompanyWebsite" class="text-danger"></span>
</div>
<div id="contactSection">
<h4 style="margin:0 0 20px 0;">Contact Section</h4>
#if (Model.Contact != null)
{
<div class="form-group">
<label asp-for="Contact.ContactID" class="control-label">Contact ID</label>
<input asp-for="Contact.ContactID" disabled class="form-control" />
<span asp-validation-for="Contact.ContactID" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Contact.FirstName" class="control-label">First Name</label>
<input asp-for="Contact.FirstName" class="form-control" />
<span asp-validation-for="Contact.FirstName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Contact.LastName" class="control-label">Last Name</label>
<input asp-for="Contact.LastName" class="form-control" />
<span asp-validation-for="Contact.LastName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Contact.PhoneNumber" class="control-label">Phone Number</label>
<input asp-for="Contact.PhoneNumber" class="form-control" />
<span asp-validation-for="Contact.PhoneNumber" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Contact.Email" class="control-label">Email</label>
<input asp-for="Contact.Email" class="form-control" />
<span asp-validation-for="Contact.Email" class="text-danger"></span>
</div>
}
else
{
<a asp-action="AddContact" asp-route-userId="#Model.CompanyID" style="width:auto" class="btn btn-outline-primary">
Add Contact
</a>
}
</div>
<div id="locationsSection">
<h4 style="margin:20px 0 20px 0;">Company Locations</h4>
#if (Model.Locations.Any())
{
int counter = 1;
for (int i = 0; i < Model.Locations.Count; i++)
{
<h3>Location #counter</h3>
<div class="form-group">
<label asp-for="#Model.Locations[i].Street" class="control-label">Street</label>
<input asp-for="#Model.Locations[i].Street" class="form-control" />
<span asp-validation-for="#Model.Locations[i].Street" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="#Model.Locations[i].City" class="control-label">City</label>
<input asp-for="#Model.Locations[i].City" class="form-control" />
<span asp-validation-for="#Model.Locations[i].City" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="#Model.Locations[i].Province" class="control-label">Province</label>
<input asp-for="#Model.Locations[i].Province" class="form-control" />
<span asp-validation-for="#Model.Locations[i].Province" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="#Model.Locations[i].Country" class="control-label">Country</label>
<input asp-for="#Model.Locations[i].Country" class="form-control" />
<span asp-validation-for="#Model.Locations[i].Country" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="#Model.Locations[i].ZipCode" class="control-label">ZipCode</label>
<input asp-for="#Model.Locations[i].ZipCode" class="form-control" />
<span asp-validation-for="#Model.Locations[i].ZipCode" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="#Model.Locations[i].PhoneNumber" class="control-label">Location Phonenumber</label>
<input asp-for="#Model.Locations[i].PhoneNumber" class="form-control" />
<span asp-validation-for="#Model.Locations[i].PhoneNumber" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="#Model.Locations[i].Email" class="control-label">Branch Email</label>
<input asp-for="#Model.Locations[i].Email" class="form-control" />
<span asp-validation-for="#Model.Locations[i].Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="#Model.Locations[i].Manager" class="control-label">Manager Name</label>
<input asp-for="#Model.Locations[i].Manager" class="form-control" />
<span asp-validation-for="#Model.Locations[i].Manager" class="text-danger"></span>
</div>
counter++;
}
}
else
{
<a asp-action="AddLocation" asp-route-id="#Model.CompanyID" style="width:auto;" class="btn btn-outline-primary">
Add Location
</a>
</div>
}
<div class="form-group row" style="margin-top:80px;">
<div class="col-sm-10">
<button type="submit" class="btn btn-outline-primary">Update</button>
<a asp-action="ListCompanies" class="btn btn-outline-primary">Cancel</a>
</div>
</div>
</form>
</div>
CompanyController.cs
[HttpPost]
public async Task<IActionResult> EditCompany (EditCompanyVM model)
{
// model is submitted with null fields, even though warnings should trigger in the view
// by asp-validation-for
return RedirectToAction("ListCompanies");
}
There's been a lot of discussion in the comments, so I'd like to clear some things up.
Client-side validation happens in a user's browser, and requires scripts to take place. If a form is not valid, the script can prevent the form from being submitted, and display error messages for a user to correct. This is an enhancement for users, and servers, as it stops the majority of invalid requests being sent to the server, when they could be handled by the user in their browser.
Server-side validation takes place in addition to client-side validation - client-side validation is the optional extra, not the other way around, because users cannot be trusted to be non-malicious. Server-side validation within ASP.NET Core takes place using a combination of data annotations, and validators, that culminate in ModelState. Server-side validation will not prevent a form from being submitted in a user's browser, but can still send errors back to the browser via ModelState and returning your current model:
[HttpPost]
public async Task<IActionResult> EditCompany(EditCompanyVM model)
{
// This property indicates if the model's data,
// based on the data annotations it's
// decorated with, is valid.
if (!ModelState.IsValid)
{
// Returning the same instance of the model back
// to the view causes Razor to use the `ModelState`'s
// data to render errors via `asp-validation-for`.
return View(model);
}
// If no errors, redirect.
return RedirectToAction("Index");
}
Now, if your question is why you're able to submit the form without validation first taking place, and subsequently preventing invalid data from being submitted, this is all because of the client-side validation - it has nothing to do with your controller at all; this is all down to what's going on in your view.
If you take a look in your ~Views/Shared folder, you should see a view called _ValidationScriptsPartial.cshtml. The default views prefixed with a _ are intended to be used as partial views, although this is a convention you don't have to follow with your own views. If you open it up, you'll see it contains the following:
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
These are scripts for client-side validation, but they're not included by default. Therefore, to fix your problem, simply add the following at the bottom of your EditCompany.cshtml view:
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}
This will now render those scripts to the browser, loading client-side validation. Trying to submit your form now will trigger client-side validation, without hitting the server if the data is invalid.
I'm trying to refresh my Partial View after submitting a form which will be processed in my controller. The problem is that whenever I try to refresh it form my controller, I get redirected to a blank page with content from the Partial View.
Partial View
#model Smarty.Viewmodels.BugViewModel
<div class="modal fade" id="bugModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Bug Reporting Tool</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span>×</span>
</button>
</div>
<form asp-controller="Smarty" asp-action="SendBugReport" enctype="multipart/form-data">
#if (!string.IsNullOrWhiteSpace(ViewBag.message))
{
if (!ViewBag.IsError)
{
<span class="border border-success text-success">#ViewBag.message</span>
}
else
{
<span class="border border-danger text-danger">#ViewBag.message</span>
}
}
<div class="modal-body">
<label asp-for="Description" class="control-label"></label>
<textarea asp-for="Description" class="form-control"></textarea>
<span asp-validation-for="Description" class="text-danger"></span>
<label asp-for="FormFile" class="control-label"></label><br />
<input asp-for="FormFile" type="file" />
<span asp-validation-for="FormFile" class="text-danger"></span>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Schliessen</button>
<button type="submit" id="BugReportBtn" class="btn btn-success">Bug Report senden</button>
</div>
</form>
</div>
</div>
</div>
Controller
public async Task<IActionResult> SendBugReport(BugViewModel viewModel)
{
//Process Form
return PartialView("BugModal", viewModel);
}
Thanks in advance!
I get redirected to a blank page with content from the Partial View.
That is expected because you use return PartialView() which will return the simple partial html to render it into the view.
I want to refresh the Partial View with content like Error Messages, Success messages etc
You could not get #ViewBag.message from the SendBugReport action, it is passed from the action of main page.
As the comment has said that, first of all, you could use ajax to submit the form to SendBugReport action.Then the action return message and isError json data to ajax success function. Finally, you render message on the view based on the value of isError:
1.Partial View (Views/Shared/BugModal.cshtml)
#model BugViewModel
<div class="modal fade" id="bugModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Bug Reporting Tool</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span>×</span>
</button>
</div>
<form id="myForm" asp-controller="Smarty" asp-action="SendBugReport" enctype="multipart/form-data">
<div id="result"></div>
<div class="modal-body">
<label asp-for="Description" class="control-label"></label>
<textarea asp-for="Description" class="form-control"></textarea>
<span asp-validation-for="Description" class="text-danger"></span>
<label asp-for="FormFile" class="control-label"></label><br />
<input asp-for="FormFile" id="FormFile" name="FormFile" type="file" />
<span asp-validation-for="FormFile" class="text-danger"></span>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Schliessen</button>
<button type="button" id="BugReportBtn" class="btn btn-success">Bug Report senden</button>
</div>
</form>
</div>
</div>
</div>
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
<script>
$('#BugReportBtn').on('click', function (event) {
var url = "/Smarty/SendBugReport";
var description = document.getElementById("Description").value;
var fileInput = $('#FormFile')[0];
var formFile = fileInput.files[0];
var formData = new FormData();
formData.append("Description", description);
formData.append("FormFile", formFile);
$.ajax({
type: "POST",
url: url,
data: formData,
dataType: "json",
processData:false,
contentType: false,
success: function (data) {
if (!data.isError) {
$("#result").html("<span class='border border-success text-success'>" + data.message + "</span>");
} else {
$("#result").html("<span class='border border-danger text-danger'>" + data.message + "</span>");
}
$('#bugModal').modal('show');
}
});
});
</script>
2.Action
[HttpPost]
public async Task<JsonResult> SendBugReport(BugViewModel viewModel)
{
//Process Form
string message;
bool isError;
//set data to message and isError
return Json(new { message, isError });
}
I'm doing insert via post, but my class is getting zero values.
The values of the inputs are passed via variable and are displayed correctly, but at the moment of action via post are coming with zero values.
The most interesting thing is if you type inside the input, then the values come correctly.
<form method="post">
<div class="col-sm-3">
<label>SALDO</label>
<div style="border:1px solid #bbb9b9; border-radius:3px;"></div>
<br />
<div class="form-group">
<label asp-for="Caixas.ValorFinalDinheiro" class="control-label"></label>
<input asp-for="Caixas.ValorFinalDinheiro" name="Caixas.ValorFinalDinheiro" id="Caixas.ValorFinalDinheiro" class="form-control finalFundo" disabled="disabled" />
</div>
<div class="form-group">
<label asp-for="Caixas.ValorFinalCheque" class="control-label"></label>
<input asp-for="Caixas.ValorFinalCheque" class="form-control finalFundo" disabled="disabled"/>
</div>
<div class="form-group">
<label asp-for="Caixas.ValorFinalBoleto" class="control-label"></label>
<input asp-for="Caixas.ValorFinalBoleto" class="form-control finalFundo" disabled="disabled" />
</div>
<div class="form-group">
<label asp-for="Caixas.ValorFinalCartao" class="control-label"></label>
<input asp-for="Caixas.ValorFinalCartao" class="form-control finalFundo" disabled="disabled" />
</div>
<div class="form-group">
<label asp-for="Caixas.ValorFinalDeposito" class="control-label"></label>
<input asp-for="Caixas.ValorFinalDeposito" class="form-control finalFundo" disabled="disabled" />
</div>
<div class="form-group">
<label asp-for="Caixas.ValorFinal" class="control-label"></label>
<input asp-for="Caixas.ValorFinal" class="form-control" style="background-color:#9FF781" />
</div>
</div>
<div class="col-sm-12">
<div class="form-group">
<input type="submit" value="Confirmar o Fechamento do Caixa" class="btn btn-primary btn-sm" />
<a asp-page="Index" class="btn btn-success btn-sm">Retorna ao Caixa</a>
</div>
</div>
</form>
And the controller
[BindProperty]
public Caixas Caixas { get; set; }
public async Task<IActionResult> OnPostAsync()
{
var C = _context.Caixas.Find(Caixas.Id);
C.fechado = true;
C.DataFinal = DateTime.Now;
C.HoraFinal = DateTime.Now;
C.FuncionarioFechamentoId = _userManager.GetUserId(HttpContext.User);
C.ValorFinalDinheiro = Caixas.ValorFinalDinheiro;
C.ValorFinalCheque = Caixas.ValorFinalCheque;
C.ValorFinalBoleto = Caixas.ValorFinalBoleto;
C.ValorFinalCartao = Caixas.ValorFinalCartao;
C.ValorFinalDeposito = Caixas.ValorFinalDeposito;
C.ValorFinal = Caixas.ValorFinal;
C.ValorSaida = Caixas.ValorSaida;
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
In fact, all browsers should not submit the disabled inputs.
Following this
In this example, the INPUT element is disabled. Therefore, it cannot
receive user input nor will its value be submitted with the form.
<INPUT disabled name="fred" value="stone">
I don't know why you have a form like that. But to overcome this situation, you can add an <input type="hidden"> element with the same name and same value as the disabled input. And send the value in POST request.
Try to use, the Data Annotation "HttpPost" before your method. Like this:
[HttpPost]
public async Task<IActionResult> OnPostAsync()
{
...
}
I am trying to add in the Suppliers table a new entry. This table also has another one linked to it in which are stored the contracts with each supplier.
The desired functionality is to submit in the same form both the data for the new Supplier and the contract, but I can't make it work.
I am able to add a new supplier and after the contract by uploading the file separately in another form, but not in the same submit action.
How can I do that?
My form looks like this:
<form class="form-material m-t-40" enctype="multipart/form-data">
<div class="form-group has-warning">
<h4 class="entity-info"><label for="denumire" class="label-has-danger"> Denumire furnizor </label></h4>
<input type="text" id="denumire" name="denumire" class="form-control" placeholder="Denumire" [(ngModel)]="furnizor.denumire" #denumire="ngModel">
</div>
<div class="form-group has-warning">
<h4 class="entity-info"><label for="cod" class="label-has-danger"> Cod intern furnizor </label></h4>
<input type="text" id="cod" name="cod" class="form-control" placeholder="Cod intern" [(ngModel)]="furnizor.cod" #cod="ngModel">
</div>
<div class="form-group has-warning">
<h4 class="entity-info"><label for="cod" class="label-has-success"> Cod de inregistrare fiscala furnizor </label></h4>
<input type="text" id="codIntern" name="codIntern" class="form-control" placeholder="Cod" [(ngModel)]="furnizor.codIntern" #codIntern="ngModel">
</div>
<div class="form-group has-warning">
<h4 class="entity-info"><label for="adresa" class="label-has-success"> Adresa </label></h4>
<input type="text" id="adresa" name="adresa" class="form-control" placeholder="Adresa" [(ngModel)]="furnizor.adresa">
</div>
<div class="form-group has-warning">
<h4 class="entity-info"><label for="persoanaContact" class="label-has-success"> Persoana Contact </label></h4>
<input type="text" id="persoanaContact" name="persoanaContact" class="form-control" placeholder="Persoana Contact" [(ngModel)]="furnizor.persoanaContact" #reprezentant="ngModel">
</div>
<div class="form-group has-warning">
<h4 class="entity-info"><label for="telefon" class="label-has-success"> Telefon </label></h4>
<input type="tel" id="telefon" name="telefon" class="form-control" placeholder="Telefon" [(ngModel)]="furnizor.telefon" #telefon="ngModel">
</div>
<div class="form-group has-warning">
<h4 class="entity-info"><label for="dataIncepereContract" class="label-has-success"> Data incepere contract </label></h4>
<input type="date" class="form-control m-b-40" placeholder="2017-06-04" id="dataIncepereContract" name="dataIncepereContract" [(ngModel)]="furnizor.dataIncepereContract" #dataIncepereContract="ngModel">
</div>
<div class="form-group has-warning">
<h4 class="entity-info"><label for="dataExpirareContract" class="label-has-success"> Data expirare contract </label></h4>
<input type="date" class="form-control m-b-40" placeholder="2017-06-04" id="dataExpirareContract" name="dataExpirareContract" [(ngModel)]="furnizor.dataExpirareContract" #dataExpirareContract="ngModel">
</div>
<input type="file" #fileInput>
<button type="button" class="btn btn-md btn-add animated flipInX flipInY lightSpeedIn slideInUp" (click)="submit()">
<i class="fa fa-floppy-o"></i> Save
</button>
</form>
I have tried a lot of options and combinations for the file and the other form fields, but none work.
My ts file reads the file input like this:
...
#ViewChild('fileInput') fileInput: ElementRef;
...
submit() {
var nativeElement: HTMLInputElement = this.fileInput.nativeElement;
if (nativeElement.files) this.file = nativeElement.files[0];
this.furnizorService.create(this.furnizor, this.file).subscribe(() => {});
}
My service:
create(furnizor: any, fileToUpload: any) {
let input = new FormData();
input.append("file", fileToUpload);
furnizor.file = input;
return this.http.post('/api/furnizor', furnizor).map(res => res.json());
}
And in my C# Controller I tried:
[HttpPost("/api/furnizor")]
public async Task<IActionResult> CreateFurnizor([FromBody]FurnizorResource furnizorResource)
{
...
}
Where I added a new property
public IFormFile file { get; set; }
in FurnizorResource, but if I do this, furnizorResource is not mapped and is null.
I also tried sending them separately (just to try):
[HttpPost("/api/furnizor")]
public async Task<IActionResult> CreateFurnizor([FromBody]FurnizorResource furnizorResource, IFormFile file)
{
...
}
(Which obviously doesn't work since in the Angular service I can't send 2 "body" elements). With this method the furnizorResource data is correct, but of course file is null...
How can I post Json data and a file at the same time in Angular 4.3.6 and ASP.NET Core 2?
Have you tried something like that? That's teh way I use it in my app and it works.
var formData = new FormData()
for (var key in model)
formData.append(key, furnizor[key])
formData.append('file', fileToUpload)
let headers = new Headers({ 'Content-Type': 'multipart/form-data' })
let options = new RequestOptions({ headers: headers })
return this.authHttp.post('/api/furnizor', formData, options).map(res => res.json())
I understand that your both, Angular and c# must be the property fornitureResources that it will be a array of FornitureResource
interface Forniture
{
cod:number;
...
fornitureResources :IFromFile[]
}
So, e.g.
let myforniture={
cod:1,
...
fornitureResources:[
{ file:"file1"},
{ file:"file2"}
]
}
If you send "myforniture" using this.http.post('/api/furnizor', myforniture) you must be get a "Forniture" in your API