I have a BootStrap Modal Popup that I want to use for selecting and uploading a file. The pop-up works in all respects EXCEPT it is not passing the selected file to the underlying controller. Here is the form:
<!--Modal Body Start-->
<div class="modal-content">
<!--Modal Header Start-->
<div class="modal-header">
<h4 class="modal-title">Upload File</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
<!--Modal Header End-->
<form asp-action="FileUpload" asp-controller="Attachment" method="post" enctype="multipart/form-data">
#Html.AntiForgeryToken()
<div class="modal-body form-horizontal">
<div>
<p>Upload a file using this form:</p>
<input type="file" name="file" />
</div>
<!--Modal Footer Start-->
<div class="modal-footer">
<button data-dismiss="modal" id="cancel" class="btn btn-default" type="button">Cancel</button>
<input type="submit" class="btn btn-success relative" id="btnSubmit" data-save="modal" value="Upload">
</div>
<div class="row">
</div>
</div> <!--Modal Footer End-->
</form>
</div>
<script type="text/javascript">
$(function () {
});
</script>
<!--Modal Body End-->
Here is the action in the controller:
[HttpPost]
public IActionResult FileUpload(IFormFile file)
{
//DO something with the file
return View();
}
[HttpGet]
public ActionResult UploadFile(string issueid)
{
ViewBag.id = issueid;
return PartialView("_UploadFile");
}
The action gets called but the "file" variable is NULL.
I have the following markup & script on the MAIN page the pop-up originates from:
<div id="modal-container" class="modal fade" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
</div>
</div>
</div>
Upload Files
<script>
$('body').on('click', '.modal-link', function () {
var actionUrl = $(this).attr('href');
$.get(actionUrl).done(function (data) {
$('body').find('.modal-content').html(data);
});
$(this).attr('data-target', '#modal-container');
$(this).attr('data-toggle', 'modal');
});
$('body').on('click', '.relative', function (e) {
e.preventDefault();
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
var dataToSend = form.serialize();
$.post(actionUrl, dataToSend).done(function (data) {
$('body').find('.modal-content').html(data);
});
})
$('body').on('click', '.close', function () {
$('body').find('#modal-container').modal('hide');
});
$('#CancelModal').on('click', function () {
return false;
});
$("form").submit(function () {
if ($('form').valid()) {
$("input").removeAttr("disabled");
}
});
</script>
To upload form data with a file you have to use a FormData object.
Also, you have to use $.ajax, as $.past cannot handle the FormData object
$('body').on('click', '.relative', function (e) {
e.preventDefault();
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
var dataToSend = new FormData(form[0]);
$.ajax({
url: actionUrl,
type: 'POST',
data: dataToSend,
processData: false, //prevent jQuery from trying to serialize the FormData object
contentType: false, // prevents jQuery from setting the default content type
success: function(data){
$('body').find('.modal-content').html(data);
}
});
})
Related
I have a C# Razor Pages project.
I created a Login view in the following structure:
- Pages
- Account
- Login.cshtml
This is the code for my Login view
#page "{handler?}"
#model HAL_WEB.Pages.LoginModel
#{
Layout = "_LayoutLogin";
}
<section class="section register min-vh-100 d-flex flex-column align-items-center justify-content-center py-4">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-4 col-md-6 d-flex flex-column align-items-center justify-content-center">
<div class="d-flex justify-content-center py-4">
<a href="index.html" class="logo d-flex align-items-center w-auto">
<img src="assets/img/teamtruetech_logo.png" alt="">
<span class="d-none d-lg-block">HAL Admin</span>
</a>
</div><!-- End Logo -->
<div class="card mb-3">
<div class="card-body">
<div class="pt-4 pb-2">
<h5 class="card-title text-center pb-0 fs-4">Login to Your Account</h5>
<p class="text-center small">Enter your username & password to login</p>
</div>
<form id="login-form" class="row g-3 needs-validation" novalidate>
<div class="col-12">
<label for="yourUsername" class="form-label">Username</label>
<div class="input-group has-validation">
<span class="input-group-text" id="inputGroupPrepend"></span>
<input type="text" name="username" class="form-control" id="yourUsername" required>
<div class="invalid-feedback">Please enter your username.</div>
</div>
</div>
<div class="col-12">
<label for="yourPassword" class="form-label">Password</label>
<input type="password" name="password" class="form-control" id="yourPassword" required>
<div class="invalid-feedback">Please enter your password!</div>
</div>
<div class="col-12">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="remember" value="true" id="rememberMe">
<label class="form-check-label" for="rememberMe">Remember me</label>
</div>
</div>
<div class="col-12">
<button class="btn btn-primary w-100" type="submit">Login</button>
</div>
#* <div class="col-12">
<p class="small mb-0">Don't have account? Create an account</p>
</div>*#
</form>
</div>
</div>
</div>
</div>
</div>
</section>
#section Scripts {
<script src="~/assets/js/loginpage.js"></script>
}
And this is the code behind:
using HAL_WEB.Data;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Security.Claims;
namespace HAL_WEB.Pages
{
public class LoginModel : PageModel
{
private readonly ApplicationDBContext _dbContext;
public LoginModel([FromServices] ApplicationDBContext dbContext)
{
_dbContext = dbContext;
}
public void OnGet()
{
}
public async Task<IActionResult> OnPostLoginAsync(string username, string password)
{
// Check if the provided credentials are valid
if (IsValidCredentials(username, password))
{
// If the credentials are valid, log the user in
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, username) }, CookieAuthenticationDefaults.AuthenticationScheme)),
new AuthenticationProperties
{
IsPersistent = true, // Set this to true if you want the user to stay logged in after closing the browser
ExpiresUtc = DateTime.UtcNow.AddDays(7) // Set the expiration time for the cookie
});
// Redirect the user to the home page
return RedirectToPage("/Home");
}
else
{
// If the credentials are invalid, show an error message
ModelState.AddModelError(string.Empty, "Invalid username or password.");
return Page();
}
}
private bool IsValidCredentials(string username, string password)
{
// Replace this with your own validation logic
return username == "admin" && password == "password";
}
public IActionResult OnPostLoginTestAsync()
{
return new JsonResult(true);
}
}
In my Javascript file I tried to call the method OnPostLoginTestAsync or OnPostLoginAsync without success.
I'm getting a "Bad Request 400" error:
This is my Javascript Axios code for calling the method:
// Use Axios to send a POST request to the server with the form data
axios.post('/Account/Login?handler=login', {
username,
password,
})
.then((response) => {
// If the request is successful, redirect the page
window.location.href = '/home';
})
.catch((error) => {
// If there is an error, log it to the console
console.error(error);
});
Any clue what am I doing wrong? I'm going to /Account/Login?handler=login because the call is a Post and what I think is that the method OnPostLoginAsync should be executed.
UPDATE
I found something interesting, I created the following Get method:
public IActionResult OnGetTestAsync()
{
return new JsonResult(true);
}
And in my Javascript, I changed the Axios url to be:
axios.get('/Account/Login?handler=test')
.then(function (response) {
})
.catch(function (error) {
// Handle the error response
});
And I could get the method executed! But when I change the method name back to:
OnPostTestAsync
and my Axios to:
axios.post('/Account/Login?handler=test')
.then(function (response) {
})
.catch(function (error) {
// Handle the error response
});
It never gets executed and I get 400 Bad Request. Any clue?
how to make a file upload function in vue js ? here I create a dynamic form that can be added.
I made a form name and uploaded a file
when the add Attachment button is clicked, the form increases
when I send to the backend, only 1 file is sent, how to make the uploaded file into an array?
and this my code
<div class="col-6">
<div class="row row g-3" v-for="(attachment, index) in attachment" :key="index">
<div style="font-size:13px">Attachment</div>
<div class="col-sm-4">
<input type="text" v-model="attachment.att_name">
</div>
<div class="col-sm-7">
<div class="col">
<input type="file" id="file" ref="file" #change="selectFile"/>
</div>
</div>
</div>
<div style="margin-top: 15px;">
<button type="button" #click="addNewAttachment">Add Attachment</button>
</div>
</div>
//submit button
<div style="margin-top:50px">
<button type="button" #click="onsubmit">Submit</button>
</div>
and this
export default {
name : 'bbb',
data() {
return {
attachment : [
{
att_name: '',
att_file:'',
}
],
}
},
methods:{
selectFile(e) {
const selectedFile = e.target.files[0];
this.attachment.att_file = selectedFile;
},
addNewAttachment() {
this.attachment.push(
{
att_name: '',
att_file:'',
}
);
},
onsubmit(){
const data = new FormData();
data.append("item[]", JSON.stringify(this.attachment));
//for (var lop of data.entries()) {
//console.log(lop[1])
//}
}
}
}
I have ASP.NET Core MVC project. In my core project, I am using fluent validation like this:
public class AddEntityViewModelValidator: AbstractValidator<AddEntityViewModel>
{
public AddEntityViewModelValidator()
{
RuleFor(x => x.Name)
.NotEmpty()
.WithMessage("You must enter name.");
}
}
My controller looks like this:
[HttpPost]
public async Task<IActionResult> CreateEntity(AddEntityViewModel addEntityViewModel)
{
try
{
if (!ModelState.IsValid)
{
var errors = ModelState.Values.SelectMany(v => v.Errors.Select(x => x.ErrorMessage)).ToList();
foreach(var error in errors)
{
ModelState.AddModelError("Error: ", error);
}
return View(addEntityViewModel);
}
await _businessLogic.CreateEntity(addEntityViewModel.Entity);
return View(addEntityViewModel);
}
catch (Exception)
{
return View(addEntityViewModel);
}
}
When user doesn't enter the name in model dialog, fluent validation do the work. This list of errors (var errors in controller) contains this error, so this part is working. But in my cshmtl modal-dialog this error message is not showing anywhere.
I have the the button for opening modal dialog:
<div id="PlaceHolderHere"></div>
<button type="button" class="btn btn-success" data-toggle="ajax-modal" data-target="#addEntity"
data-url="#Url.Action("AddEntity", "Entity", new { entityId = Model.Id})">
Add entity
</button>
and my jquery code:
$(function () {
var PlaceHolderElement = $('#PlaceHolderHere');
$('button[data-toggle="ajax-modal"]').click(function (event) {
var url = $(this).data('url');
var decodeUrl = decodeURIComponent(url);
$.get(decodeUrl).done(function (data) {
PlaceHolderElement.html(data);
PlaceHolderElement.find('.modal').modal('show');
})
})
PlaceHolderElement.on('click', '[data-save="modal"]', function (event) {
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
var sendData = form.serialize();
$.post(actionUrl, sendData).done(function (data) {
PlaceHolderElement.find('.modal').modal('hide');
location.reload(true);
})
})
})
Here is my modal-dialog:
#model AddEntityViewModel
<div class="modal fade" id="addEntity">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title" id="addEntityLabel">#Model.Title</h3>
</div>
<div class="modal-body">
<form action="CreateEntity">
<div asp-validation-summary="All" class="text-danger wrapper"></div>
<div class="form-group">
<label asp-for="#Model.Entity.Name">Name</label>
<input asp-for="#Model.Entity.Name" class="form-control" />
<span asp-validation-for="#Model.Entity.Name" class="text-danger"></span>
</div>
</form>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" data-save="modal">Save</button>
<button type="button" class="btn btn-danger" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
So, i have this line:
<div asp-validation-summary="All" class="text-danger wrapper"></div>
but error is still now showing. Any idea how to solve this? Should I change something in my jquery function?
I want to make a dynamic dialog box. For that I need some data like title, content and viewmodel. The title and the content will be shown. But the viewmodel not bind correctly. To see the problem, I prefilled the first_name with 'foo'. But it should be 'my first name'.
To make the modal dialog dynamic, we have a modalDialog object that must be filled with the specific data. The openDialog function fill this data and open it.
Normally the dynamic part will be load by requirejs. For demonstrate the problem, I have made it here much easier.
Here the html code:
<!-- the dynamic modal dialog -->
<div id="modal-dialog" class="modal fade" role="dialog" data-backdrop="static" data-bind="css: modalDialog.classes">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-bind="click: modalDialog.close">×</button>
<h4 class="modal-title" data-bind="html: modalDialog.title"></h4>
</div>
<div data-bind="with: modalDialog.viewModel">
<div class="modal-body" data-bind="html: $parent.modalDialog.content"></div>
</div>
<div class="modal-footer" data-bind="foreach: modalDialog.buttons">
<button type="button" class="btn btn-primary" data-bind="click: action, text: label"></button>
</div>
</div>
</div>
</div>
<!-- Test button for open the dialog -->
<button type="button" class="btn btn-info" data-bind="click: testDialog">Open modal</button>
Here the javascript code for the modal dialog viewmodel:
// the main viewmodel
var appVM = {
modalDialog:
{
title: ko.observable(''),
content: ko.observable(''),
viewModel: ko.observable(this),
buttons: ko.observableArray([]),
classes: ko.observable(''),
open: function()
{
$("#modal-dialog").modal('show');
},
close: function()
{
$("#modal-dialog").modal('hide');
}
},
openDialog: function(title, content, viewModel, buttons, classes)
{
if (!viewModel)
viewModel = appVM;
if (!buttons)
buttons = [{action: appVM.modalDialog.close, label: 'Close'}];
if (!classes)
classes = '';
appVM.modalDialog.title(title);
appVM.modalDialog.content(content);
appVM.modalDialog.buttons(buttons);
appVM.modalDialog.classes(classes);
appVM.modalDialog.viewModel(viewModel);
appVM.modalDialog.open();
},
testDialog: function()
{
var vm = new userViewModel();
var title = 'Test Title';
var html = dialogContent;
var buttons = [
{ action: vm.onSave, label: 'Apply' },
{ action: appVM.modalDialog.close, label: 'Cancel' }
];
appVM.openDialog(title, html, vm, buttons);
}
};
ko.applyBindings(appVM);
At least the code for the dynamic data:
// the user data
function User(data)
{
var self = this;
self.first_name = ko.observable(data.first_name).extend({required: true});
self.last_name = ko.observable(data.last_name).extend({required: true});
}
// the user viewmodel
function userViewModel()
{
var self = this;
self.user = ko.observable(new User(
{
first_name: 'my first name',
last_name: 'my last name'
}));
self.onSave = function()
{
alert('save data');
};
}
// The loaded content for the dialog
var dialogContent = ' \
<div class="clearfix"> \
<div class="col-xs-12"> \
<div class="row form-group"> \
<label class="col-xs-12 col-sm-4 col-md-3">Vorname:</label> \
<input class="col-xs-12 col-sm-8 col-md-9" type="text" data-bind="textInput: user().first_name" title="" value="foo"/> \
</div> \
<div class="row form-group"> \
<label class="col-xs-12 col-sm-4 col-md-3">Nachname:</label> \
<input class="col-xs-12 col-sm-8 col-md-9" type="text" data-bind="textInput: user().last_name" title=""/> \
</div> \
</div> \
</div> \
';
You can try it here:
http://jsfiddle.net/p8zbfw65/
Update
With the Tip from Roy it works like expected. I inserted the boundHtml binding
ko.bindingHandlers.boundHtml = {
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
const contentHtml = ko.unwrap(valueAccessor());
element.innerHTML = contentHtml;
ko.applyBindingsToDescendants(bindingContext, element)
}
};
and changed the html: $parent.modalDialog.content
to boundHtml: $parent.modalDialog.content
The html binding inserts HTML but does not apply bindings to it. You will need a custom binding handler to do that. I wrote a simple one here.
I am new to backbone and Marionette.
My requirement is,
I have a main grid having few rows. If i select a row from grid i need to fetch the details and display on the same page.
Binding the grid is working fine. But when i click on the row data is not binding to html template. I am unable to find out the issue.
Below is my html template for row details
<script id="selected-broker-details-tmpl" type="text/x-handlebars-template">
<div id="pnl-broker-details" class="panel panel-default">
<div class="panel-heading">
Broker Details
</div>
<div id="broker-details-container" class="panel-body">
<div class="col-md-6">
<div class="form-group">
<label for="inputbrokerName" class="col-sm-3 control-label">BrokerName</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="inputbrokerName" placeholder="Broker Name" value="{{BrokerName}}">
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="inputMnemonic" class="col-sm-3 control-label">Mnemonic</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="inputMnemonic" placeholder="Mnemonic" value="{{Mnemonic}}">
</div>
</div>
</div>
</div>
</div>
</script>
Backbone view declaration
App.Views.BrokerDetails = Backbone.View.extend({
initialize: function () {
this.listenTo(this.model, 'change', this.render);
},
el: '#details',
template: brokerTemplates.BrokerDetailsTempalte,
render: function () {
this.$el.html(this.template({}));
}
});
Model and collection declaration
var BrokderDetails = Backbone.Model.extend({
BrokerId: null,
BrokerName: null,
Mnemonic: null,
OASYSMnemonic: null
});
var BrokerDetailsCollection = Backbone.Collection.extend({
initialize: function (options) {
this.model = BrokderDetails;
this.url = '/api/BrokerSelections/SelectedBroker/';
}
,
setParam: function (str) {
this.url = '/api/BrokerSelections/SelectedBroker/' + str;
this.fetch();
},
parse: function (data) {
return data;
}
});
click event in main grid
events: {
"click .selection": "selectedBroker",
},
selectedBroker: function (e) {
var details = new BrokerDetailsCollection();
var brokerdetails = new App.Views.BrokerDetails({ model: null, collection: details });
details.setParam($(e.currentTarget).data("id"));
details.fetch();
brokerdetails.render();
},
Now there are 2 issues,
1. Click event is firing 2 times, if i select a row i main grid
2. Model data is not binding to html template. I mean html template is displayed, but with empty values in textboxes