I'm building a support contact form where the user can upload files. The file upload is managed using AJAX: the user can upload the files, then submit the form at their convenience. The current layout that works is, however, not aesthetic: the upload input is below the form submit button.
I read about nested forms and the new form attribute and I thought this would do the trick:
<form action="" method="post" enctype="multipart/form-data" id="main-form">
...
<form action="/upload_file_ajax.php" method="post" id="file-upload-form">
<div class="form-group row mb-3 mb-3">
<label class="col-sm-3 col-lg-3 col-form-label" for="file"><?php echo $label['attach-file']; ?></label>
<div class="col-sm-8 col-lg-7">
<input class="form-control custom-file-input" name="file" id="file" type="file" form="file-upload-form" />
</div>
</div>
</form>
<div class="form-group row">
<div class="col-4 offset-3">
<button type="submit" name="submit" class="btn btn-outline-success" form="main-form"><?php echo $label['submit-button']; ?></button>
</div>
</div>
</form>
I have added the form attribute to every input and button. However, the inner form ("file-upload-form") won't submit at all when I add the file.
Could it be because this is an auto-submit input, i.e. the Javascript triggers the AJAX when the file is selected? This is the trigger line:
$('#file-upload-form').on('change', function(e){
...
As soon as I move the nested form below the closing </form> tag of the main form, it works.
If the aesthetic layout can be achieved in any other way, e.g. the file upload input can appear above the Submit button without nesting the forms, please let me know.
EDIT: This is the revised Javascript that takes care of the file upload via AJAX. I have removed the inner form tags as advised but the input still won't submit.
$(function(){
// listen for input changes (when a file is selected)
$('#file-upload-input').on('change', function(e){
//var formData = new FormData();
// file has been selected, submit it via ajax
$.ajax({
type: 'POST',
url: "/upload_file_ajax.php",
data: new FormData(this),
cache: false,
contentType: false,
processData: false,
success: function(data){
// the upload_file_ajax.php endpoint returns the file name and a status message for the uploaded file
console.log(data.filename, data.message);
// we then inject these into the main data form
var $hiddenInput = $('<input type="hidden" name="uploads[]" value="'+data.filename+'">');
$('#main-form').append($hiddenInput);
// show a thumbnail maybe?
var $thumbnail = $('<img src="/uploaded_files/'+data.filename+'" width="40" height="40" />');
$("#preview").append($thumbnail);
$("#status").html(JSON.stringify(data.message));
// reactivate file upload form to choose another file
$('#file-upload-input').val('');
},
error: function(){
console.log("error");
}
});
});
});
This is what the revised HTML looks like:
<form action="" method="post" enctype="multipart/form-data" id="main-form">
... (other inputs here)...
<div class="form-group row offset-3 mb-3">
<div class="col-12" id="preview"></div>
<div class="col-12" id="status"></div>
</div>
<div class="form-group row mb-3 mb-3">
<label class="col-sm-3 col-lg-3 col-form-label" for="file"><?php echo $label['attach-file']; ?></label>
<div class="col-sm-8 col-lg-7">
<input class="form-control custom-file-input" name="file" id="file" type="file" id="file-upload-input" form="file-upload-form" />
</div>
</div>
<div class="form-group row">
<div class="col-4 offset-3">
<button type="submit" name="submit" class="btn btn-outline-success" form="main-form"><?php echo $label['submit-button']; ?></button>
</div>
</div>
</form>
Here is how I solved my problem. I found the answer here, on SO, but can't find the link to the post any more.
The problem with uploading a file independently, without submitting the form or without having <form>...</form> tags, is that FormData(); does not contain the file as it does when the <form>...</form> tags are present. So, you need to append the file to it.
Here is my entire jQuery code that takes care of the file upload. On success, it creates additional form input tags containing the uploaded files info, so that I can submit them together with the form. It also creates a thumbnail for each uploaded image, and a Delete button next to the input in case the user changes their mind.
$('#file-upload-input').change(function(){
var file_data = $('#file-upload-input').prop('files')[0];
var form_data = new FormData();
// pass the file itself – needed because the input is submitted without <form> tags
form_data.append('file', file_data);
// pass website language variable to the PHP processor to load the correct language file
form_data.append('lang', '<?php echo $lang; ?>');
$.ajax({
url: "/ajax_upload_file.php",
type: "POST",
data: form_data,
cache: false,
contentType: false,
processData: false,
success: function(data){
// the upload_file_ajax.php endpoint returns the file name and a status message for the uploaded file
console.log(data.filename, data.message);
// we then inject these into the main data form
var $hiddenInput = $('<div class="input-group mb-1"><input class="form-control" readonly type="text" name="uploads[]" value="'+data.filename+'" /><input type="button" name="delete_'+data.filename+'" id="delete_'+data.filename+'" value="Delete" class="delete btn btn-outline-danger ms-2" /></div>');
$('#uploaded_files').append($hiddenInput);
// show a thumbnail if the uploaded file is an image
var $thumbnail = $('<img src="/uploaded_files/'+data.filename+'" height="75" id="img_'+data.filename+'" class="me-1" />');
$("#preview").append($thumbnail);
// print a status message returned from the PHP processor
$("#status").html(data.message);
// reactivate file upload form to choose another file
$('#file-upload-input').val('');
},
error: function(){
console.log("error");
}
});
});
This is the relevant HTML. It contains divs for the inputs containing the uploaded files names, for the thumbnails (called "preview"), and for the status message returned from the PHP script.
<div class="form-group row offset-2 mb-3">
<div class="col-sm-8 col-lg-7" id="uploaded_files">
</div>
</div>
<div class="form-group row offset-2 mb-3">
<div class="col-12" id="preview"></div>
</div>
<div class="form-group row offset-2 mb-3">
<div class="col-12" id="status"></div>
</div>
<div class="form-group row mb-3 mb-3">
<label class="col-sm-3 col-lg-2 col-form-label" for="file"><?php echo $label['attach-file']; ?></label>
<div class="col-sm-8 col-lg-7">
<input class="form-control custom-file-input" name="file" type="file" id="file-upload-input" />
</div>
</div>
Related
I can't submit the form even though I used preventDefault, (page refreshed and doesn't take any action) My form inputs are filled dynamically here is my code.
HTML
<div class="modal-body">
<form id="update_form">
<!-- loaded below -->
</form>
</div>
another request that fill my form data
#csrf
<div class="form-row">
<div class="form-group col-md-6">
<input type="hidden" name="request_type" value="{{RegisterTypesNames::Faculty}}">
<label>University</label>
<select name="university" class="custom-select" id="university{{$action}}">
<option selected value="1">University of Cansas</option>
</select>
</div>
<div class="form-group col-md-6">
<label>Faculty</label>
<input type="text" class="form-control" name="faculty" id="faculties{{$action}}">
</div>
<div class="form-group col-md-6">
<label>Init</label>
<input type="text" class="form-control" name="short_name" id="short_names{{$action}}">
</div>
</div>
<button type="submit" class="btn btn-primary"><span class="fa fa-save"></span> Save</button>
And jquery code
$('#update_form').submit(function (e) {
$.ajax({
url: '/update_data',
type: "POST",
data: $('#update_form').serialize(),
dataType: "json",
success: function (data) {
console.log(data.result);
}
});
e.preventDefault();
});
Note: I use multiple partial forms like this all others works fine
I can't submit the form even though I used preventDefault, (page refreshed and doesn't take any action)
Interpretation: the statements "page refreshed" and "used preventDefault" indicate that the problem is that the code inside the $("#id").submit( is not firing and the page's default submit is kicking in hence the "page refreshed".
As the jquery event is not firing, it likely means that the HTML does not exist when the script runs. This can usually be handled by putting in a doc.ready; OP indicates that it's already in doc.ready.
The alternative is to use event delegation. Though it's not clear if the code is running before the HTML is generated or if the HTML is added after (subtle difference).
The solution for event delegation is to use:
$(document).on("submit", "#update_form", function(e) {
e.preventDefault();
$.ajax({...
});
I created an html form which submits data to my backend when submitted. The backend then redirects the webpage and shows a json message. I would like to remain on the same page and capture that json message to show to the user. I tried doing this using AJAX forms (https://jquery-form.github.io/form/) however upon clicking the submit button, the page still redirects and the script is kind of ignored.
Script included in the head after the CSS:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.form/4.2.2/jquery.form.min.js" integrity="sha384-FzT3vTVGXqf7wRfy8k4BiyzvbNfeYjK+frTVqZeNDFl8woCbF0CYG6g2fMEFFo/i" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script>
// wait for the DOM to be loaded
$(function() {
// bind 'myForm' and provide a simple callback function
$('#signup-form').ajaxForm(function() {
alert("Thank you for your comment!");
});
});
</script>
The form:
<form id="signup-form" action="https://example-placeholder.com/api/auth/register" method="POST">
<div class="form-group row">
<div class="col">
<input type="email" class="form-control" id="username" name="username" placeholder="Email" required>
</div>
</div>
<div class="form-group row">
<div class="col">
<input type="password" class="form-control" id="password" name="password" placeholder="Password" required>
</div>
</div>
<div class="form-group row">
<div class="col">
<button type="submit" class="btn btn-custom btn-block" id="register-button">Register</button>
</div>
</div>
<label id="submit-label" style="display: none;">Check your inbox to activate your account!</label>
</form>
Response returned by backend:
return response()->json([
'message' => 'Successfully created user!'
], 201);
Errors returned by Google Chrome:
UPDATE (To fix CORS Error):
Added the following three lines before RewriteEngine On in the .htaccess file of my backend:
Header add Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Headers "origin, x-requested-with, content-type"
Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"
Can Anyone solve this problem?pop-up message
I have this code below
<body>
<div class="contact-form-wrap responsive">
<!--- pop-up message start --->
<div class="status alert alert-success contact-status"></div>
<!--- pop-up message end --->
<form id="main-contact-form4" class="contact-form" name="contact-form" method="post" action="app.php" role="form">
<legend style="padding-bottom: 20px; color: #708090;">Please provide us your information.</legend>
<!-- Name Filed Starts -->
<div class="col-sm-6">
<div class="form-group">
<div class="input-group">
<span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
<input type="text" class="form-control" name="name" id="name" required="required" placeholder="Full Name">
</div>
</div>
</div>
<!-- Name Filed Ends -->
<!---------------- Pop-up Message here ---------------->
<!-- Button starts -->
<div class="col-sm-12">
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block">Submit</button>
</div>
</div>
<!-- Button Ends -->
</form>
</div>
</div>
</body>
I like to move my pop-up message on the top of the button. so every time the button will press the pop-up message will notice immediately.
here is my js
$(".contact-form").submit(function() {
var rd = this;
var url = "app.php";
$.ajax({
type: "POST",
url: url,
data: $(".contact-form").serialize(),
success: function(data) {
$(rd).prev().text(data.message).fadeIn();
}
});
return false;
});
The problem with your code is that you're selecting the popup message based on it's location in the DOM. You need to select it on a proper selector instead. Since it has a class called contact-status, let's use that.
Change:
$(rd).prev().text(data.message).fadeIn();
to
$('.contact-status').text(data.message).fadeIn();
It's a bad idea to select elements from their location in the DOM since you sometimes (like now) want to move them. Using proper selectors (like id's or classes) will keep your code working regardless where in the DOM the element is.
I am working on a project with Symfony 2.8. My main goal is to create a dynamic calendar based on Fullcalendar library.
I add my events called "dispos" (avalabilities in English) and "Rdvs" (appointments" in English) through a Json request and ajax. This works fine.
Now, I would like to transform availabilites into appointements (which are both considered as events in Fullcalendar).
E.g : When someone clicks on one availability a modal shows up, then the person fills the form in it and clicks "save" button.
When the "save" button is clicked, all informations entered in the form are sent and saved (through a Json request) into my Database and the appointment is taken
--> all events of the current should be reloaded through ajax, the event should be displayed with the title of the event entered (name of the patient) and the modal should contain all informations given/wrote before "save" action.
I tried to do it but my ajax is not working since events do not reload after saving everything else is working.
Anyway, I think I did it wrong somewhere. The code I will show you in my Controller returns a view because I didn't manage to return a response (+ I think routing or something is bad but don't know how to fix it...)
Any clue or advice woud be really appreciated :)
So here is my code :
TakeRdvAction in my controller :
/* ----------------- /
/ --- TAKE RDV ---- /
/ ----------------- */
public function takeRdvAction(){
$request = $this->get('request_stack')->getCurrentRequest();
parse_str($request->getContent(), $myArray);
/*$request->isXmlHttpRequest()*/
if (1) {
$dateHeureDispo=$myArray['heureDispo'];
$dateDispo= new \DateTime($dateHeureDispo);
$heureDispo = $dateDispo->format('H:i');
$dateDispo=$dateDispo->format('d-m-Y');
$civilite=$myArray['civilite'];
$nom=$myArray['inputNom'];
$prenom=$myArray['inputPrenom'];
$naissance=$myArray['birth'];
$email=$myArray['email'];
$tel=$myArray['tel'];
$telFixe=$myArray['telFixe'];
$adresse=$myArray['adresse'];
$cp=$myArray['cp'];
$ville=$myArray['ville'];
$pays=$myArray['pays'];
$medecin_traitant=$myArray['medecin_traitant'];
$ame=$myArray['ame'];
$cmu=$myArray['cmu'];
$takeRDv="http://connect.mysite.com/nameofapi2/takeappt?center=13&motive=238&prenom=".urlencode($prenom)."&nom=".urlencode($nom)."&email=".urlencode($email)."&birthdate=".$naissance."&address=".urlencode($adresse)."&cp=".$cp."&city=".urlencode($ville)."&country=".urlencode($pays)."&tel=".$tel."&titre=1&source=1&origine=1&daterdv=".$dateDispo."&time=".$heureDispo."&slot=1%E1%90%A7&civilite=".$civilite."&origin=smwh&referer=1";
$streamContext = stream_context_create([
'ssl' => [
'verify_peer' => false,
'verify_peer_name' => false
]
]);
$json = file_get_contents($takeRDv, false, $streamContext);
$response = new jsonResponse();
$response->setContent($json);
return $this->indexAction();
}
else {
return new response("Ajax request failed");
}
}
If I put if ($request->isXmlHttpRequest()), the controller goes directly to "else" end returns "Ajax request failed"
Ajax.js file (It's the last ajax function we are talking about):
$(document).ready(function () {
/* TakeRdvs */
$("#monBouton").click(function(){
if (nom.value != "" && prenom.value != "" && email.value != "")
{
$.ajax({
url: "{{ path('takeRdv') }}",
method: 'POST',
data: {},
success: function(data) {
$("#calendarModal").modal('hide');
$("#calendarModal").on('hidden.bs.modal', function (e) {
$('#calendar').fullCalendar('refetchEvents');
});
},
error: function(XMLHttpRequest, textStatus, errorThrown)
{
alert('Error: ' + errorThrown);
}
});
}
else if (nom.value == "")
{
alert('Veuillez renseigner le Nom');
return false;
}
else if (prenom.value == "")
{
alert('Veuillez renseigner le prénom');
return false;
}
else if (email.value == "")
{
alert("Veuillez renseigner l'adresse mail");
return false;
}
});
});
Other ajax functions work just fine, I made them after trying to take an appointment on an availability. When I implemented FosJsRouting, I thought it would be easier to try to make my takeRdvs action work. But the truth is, I don't know how to do it since it's a different action from the others and I am lost now :'(
My modal showing up when a event is clicked (got cut in several part sorry could not fix it):
×
close
<div class="form-group">
<div class="col-sm-12">
<h4 id="modalTitle" class="modal-title modify"></h4>
</div>
</div>
<div class="col-sm-4 form-group">
<label for="motif">
Motif de la consultation :
</label>
<select class="form-control" id="motif" data-placeholder="Choisissez un motif" style="width: 100%;" name="motif"> {# multiple data-max-options="1" #}
<option value="238"> Bilan de la vue</option>
<option value="Visite de controle"> Visite de contrôle</option>
<option value="Chirurgie réfractive"> Chirurgie réfractive</option>
<option value="Rééducation visuelle"> Rééducation visuelle</option>
<option value="Urgences"> Urgences</option>
</select>
</div>
<div class="form-group create">
<div class="col-sm-2">
<label class="control-label" for="civilite">Civilité</label>
<select class="custom-select" id="civilite" name="civilite">
<option value="Mme">Mme</option>
<option value="M">M.</option>
</select>
</div>
<div class="col-sm-5">
<label class="control-label" for="inputNom">Nom</label>
<input name="inputNom" type="text" class="form-control" id="inputNom" placeholder="Doe" required >
</div>
</div>
<div class="form-group">
<div class="col-sm-5 create">
<label class="control-label" for="inputPrenom">Prénom</label>
<input name="inputPrenom" type="text" class="form-control" id="inputPrenom" placeholder="Jane" required >
</div>
</div>
<div class="form-group">
<div class="col-sm-6">
<label class="control-label" for="email">Email</label>
<input name="email" type="email" class="form-control" id="email" placeholder="jane.doe#example.com" required >
</div>
</div>
{# fin de la condition #}
<div class="form-group">
<div class="col-sm-6">
<label class="control-label" for="naissance">Date de naissance</label>
<input name="birth" type="text" class="form-control" id="naissance" placeholder="01-01-2001" required>
</div>
<div class="col-sm-6">
<label class="control-label" for="tel">Mobile</label>
<input name="tel" type="tel" class="form-control" id="tel" placeholder="0607080910" required>
</div>
</div>
<div class="form-group">
<div class="col-sm-6">
<label class="control-label" for="telFixe">Téléphone fixe</label>
<input name="telFixe" type="tel" class="form-control" id="telFixe" placeholder="0101010101">
</div>
</div>
<div class="form-group">
<div class="col-sm-5">
<label class="control-label" for="adresse">Adresse</label>
<input name="adresse" type="text" class="form-control" id="adresse" placeholder="1 Bd de Strasbourg 83000 Toulon" required>
</div>
</div>
<div class="form-group">
<div class="col-sm-3">
<label class="control-label" for="cp">Code postal</label>
<input name="cp" type="text" class="form-control" id="cp" placeholder="83000" required>
</div>
</div>
<div class="form-group">
<div class="form-group">
<div class="col-sm-4">
<label class="control-label" for="ville">Ville</label>
<input name="ville" type="text" class="form-control" id="ville" placeholder="Toulon" required>
</div>
</div>
</div>
<div class="form-group">
<div class="form-group">
<div class="col-sm-4">
<label class="control-label" for="pays">Pays</label>
<input name="pays" type="text" class="form-control" id="pays" placeholder="France" required>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-6">
<label class="control-label" for="medecin_traitant">Médecin traitant</label>
<input name="medecin_traitant" type="text" class="form-control" id="medecin_traitant" placeholder="Dr Bicharzon" required>
</div>
</div>
<div class="form-group">
<div class="col-sm-6">
<label class="control-label" for="ame">
Bénéficiare de l'AME ?
</label>
<select class="form-control" name="ame" title="ame" id="ame" required>
<option value="oui">Oui</option>
<option value="non">Non</option>
</select>
</div>
</div>
<div class="form-group">
<div class="col-sm-6">
<label class="control-label" for="cmu">
Bénéficiare de la CMU ?
</label>
<select class="form-control" name="cmu" title="cmu" id="cmu" required>
<option value="oui">Oui</option>
<option value="non">Non</option>
</select>
</div>
</div>
<input title="heureDispo" class="visually-hidden form-control" name="heureDispo" type="text" id="heureDispo">
<div class="form-group boutonsModale col-sm-6">
<button type="button" class="btn btn-default btn-danger" data-dismiss="modal">Annuler</button>
<button type="submit" class="btn btn-primary" id="monBouton">Enregistrer</button>
</div>
</form>
</div>
{#{% endfor %}#}
<div class="modal-footer paddingTop">
{#<button type="button" class="btn btn-default btn-danger" data-dismiss="modal">Annuler</button>#}
{#<input type="submit" class="btn btn-primary">Enregistrer</input>#}
{#<button type="button" class="btn btn-default" data-dismiss="modal">Fermer</button>#}
</div>
</div>
</div>
</div>
</div>
Routing.yml :
Take RDV
take_rdv:
path: /prise-rdv
defaults: {_controller: RdvProBundle:Default:takeRdv}
methods: [POST]
options:
expose: true
I don't know how to change the route if I need to... + I would like the route no to show like the other routes I created but as it's coded now, it's shown...
I am junior junior as dev so I a sorry if my code is not clean :s
Thank you in advance for all the help you will provide.
It is huge. I'm not sure about your problem(s?) but if I understand :
First problem :
ajax is not working since events do not reload
If your #button is replaced in your page after your first call, the attached event is destroyed. Change your listener :
$("#monBouton").click(function(){
by
$('body').on('click', '#monBouton', function () { will solve the problem.
Second problem :
If I put if ($request->isXmlHttpRequest()), the controller goes directly to "else"
I suggest to pass $request as argument of your action and just put your condition within an if statement :
public function takeRdvAction(Request $request)
{
if ($request->isXmlHttpRequest()) {
[...]
}
}
Thirdly :
To use FosJsRouting, you exposed your route in your yaml. That's good. To use it in javascript, you have to include the given script in your base.html.twig and use Routing.generate just as defined in the doc :
$.ajax({
url: Routing.generate('take_rdv', {/* $(yourform).serialize() ?*/}),
method: 'POST',
data: {},
success: function(data) {
$("#calendarModal").modal('hide');
$("#calendarModal").on('hidden.bs.modal', function (e) {
$('#calendar').fullCalendar('refetchEvents');
});
},
error: function(XMLHttpRequest, textStatus, errorThrown)
{
alert('Error: ' + errorThrown);
}
});
Update
With my suggestions, you've to change how you use $request in your action :
$myArray = $request->request->all();
$civilite=$myArray['civilite'];
[...and so on...]
Bonus : Symfony is a powerfull framework. I suggest you to learn about using this framework and especially, in your case, about Forms
enjoy :)
UPDATE 2
if ($request->isXmlHttpRequest()) { is never true cause you are not doing an ajax call. I just see that, but your button is of type submit then, your browser send a basic HTTP request.
Add this to your js code :
$('body').on('click', '#monBouton', function (event) {
event.preventDefault();
[...$.ajax blablabla]
});
This question already has answers here:
ng-model for `<input type="file"/>` (with directive DEMO)
(13 answers)
Closed 4 years ago.
Guyz i have an issue with my code i don't know why when i tried to get file from <input ng-model="form.userfile" id="itemImage" name="userfile" type="file">
that code will not give me the values.
my code:
HTML:
<div class="panel panel-default">
<div class="panel-body">
<form id="form" accept-charset="utf-8" ng-submit="sendmessage()">
<textarea ng-model="form.message" name="message"
onkeypress="process(event, this)"
id="text" class="form-control send-message" rows="3"
placeholder="Write a reply...">
</textarea>
</div>
<span class="col-lg-3 btn btn-file send-message-btn">
<i class="glyphicon glyphicon-paperclip"></i>Add Files
<input ng-model="form.userfile" id="itemImage"
name="userfile" type="file">
</span>
<button ng-click="sendmessage()" id="send"
class="col-lg-4 text-right btn send-message-btn pull-right"
type="button" role="button">
<i class="fa fa-plus"></i> Send Message
</button>
<div id="dvPreview" class="text-center"></div>
</form>
</div>
Angular:
$scope.sendmessage = function (){
var formData = $scope.form;
var friendid = $scope.friendid;
var req =
{
type: 'POST',
enctype: 'multipart/form-data',
data:formData,
url: "<?php echo base_url() ?>User/sendmessages/"+friendid,
headers: {
'Content-Type': 'application/json'
},
};
$http(req).then(function (response) {
$('#text').val('');
console.log(response)
}, function (response) {
});
};
here is what i have done before please help.
ngModel directive is not usable on file input.
If you don't care about being in debugInfoEnabled on prod, you can pass it true like this in your app.js.
$compileProvider.debugInfoEnabled(true);
You then will be able to access your scope from your html.
In you file input just add :
onchange="angular.element(this).scope().yourChangeFunction(this)
You can access your file in your js code with :
scope.yourChangeFunction = function(element){scope.file=element.files[0];}