I have an interesting task (I think). I need to have an input field share validation. The desired outcome would be both fields are "technically" required. However, if a user types in their email address then both fields are now valid and vice versa if they fill out a phone number. Here is my code below.
HTML
<div class="col-12 col-md-6 col-lg-3">
<label>Phone Number</label>
<div class="input-group">
<input
class="form-control"
type="text"
ngModel
#contactPhone="ngModel"
name="phone"
minlength="10"
[required]="contactEmail.invalid"
(change)="checkValidation(name)"
/>
</div>
<div class="col-12 col-md-6 col-lg-3">
<div class="form-group">
<label>Email</label>
<input
class="form-control"
type="text"
ngModel
[ngClass]="setClasses(contactEmail, form)"
#contactEmail="ngModel"
name="email"
maxlength="100"
pattern="\b[\w.%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b"
[required]="contactPhone.invalid"
(change)="checkValidation(name)"
/>
</div>
Relevant TS
checkValidation(name) {
if (
this.form.controls[name]?.controls?.email?.value ||
this.form.controls[name]?.controls?.phone?.value
) {
this.eitherFieldRequired = false;
}
}
You can do this in either one of two ways:
this.myFormGroup({ ... }, formValue => this.myValidator)
this.myFormGroup
.get(‘myControl’)
.valueChanges
.pipe(
takeUntil(this.destroyed), // handle the unsubscription
tap(value => {
if (value) {
this.myFormGroup
.get(‘myControl’)
.setValidators([ ... ])
} else {
// unset validators
}
}),
).subscribe()
Let me know if you need more guidance.
Related
I have a form where all input fields are made reactive with an array of values in a Vuex store.
Here is the form :
<form #submit="submitForm">
<div class="mb-3">
<label for="nom" class="form-label">Nom:</label>
<input :value="nom" #input="onInputChange" type="text" class="form-control" id="nom" placeholder="Nom"
name="NOM">
<span style="color: red">{{ fieldErrors.nom }}</span>
</div>
<div class="mb-3">
<label for="prenom" class="form-label">Prénom:</label>
<input :value="prenom" #input="onInputChange" type="text" class="form-control" id="prenom"
placeholder="Prénom" name="PRENOM">
<span style="color: red">{{ fieldErrors.prenom }}</span>
</div>
<div class="mb-3 mt-3">
<label for="email" class="form-label">Courriel:</label>
<input :value="email" #input="onInputChange" type="text" class="form-control" id="email"
placeholder="Email" name="EMAIL" />
<span style="color: red">{{ fieldErrors.email }}</span>
</div>
<div class="mb-3 mt-3">
<label for="phone" class="form-label">Téléphone:</label>
<input :value="phone" #input="onInputChange" type="text" class="form-control" id="phone"
placeholder="Numéro de téléphone" name="PHONE" />
<span style="color: red">{{ fieldErrors.phone }}</span>
</div>
<div class="mb-3 mt-3">
<label for="postalCode" class="form-label">Code postal:</label>
<input :value="postalCode" #input="onInputChange" type="text" class="form-control" id="postalCode"
placeholder="Code Postal" name="POSTALCODE" />
<span style="color: red">{{ fieldErrors.postalCode }}</span>
</div>
<div class="mb-3 mt-3">
<input :checked="termsAndConditions" #change="onInputChange" type="checkbox" class="me-1" id="chkTerms"
placeholder="TERMS AND CONDITIONS" name="TERMS_AND_CONDITIONS" />
<label for="chkTerms" class="form-label">I accept the terms and conditions:</label>
<span style="color: red">{{ fieldErrors.termsAndConditions }}</span>
</div>
</form>
All inputs share the same function (onInputChange) when there is a change to the value
Here are the computed properties used for the form as well as the function mentionned above:
computed: {
...mapGetters(["nom", "prenom", "email", "phone", "postalCode", "termsAndConditions", "items"]),
},
methods: {
onInputChange(evt) {
const element = evt.target;
const value =
element.name === "TERMS_AND_CONDITIONS"
? element.checked
: element.value;
store.commit('UPDATE_'+element.name, value);
},
As you can see, whenever there is a change in inputs, the appropriate mutation will be called from the store.
Here is the store and all the relevant mutations:
const state = {
fields: {
nom: '',
prenom: '',
email: '',
termsAndConditions: false,
phone:'',
postalCode:'',
},
}
const mutations = {
UPDATE_NOM(state, payload) {
state.fields.nom = payload;
},
UPDATE_PRENOM(state, payload) {
state.fields.prenom = payload;
},
UPDATE_EMAIL(state, payload) {
state.fields.email = payload;
},
UPDATE_PHONE(state, payload){
state.fields.phone = payload
},
UPDATE_POSTALCODE(state, payload){
state.fields.postalCode = payload
},
UPDATE_TERMS_AND_CONDITIONS(state, payload) {
state.fields.termsAndConditions = payload;
},
}
The problem is: Whenever there is a change in state on the checkbox, the values in the textboxes nom, phone and postalCode are cleared. Their corresponding values in the store stay the same though and the textboxes prenom and email don't have their values cleared at all.
What is this behavior and why is it happenning?
Note: For reproduction sake, I am using bootstrap 5 so you might want to remove the classes if they cause a problem
All your <input> elements bind value to a different store getter, not the actual state. You didn't post what your getters are and the error is likely there, but you say your state remains correct when you toggle the checkbox, so just bind your <input> elements to the actual state, i.e. use mapState instead of mapGetters. Even better, two-way bind your state with v-model on your <input> instead of the combination of :value + #input:
<div class="mb-3 mt-3">
<label for="postalCode" class="form-label">Code postal:</label>
<input
v-model="$store.state.fields.postalCode"
type="text"
class="form-control"
id="postalCode"
placeholder="Code Postal"
name="POSTALCODE"
/>
</div>
<span style="color: red">{{ fieldErrors.postalCode }}</span>
<div class="mb-3 mt-3">
<input
v-model="$store.state.fields.termsAndConditions"
type="checkbox"
class="me-1"
id="chkTerms"
placeholder="TERMS AND CONDITIONS"
name="TERMS_AND_CONDITIONS"
/>
<label for="chkTerms" class="form-label"
>I accept the terms and conditions:</label
>
<span style="color: red">{{ fieldErrors.termsAndConditions}}</span>
</div>
no onInputChange(), mapState, or even mutations needed
Did you console.log(element), what do you get there?
I am not sure but I think you need to pass the event to your function call
#input="onInputChange"($event)
I am using the owl-date-time module in my application to get date-time parameters in two fields. However, I am getting the value in a list with an additional null value in the payload.
Also, I wish to convert the value to epoch time to meet the API requirements.
In HTML Component:
<div class="form-group row">
<label class="col-md-3 col-form-label text-right">
Start Time
<span class="colorRed">*</span>
</label>
<div class="col-lg-5 col-sm-11">
<input type="text" id="start_time" style="height: 36px;"
class="form-control" [selectMode]="'rangeFrom'" name="start_time"
placeholder="Start Time" [(ngModel)]="startTime"
[owlDateTimeTrigger]="dt1" [owlDateTime]="dt1"
(change)="getTime(startTime,dt1)" [max]="maxFrom"
autocomplete="off" required>
<owl-date-time #dt1></owl-date-time>
</div>
<!---->
</div>
<div class="form-group row">
<label class="col-md-3 col-form-label text-right">
Stop Time
<span class="colorRed">*</span>
</label>
<div class="col-lg-5 col-sm-11">
<input type="text" id="stop_time" style="height: 36px;"
class="form-control" [selectMode]="'rangeTo'" name="stop_time"
placeholder="End Time" [(ngModel)]="stopTime"
[owlDateTimeTrigger]="dt2" [owlDateTime]="dt2"
(change)="getTime(stopTime,dt2)" [min]="minTo"
autocomplete="off" required>
<owl-date-time #dt2></owl-date-time>
</div>
</div>
</div>
In Typescript, I am calling this function to do the conversion. But I do not think that the function is getting called as I am unable to get any console logs.
TS Code
getTime(t, selectMode) {
console.log("Hello Chuckles");
let tempRangeFrom, tempRangeTo;
t.forEach(element => {
if (typeof (element) != 'undefined' && element != null) {
if (element[1] != null) {
console.log("FROM!##$%^&*()");
tempRangeFrom = element.getTime(); // Date To TimeStamp
this.minTo = new Date(tempRangeFrom); // TimeStamp to Date
this.minTo.toGMTString();
} else {
tempRangeTo = element.getTime();
this.maxFrom = new Date(tempRangeTo);
this.maxFrom.toGMTString();
}
}
});
}
Screenshot for date-picker:
Payload:
You can simply do this:
const date = new Date()
console.log(new Date(date).getTime())
You can also check this link if the above code doesn't help.
I'm trying to access and use the data from my service and having some issues. I am able to see the data returned just fine in the console from my console.log(data); from the method below:
public getCustomerData() {
this.Service.getCustomers().subscribe((data) => {
console.log(data);
this.customers = data.value;
console.log(this.customers);
var i:number;
for(i = 0; i < this.customers.length; i++ ){
if(this.customers[i].CityName == null || this.customers[i].StateName == null || this.customers[i].ZipCode == null || this.customers[i].Address1 == null){
this.customers[i].Address1 = "";
this.customers[i].CityName = "San Diego";
this.customers[i].StateName = "California";
this.customers[i].ZipCode = "12345";
}
}
})
}
Where I am running into issues is the next line this.customers = data.value;, I am recieving the error Property 'value' does not exist on type 'Customer[]'.
Here is how my data is returned:
Service method:
public getCustomers()
{
let url = "https://rss-staging.carefusion.com/api/odata/Facilities";
const params = new HttpHeaders()
.set('X-Atlas-SecurityKey', '75162FD1-A4E8-40AB-A62A-823932CEAD1F')
return this.http.get<Customer[]>(url, {headers: params})
}
HTML Table:
<div class="row pb-2">
<div class="col-lg-4">
<div class="form-group">
<label for="input1">Name</label>
<input type="text" placeholder="Customer Name" class="form-control" id="input1"
aria-describedby="Text field" name="name" [(ngModel)]="fields.Name"
(ngModelChange)="updateFilters()" />
</div>
</div>
<div class="col-lg-5">
<div class="form-group">
<label for="input1">Address</label>
<input type="text" placeholder="Customer Address" class="form-control" id="input1"
aria-describedby="Text field" name="address" [(ngModel)]="fields.Address1"
(ngModelChange)="updateFilters()" />
</div>
</div>
</div>
<div class="row pb-2">
<div class="col-lg-3">
<div class="form-group">
<label for="input1">City</label>
<input type="text" placeholder="City" class="form-control" id="input1" aria-describedby="Text field"
name="city" [(ngModel)]="fields.CityName" (ngModelChange)="updateFilters()" />
</div>
</div>
<div class="col-lg-3">
<div class="form-group">
<label for="input1">State</label>
<input type="text" placeholder="State" class="form-control" id="input1" aria-describedby="Text field"
name="name" [(ngModel)]="fields.StateName" (ngModelChange)="updateFilters()" />
</div>
</div>
<div class="col-lg-3">
<div class="form-group">
<label for="input1">Zip Code</label>
<input type="text" placeholder="123456" class="form-control" id="input1" aria-describedby="Text field"
name="name" [(ngModel)]="fields.ZipCode" (ngModelChange)="updateFilters()" />
</div>
</div>
</div>
How can I fix this?
From the code, I can see that you have typecasted the result of the function getCustomers() to customers[]
return this.http.get<Customer[]>(url, {headers: params})
Basically you are returning an array of customers from the http call.
To return correct value, pipe the results and map
import { map } from 'rxjs/operators'
return this.http.get<any>(url, {headers: params}).pipe(
map(data => data.value as Customer[])
)
Your method getCustomers() from the service already return a list of customers, and a list doesn't have a property called value.
You only have to do this, and should works.
this.customers = data;
My view:
<div class="col-md-3">
<div class="form-group">
<label>Employee Id</label>
<input type="text" class="form-control" placeholder="Enter employee id" name="empid">
</div>
</div>
<div class="col-md-3">
<div class="form-group">
<label>Employee Name</label>
<input type="text" class="form-control" placeholder="Enter employee name" name="empname">
</div>
</div>
<div class="col-md-3">
<div class="form-group">
<label>Order Number</label>
<input type="number" class="form-control" placeholder="Enter order number" name="ordernumber" value="<?php echo $order_number;?>">
</div></div>
<div class="col-md-3">
<div class="form-group">
<label></label>
<a onclick="myFunctionfirst()" class="form-control">Proceed to order Create</a>
</div></div>
Once you click on 'proceed to order create' the second row is created. I want this to happen only when the first 3 fields in first row are filled. Please suggest on this
And this is my controller:
public function index()
{
$empid = $_POST['empid'];
If ($empid == ""){
$this->load->model('invoice_model');
$data['stat']= $this->invoice_model->get_stationary();
$data['order_numbers']= $this->invoice_model->get_countnumber();
$data['order_number']= $data['order_numbers'][0]->count+1;
$data['page']='invoice/invoice_view';
$this->load->view("template",$data);
}
}
And it's throwing an error undefined index empid
Welcome to stackoverflow. what you can do is save the input as a variable Store input from a text field in a PHP variable
this method is however a bit unsafe. to secure the input you can use https://www.w3schools.com/php/func_string_htmlspecialchars.asp
https://www.php.net/manual/en/function.htmlspecialchars.php
and once you have the variables just simply check if the variable is empty or not
public function index()
{
$firstname = $_POST['firstname'];
If ($firstname != ""){
$this->load->model('invoice_model');
$data['stat']= $this->invoice_model->get_stationary();
$data['order_numbers']= $this->invoice_model->get_countnumber();
$data['order_number']= $data['order_numbers'][0]->count+1;
$data['page']='invoice/invoice_view';
$this->load->view("template",$data);
}
}
$_POST is how the data is being send. here they explain the difference between POST and GET https://www.quora.com/What-is-the-difference-between-PHPs-get-method-post-method
'firstname' is the name of the input. in your case its <input type="text" class="form-control" placeholder="Enter employee id" name="empid"> so it should be $_POST['empid']
the data is being send with the submit button. instead of using the <a> tag you should use the <button type="submit"> tag also, wrap the inputs in a form tag.
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]
});