I'm using Symfony to create a form. Between the form label and the widget where the user enters data I have a button that when pressed displays text prompts to help guide the user. This works fine and when the user clicks on the button it correctly displays the text, however it also displays the error message for the field, saying that the field cannot be blank. I don't need the error displayed until the form is submitted so it seems to be displaying it too early. Many thanks for any suggestions.
Here is the relevant part of the template:
{{ form_start(form) }}
{{ form_label(form.field1, 'My Custom Task Label') }}
<button onclick="myFunction()">Click to display prompts</button>
<div id="myDIV" style = "display:none">
This is a helpful prompt.
</div>
{{ form_widget(form.field1) }}
<script>
function myFunction() {
var x = document.getElementById("myDIV");
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}
</script>
{{ form_end(form) }}
buttons by default are submit buttons. your button doesn't indicate any type, so it's of submit type. solution: set type to "button":
<button type="button" onclick="myFunction()">Click to display prompts</button>
otherwise it's sending the form / trying to send the form, obviously catching the errors / required fields, hence displaying an error.
Related
Sorry if this sounds very obvious but I am new to Ionic 2 / Angular 2. Upon submitting a form, I need to update the button text and click event, ie:
first click on button = submit form + update button text to "Next"
second click on button = trigger goToNext()
I managed to update the button text but not update the click event (to goToNext() ).
.html
<form (ngSubmit)="logForm(i)">
<ion-item>
<ion-input type="text" [(ngModel)]="form.userinput[i]" name="userinput[i]"></ion-input>
</ion-item>
<button ion-button block type="submit" (click)="setNext($event.target, 'Next')">Check</button>
</form>
.ts
setNext(element, text){
element.textContent = 'Next';
}
goToNext(){
// go to Next Page
}
Ideally you change your design a bit to keep a variable that stores state of your 'Controller'. e.g. stores PageNumber. and then behave differently based on what page you are on. So I suggest change design a bit.
But to answer your current question without major change, you can bind the handler dynamically the same way you bind the text. then in the first handler, change the handler for the next click. the default values for handler and text will decide which one is going the be used initially
handler = this.setNext;
text = 'first text';
setNext(){
alert('handler1 called');
this.handler = this.goToNext;
this.text = 'other text';
}
goToNext(){
alert('second called');
// go to Next Page
}
and in your html you go like
<button ion-button block type="submit" (click)="handler()">{{text}}</button>
You can use n00b answer or something like this:
in html file:
<button ion-button block type="submit" (click)="check()">{{btn_txt}}</button>
in ts file:
btn_txt = 'Check';
check() {
if (this.btn_txt == 'Check') {
//do some logic
this.btn_txt = 'Next';
} else {
console.log('go to next page');
}
}
I have a form, which I'm validating using JQuery Validation plugin. Validation works file until I add a Bootstrap 3 popover to the text field with name "taskName" (the one being validated) (please see below) . When I add the popover to this text field, error messages are repeatedly displayed every time the validation gets triggered. Please see the code excerpts and screenshots below.
I've been trying to figure out what is happening, with no success so far. Any help will be greatly appreciated. Thanks in advance!
HTLM Excerpt
The popover content
<div id="namePopoverContent" class="hide">
<ul>
<li><small>Valid characters: [a-zA-Z0-9\-_\s].</small></li>
<li><small>Required at least 3 characters.</small></li>
</ul>
</div>
The form
<form class="form-horizontal" role="form" method="post" action="" id="aForm">
<div class="form-group has-feedback">
<label for="taskName" class="col-md-1 control-label">Name</label>
<div class="col-md-7">
<input type="text" class="form-control taskNameValidation" id="taskName" name="taskName" placeholder="..." required autocomplete="off" data-toggle="popover">
<span class="form-control-feedback glyphicon" aria-hidden="true"></span>
</div>
</div>
...
</form>
JQuery Validate plugin setup
$(function() {
//Overwriting a few defaults
$.validator.setDefaults({
errorElement: 'span',
errorClass: 'text-danger',
ignore: ':hidden:not(.chosen-select)',
errorPlacement: function (error, element) {
if (element.is('select'))
error.insertAfter(element.siblings(".chosen-container"));
else
error.insertAfter(element);
}
});
//rules and messages objects
$("#aForm").validate({
highlight: function(element) {
$(element).closest('.form-group').removeClass('has-success').addClass('has-error');
$(element).parent().find('.form-control-feedback').removeClass('glyphicon-ok').addClass('glyphicon-remove');
},
success: function(element) {
$(element).closest('.form-group').removeClass('has-error').addClass('has-success');
$(element).parent().find('.form-control-feedback').removeClass('glyphicon-remove').addClass('glyphicon-ok');
}
});
$('.taskNameValidation').each(function() {
$(this).rules('add', {
required: true,
alphanumeric: true,
messages: {
required: "Provide a space-separated name."
}
});
});
});
Bootstrap 3 popover setup
$('[data-toggle="popover"]').popover({
trigger: "focus hover",
container: "body",
html: true,
title: "Name Tips",
content: function() { return $('#namePopoverContent').html();}
});
The screenshots
First Edit
It seems I did not make my question clear, so here it goes my first edit.
I'm not using the popover to display the error messages of the validation. The error messages are inserted after each of the fields that fail validation, which is precisely what I want. Hence, this question does not seem to be a duplicate of any other question previously asked.
Regarding the popover, I just want to add an informative popover that gets displayed whenever the user either clicks the text field "taskName" or hovers the mouse over it. Its role is completely independent of the validation.
The question is, then, why adding the (independent) popover is making the validation plugin misbehave, as shown in the screenshots.
I had the very same issue a few days ago and the only solution I found was to use 'label' as my errorElement:.
Change the line errorElement: 'span' to errorElement: 'label' or simply removing the entire line will temporarily fix the issue. ('label' is the default. )
I am not completely sure what the JQ validate + BS popover conflict is, but I will continue to debug.
After some debugging I think I found the issue.
Both jQuery validate and bootstrap 3 popovers are using the aria-describedby attribute. However, the popover code is overwriting the value written by jQuery validate into that attribute.
Example: You have a form input with an id = "name", jQuery validate adds an aria-describedby = "name-error" attribute to the input and creates an error message element with id = "name-error" when that input is invalid.
using errorElement:'label' or omitting this line works because on line 825 of jquery.validate.js, label is hard-coded as a default error element selector.
There are two ways to fix this issue:
Replace all aria-describedby attributes with another attribute name like data-describedby. There are 4 references in jquery.validate.js. Tested.
or
Add the following code after line 825 in jquery.validate.js. Tested.
if ( this.settings.errorElement != 'label' ) {
selector = selector + ", #" + name.replace( /\s+/g, ", #" ) + '-error';
}
I will also inform the jQuery validate developers.
The success option should only be used when you need to show the error label element on a "valid" element, not for toggling the classes.
You should use unhighlight to "undo" whatever was done by highlight.
highlight: function(element) {
$(element).closest('.form-group').removeClass('has-success').addClass('has-error');
$(element).parent().find('.form-control-feedback').removeClass('glyphicon-ok').addClass('glyphicon-remove');
},
unhighlight: function(element) {
$(element).closest('.form-group').removeClass('has-error').addClass('has-success');
$(element).parent().find('.form-control-feedback').removeClass('glyphicon-remove').addClass('glyphicon-ok');
}
(The success option could also be used in conjunction with the errorPlacement option to show/hide tooltips or popovers, just not to do the styling, which is best left to highlight and unhighlight.)
Also, I recommend letting the Validate plugin create/show/hide the error label element, rather than putting it the markup yourself. Otherwise, the plugin will create its own and ignore the one you've created.
In case you were unaware, you cannot use the alphanumeric rule without including the additional-methods.js file.
I have a form which allows the user to delete some data from a database.
I want to have a bit of confirmation to prevent accidental deletes. I want to do the following:
When submit is pressed, alert pops up with "Are you sure?"
If user hits "yes" then run the script
If user hits "no" then don't submit the script.
How can this be done?
I have added the onSubmit alert but it does not show anything, and it still submits the form. How can I delay the submission of the form to only occur when the user selects "yes" from the alert?
<form
method="POST"
action="actions/remove-daily-recipient.php"
onSubmit="alert('Are you sure you wish to delete?');"
>
...
</form>
Instead of alert, you have to use confirm and return in your form, for an example:
<form
method="post"
onSubmit="return confirm('Are you sure you wish to delete?');">
...
</form>
on your form can you try with a js function like:
<form onsubmit="return submitResult();">
and on your function have something like?
function submitResult() {
if ( confirm("Are you sure you wish to delete?") == false ) {
return false ;
} else {
return true ;
}
}
I think this will be a good start.
Stop the default behaviour, ask for confirmation and then submit the form:
var form1 = document.getElementById('form1');
form1.onsubmit = function(e){
var form = this;
e.preventDefault();
if(confirm("Are you sure you wish to delete?"))
form.submit();
}
JS Fiddle: http://jsfiddle.net/dq50e963/
I have a form, and I'm navigating only with TAB. Tab order should be input > select > button, but because of the ng-disable on the SUBMIT, on certain browsers the TAB out of the select will kick you somewhere else.
HTML
<div ng-app="myApp">
<div ng-controller="FirstCtrl">
<form name="myForm" ng-submit="submit()" novalidate>
First Name: <input type="text" ng-model="Data.FirstName" required><br>
Last Name: <select ng-model="Data.LastName" required>
<option value="Bigglesworth">Bigglesworth</option>
<option value="Burgermeister">Burgermeister</option>
</select><br>
<input type="submit" value="Submit" ng-disabled="myForm.$invalid" />
</form>
</div>
</div>
JS
var myApp = angular.module('myApp', []);
myApp.factory('Data', function(){
return {
FirstName: '',
LastName: ''
};
});
myApp.controller('FirstCtrl', function( $scope, Data ){
$scope.Data = Data;
$scope.submit = function() {
console.log('you just submitted, foolio');
}
});
JsFiddle here.
On Mac FF the final tab kicks you to the address bar before enabling the submit button. Mac Chrome works as you'd expect, focusing on the submit button after final tab. I know Windows is janky, but don't have exact specs to post.
Thoughts? How can I do this in a fool-proof fashion?
EDIT
I've selected #David B.'s answer as it's the best Angular solution. I ended up using a somewhat hidden element right after the the submit button so the focus would stay in the same general area. Lame and hacky, I know, but for a tight deadline it worked.
<h3><button class="fakebtn_hack">Confirmation</button></h3>
<style>.fakebtn_hack {background:none; border:none; color: #FF6319; cursor: default; font-size: 1em; padding: 0;}</style>
This happens because Firefox doesn't send a change event on key-driven changes of the select. Angular doesn't see the change until the tab is hit, so the submit button isn't enabled until after the tab has been processed by the browser (and focus sent to some other element, e.g., the address bar). The W3C standard suggests not sending the event until the control loses focus, although Chrome sends one for any change and Firefox does if the change was mouse-driven.
See the angularjs issue tracker for more: https://github.com/angular/angular.js/issues/4216
As suggested in the issue tracker, solve it by manually issuing the change event via the following select directive (http://jsfiddle.net/j5ZzE/):
myApp.directive("select", function () {
return {
restrict: "E",
require: "?ngModel",
scope: false,
link: function (scope, element, attrs, ngModel) {
if (!ngModel) {
return;
}
element.bind("keyup", function () {
element.trigger("change");
})
}
}
})
You'll need JQuery loaded before AngularJS to have the trigger function available on the element object.
Manually include an empty option (<option value=""></option>) in your select or the first option will be auto-selected when the control receives focus.
Unlike the default behavior, this empty option will not disappear after selecting a real option. I suppose you could remove the empty option by declaring all the options via ng-options or ng-repeat and then removing the empty one from the bound scope once a real option has been selected, but I've never tried it.
I have user entity and activity. User has many activities. I've created a form -> list of users and theris activitis (checkboxes).
User, ACT1, ACT2, ACT3
Jhon---x--------0--------0
x- checkbox is checked
0- checkbox is unchecked
Everythings works fine when I have data like above and press save button, but when I want to uncheck all activities:
User, ACT1, ACT2, ACT3
Jhon---0--------0--------0
(I press save button) The activietes are not updated. $_POST Is empty and I think there is no bindig in controller.
Single checkbox is generated by form_widget in this way:
input type="checkbox" name="users_activities[users][0][activities][1][enabled]" value="1" checked="checked"
Any idea how to solve it?
VIEW:
{%for actv in user.activities %}
{{ form_widget(actv.enabled) }}
{%endfor%}
CONTROLLER:
$form->bindRequest($this->getRequest());
foreach ($form->get('users') as $userF) {
foreach ($userF->get('activities') as $actF) {
$act = $actF->getData();
$em->persist($act);
}
}
$em->flush();