Using jquery validation 1.17.0 with Bootstrap 4.0.0 beta - jquery-validate

I'm working on a project and noticed that bootstrap 4.0.0 beta does not use glyphicons anymore, so how could I achieve the same effect as the 2nd example "Using feedback icons" shown in the link here JQuery-validation and Bootstrap using font-awesome 4.7.0? I've included the output of the validation below for better clarity:
Currently this is what I've got:
HTML
<div class="form-group">
<label class="col-sm-4 control-label df-label" for="first_name">* First name:</label>
<div class="col-sm-5">
<input type="text" class="form-control" id="first_name" name="first_name" placeholder="First Name" />
</div>
</div>
<div class="form-group">
<label class="col-sm-5 control-label df-label" for="last_name">* Last name:</label>
<div class="col-sm-5">
<input type="text" class="form-control" id="last_name" name="last_name" placeholder="Last Name" />
</div>
</div>
....
<div class="form-group">
<div class="col-sm-12">
<button type="submit" class="btn btn-outline-success my-2 my-sm-0" id="send" name="send" value="Send">Send</button>
</div>
</div>
CSS
.has-danger .control-label,
.has-danger .help-block,
.has-danger .form-control-feedback {
color: #d9534f;
}
jQuery
$( "#contact-form" ).validate({
rules: {
first_name: "required"
,last_name: "required"
,email: {
required: true
,email: true
}
,message: {
required: true
,minlength: 10
}
}
,messages: {
first_name: "Please enter your First name"
,last_name: "Please enter your Last name"
,email: "Please enter a valid Email address"
,message: {
required: "Please enter a Message"
,minlength: "Your message must consist of at least 10 characters"
}
}
,meta: "validate"
,errorElement: "em",
errorPlacement: function ( error, element ) {
// Add the `help-block` class to the error element
error.addClass( "help-block" );
// Add `has-feedback` class to the parent div.form-group
// in order to add icons to inputs
element.parents( ".col-sm-5" ).addClass( "has-feedback" );
element.parents( ".col-sm-8" ).addClass( "has-feedback" );
if ( element.prop( "type" ) === "checkbox" ) {
error.insertAfter( element.parent( "label" ) );
} else {
error.insertAfter( element );
}
// Add the span element, if doesn't exists, and apply the icon classes to it.
if ( !element.next( "span" )[ 0 ] ) {
$( "<span class='fa fa-times form-control-feedback'></span>" ).insertAfter( element );
}
},
success: function ( label, element ) {
// Add the span element, if doesn't exists, and apply the icon classes to it.
if ( !$( element ).next( "span" )[ 0 ] ) {
$( "<span class='fa fa-check form-control-feedback'></span>" ).insertAfter( $( element ) );
}
},
highlight: function ( element, errorClass, validClass ) {
$( element ).parents( ".col-sm-5" ).addClass( "has-danger" ).removeClass( "has-success" );
$( element ).parents( ".col-sm-8" ).addClass( "has-danger" ).removeClass( "has-success" );
$( element ).next( "span" ).addClass( "fa-times" ).removeClass( "fa-check" );
},
unhighlight: function ( element, errorClass, validClass ) {
$( element ).parents( ".col-sm-5" ).addClass( "has-success" ).removeClass( "has-danger" );
$( element ).parents( ".col-sm-8" ).addClass( "has-success" ).removeClass( "has-danger" );
$( element ).next( "span" ).addClass( "fa-check" ).removeClass( "fa-times" );
}
});
And here is my output so far:

I'm guessing your issue is first the placement of the feedback icon and second the color of the elements? There were some big changes between the alpha and beta versions of bootstrap (and also bootstrap 3), esp. in regards to form validation.
First, to place the icons correctly you'll need to add styling which equates to what was in bootstrap 3 and no longer in bootstrap 4 beta...here's what I'm using
.fa.valid-feedback,
.fa.invalid-feedback {
position: absolute;
right: 25px;
margin-top: -50px;
z-index: 2;
display: block;
pointer-events: none;
}
.fa.valid-feedback {
margin-top: -28px;
}
The classes have changed as the beta uses the 'state' of the control which your posted code doesn't reflect, so your above code may not work. Anyway, you'll need to add 'was-validated' class to the form either in the success or highlight/unhighlight callbacks
$(element).closest('form').addClass('was-validated');
I would also recommend using the new element and classes for form control help text
errorElement: 'small',
errorClass: 'form-text invalid-feedback',

I assume you don't want to purchase Glyphicons, so you could make the switch to Font Awesome. View the source of the example that you provided and see how "glyphicon-ok" and "glyphicon-remove" are being used. The equivalent "fa-check" and "fa-times" icons look like the closest matches.
Related issues:
Glyphicons no longer supported in Bootstrap 4
how to use Glyphicons in bootstrap 4 and angular2?

Related

Laravel livewire not getting data (DateRangePicker)

I'm using laravel and livewire and I'm trying to pass over the date range's date to my function. The issue I'm having
is that I'm getting an empty string.
I'm also using https://www.daterangepicker.com/#example1 for my daterange.
Here is my code.
My index.blade.php
<div>
<form wire:submit.prevent="dateTest">
<input type="text" wire:model="date_range" id="testDateRange"/>
<button type="submit">Submit date</button>
</form>
</div>
#push('js')
<script>
$(function() {
$('#testDateRange').daterangepicker({
opens: 'left'
}, function(start, end, label) {
console.log("A new date selection was made: " + start.format('YYYY-MM-DD') + ' to ' + end.format('YYYY-MM-DD'));
});
});
</script>
#endpush
and this is my Index.php
<?php
namespace App\Http\Livewire\Products;
use Livewire\Component;
class Index extends Component
{
public $date_range = '';
public function dateTest()
{
dd($this->date_range);
}
}
*** UPDATE ***
I had to change the the date picker to be this one https://www.daterangepicker.com/#example4 so here is my new code
<form wire:submit.prevent="dateTest">
<input type="text" id="startDateTest" onchange="this.dispatchEvent(new InputEvent('input'))" wire:model="date_range" class="form-input block w-full sm:text-sm sm:leading-5">
<div id="reportrange" style="background: #fff; cursor: pointer; padding: 5px 10px; border: 1px solid #ccc; width: 100%" wire:model="startDate">
<i class="fa fa-calendar"></i>
<span></span> <i class="fa fa-caret-down"></i>
</div>
<button type="submit">Submit date</button>
</form>
<script type="text/javascript">
$(function() {
var start = moment();
var end = moment();
function cb(start, end) {
$('#reportrange span').html(start.format('MMMM D, YYYY') + ' - ' + end.format('MMMM D, YYYY'));
}
$('#reportrange').daterangepicker({
startDate: start,
endDate: end,
ranges: {
'Today': [moment(), moment()],
'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
'Last 7 Days': [moment().subtract(6, 'days'), moment()],
'Last 30 Days': [moment().subtract(29, 'days'), moment()],
'This Month': [moment().startOf('month'), moment().endOf('month')],
'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')]
}
}, function(start, end){
$('#startDateTest').val(start.format('YYYY-MM-DD'));
cb(start, end);
});
});
you need to use #this.set method to set livewire variable.
this is an example for dateTimePicker i hope you will understand how to implement it in dateRangePicker.
<div class="col-lg-6">
<input wire:model.lazy="startDate" type="text" id="startTime" class="form-control" name="startDate" readonly>
</div>
<script>
$('#startTime').datetimepicker({
format: 'd-m-Y H:i',
step: 5,
minDate:0,
onChangeDateTime: function (dp,$input) {
#this.set('startDate', $input.val());
},
});
$('#endTime').datetimepicker({
format: 'd-m-Y H:i',
step: 5,
onChangeDateTime: function (dp,$input) {
#this.set('endDate', $input.val());
},
});
</script>
in livewire component class get variables like :
$finalEndDate = Carbon::createFromFormat('d-m-Y H:i',$this->endDate);
$finalStartDate = Carbon::createFromFormat('d-m-Y H:i',$this->startDate);

Get all values of custom input inside v-for vuejs

I created a vuejs custom input that I wanted to use to dynamically display inputs by using props within the custom input. I haven't shown them here because it would be too long.
By clicking on the submit button, which is also part of the custom input, I wanna be able to get the values of each input, but for some reason, I have only been able to get the value of the last input.
What am I doing wrong?
Custom input:
<template>
<div class="form-input">
<label :label="label" :for="name" v-if="label && type !='submit' ">{{label}} <span v-if="required">*</span></label>
<a v-if="multiple" href="#" class="btn">Upload</a>
<input v-model="inputVal" :multiple="multiple" v-if="type != 'textarea' && type != 'submit'" class="form-control" :required="required" :class="classes" :type="type" :name="name" :placeholder="placeHolder">
<textarea v-model="inputVal" :multiple="multiple" v-else-if="type != 'submit'" class="form-control" :required="required" :class="classes" :type="type" :name="name" :placeholder="placeHolder"></textarea>
<button :multiple="multiple" :name="name" v-else type="submit">{{label}}</button>
</div>
</template>
<script>
export default {
name: "Input",
data () {
return {
inputVal: null
}
},
watch: {
inputVal: {
handler: function(newValue, oldValue) {
this.$emit('input', newValue);
},
deep: true,
}
}
}
</script>
Form where custom input is used:
<template>
<div class="form container">
<form v-on:submit.prevent="sendMail" method="post" class="d-flex row shadow bg-dark border-right border-dark">
<h3 class="col-12">Contact me</h3>
<Input v-model="formInput" v-for="input in inputs" v-bind:key="input.name" :label="input.label" :multiple="input.multiple" :type="input.type" :name="input.name" :class="input.classes" :required="input.required"></Input>
</form>
</div>
</template>
<script>
import Input from "../components/Input";
export default {
name: "Contact",
components: {Input},
data() {
return {
formInput: null,
}
},
methods: {
sendMail () {
console.log(this.formInput);
}
}
}
</script>
The issue I see in your code is, you are using only one variable "formInput" ( in case of Contact component ) and "inputVal" ( in case of Input component ) but you have number of input fields from where you need data right.
The simplest way to deal with these kind of cases is to create a datastructure and loop through that.
For eg.
// Contact component ( i am making it simple to make you understand the scenario )
<template>
<div class="form container">
<form v-on:submit.prevent="sendMail" method="post" class="d-flex row shadow bg-dark border-right border-dark">
<h3 class="col-12">Contact me</h3>
<!-- we are looping through our data structure and binding each inputVal to this input -->
<input v-for="(input, i) in formInputs" :key="i" v-model="input.inputVal">
</form>
</div>
</template>
<script>
import Input from "../components/Input";
export default {
name: "Contact",
components: {Input},
data() {
return {
formInputs: [
{inputVal: ''},
{inputVal: ''},
{inputVal: ''},
],
}
},
methods: {
sendMail () {
// You can extract the data from formInputs as per your need
}
}
}
</script>

How to get value from radio button dynamically

i am creating a form for searching a client, using either id or email both are set to be unique. Application made on Codeignitor.
I have created a form with two radio buttons, one for search with ID and another for search with mail+dob.
Depending on the radio button selected, corresponding input fields shown.
In controller, it choose the model function based on the radio button value.
This is I coded, i need to pass the value of radio button to Controller.php file
Form(only included the radio button)
$(document).ready(function() {
$("#usingdob").hide();
$("#usingmail").hide();
$("input:radio").click(function() {
if ($(this).val() == "id") {
$("#usingId").show();
$("#usingdob").hide();
$("#usingmail").hide();
} else {
$("#usingId").hide();
$("#usingdob").show();
$("#usingmail").show();
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="col-md-4">
<label class="radio-inline">
<input type="radio" name="optradio" value="id" checked>Using ID </label></div>
<div class="col-md-4">
<label class="radio-inline">
<input type="radio" name="optradio" value="mail">Using DOB</label>
</div>
I expected to get the radio button value correctlyenter image description here
JS:
$('input[name="optradio"]').click(function(){
var optradio = $(this).val();
//or
var optradio = $("input[name='optradio']:checked").val();
if(optradio == 'id'){
//do your hide/show stuff
}else{
//do your hide/show stuff
}
});
//on search button press call this function
function passToController(){
var optradio = $("input[name='optradio']:checked").val();
$.ajax({
beforeSend: function () {
},
complete: function () {
},
type: "POST",
url: "<?php echo site_url('controller/cmethod'); ?>",
data: ({optradio : optradio}),
success: function (data) {
}
});
}
Try this
<script type="text/javascript">
$( document ).ready(function() {
$("#usingdob, #usingmail").hide();
$('input[name="radio"]').click(function() {
if($(this).val() == "id") {
$("#usingId").show();
$("#usingdob, #usingmail").hide();
} else {
$("#usingId").hide();
$("#usingdob, #usingmail").show();
}
});
});
</script>
One thing I noticed is that you have 'mail' as a value in the DOB option. Another is that there seems to be 3 options and yet you only have 2 radios?
I adjusted the mail value to dob and created dummy divs to test the code. It seems to work.
$(document).ready(function() {
$("#usingdob").hide();
$("#usingmail").hide();
$("input:radio").click(function() {
console.log($(this).val());
if ($(this).val() == "id") {
$("#usingId").show();
$("#usingdob").hide();
$("#usingmail").hide();
} else {
$("#usingId").hide();
$("#usingdob").show();
$("#usingmail").show();
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="col-md-4">
<label class="radio-inline">
<input type="radio" name="optradio" value="id" checked>Using ID </label></div>
<div class="col-md-4">
<label class="radio-inline">
<input type="radio" name="optradio" value="dob">Using DOB</label>
</div>
<div id="usingId">
Using Id div
</div>
<div id="usingdob">
Using dob div
</div>
<div id="usingmail">
Using mail div
</div>
As far as passing the value to the controller goes, ideally the inputs should be in a form. When you submit the form, the selected value can be passed to the php.
<?php
if (isset($_POST['submit'])) {
if(isset($_POST['optradio']))
{
Radio selection is :".$_POST['optradio']; // Radio selection
}
?>
If you want to get currently checked radio button value Try below line which will return current radio button value
var radioValue = $("input[name='gender']:checked").val();
if(radioValue)
{
alert("Your are a - " + radioValue);
}

jquery-form-validator.js: Form input validates, but form itself fails validation. Only one input in form

I'm using jQuery-Form-Validator and most of it is going fine.
I have a form that contains only an email field and a submit button. The email field validates correctly on blur, but when the form is submitted, I get the error message saying the form isn't valid (not the field).
I'm lost.
Here are all of the code bits...
<form id="form_email" name="form_email" class="justify-content-center" onsubmit="return false;">
<div id="email-group" class="form-group">
<input class="form-control form-control-lg mr-1" type="text" id="email" name="email" placeholder="Email Address" value="" data-validation="email" data-validation-error-msg-container="#email-error-dialog" autocomplete="on" />
<p class="form-control-feedback" id="email-error-dialog"></p>
<p class="text-muted">We will only share your email address with other companies when you explicitly give us permission.</p>
<input type="submit" class="btn btn-primary btn-lg" id="email-next" value="Save" />
</div>
</form>
<script>
$( "#form_email" ).submit(function( event ) {
updateRecord('user_inputs', 'fingerprint', fp2_hash, 'email', $( "email" ).value);
//alert( "Handler for .submit() called." );
//event.preventDefault();
});
$( "#email" ).on( 'validation', function(evt, valid) {
// If it's a valid email address...
if ( valid == true ) {
// Update style
if ( $( "#email-group" ).hasClass( "has-danger" ) ) $( "#email-group" ).removeClass( "has-danger" );
if ( $( "#email" ).hasClass( "form-control-danger" ) ) $( "#email" ).removeClass( "form-control-danger" );
$( "#email-group" ).addClass( "has-success");
$( "#email" ).addClass( "form-control-success" );
} else if ( valid == false) {
// Update style
if ( $( "#email-group" ).hasClass( "has-success" ) ) $( "#email-group" ).removeClass( "has-success" );
if ( $( "#email" ).hasClass( "form-control-success" ) ) $( "#email" ).removeClass( "form-control-success" );
$( "#email-group" ).addClass( "has-danger" );
$( "#email" ).addClass( "form-control-danger" );
$( "#email-error-dialog" ).addClass( "has-danger" );
}
});
</script>
Then the validator script is called and it finishes with:
<script type="text/javascript">
$.validate({
modules : 'html5, toggleDisabled',
forms : '#leads, #form_email',
disabledFormFilter : 'form.toggle-disabled',
showErrorDialogs : false,
successElementClass : 'has-success',
errorElementClass : 'has-danger',
onError : function($form) {
alert('Validation of form '+$form.attr('id')+' failed!');
},
onSuccess : function($form) {
alert('The form '+$form.attr('id')+' is valid!');
return true; // Will stop the submission of the form
},
onValidate : function($form) {
return {
element : $( this),
message : 'This input has an invalid value for some reason'
}
},
onElementValidate : function(valid, $el, $form, errorMess) {
console.log('Input ' +$el.attr('name')+ ' is ' + ( valid ? 'VALID':'NOT VALID') );
},
validateOnBlur : true, // disable validation when input looses focus
errorMessagePosition : 'inline', // Default. Instead of top
scrollToTopOnError : true // Set this property to true on longer forms
});
</script>
You're welcome to look at it live, but you have to take a three-question quiz to get to it. Answers: "I own," "$101-150," and "No Shade."
Thank you for your help!
You probably should remove this part:
onValidate : function($form) {
return {
element : $( this),
message : 'This input has an invalid value for some reason'
}
}
It will always tell the validator that you have an element that is invalid when the form gets submitted.

Prevent knockout validation from evaluating on initial load

I have a simple view-model with a few required attributes... I want each input to highlight red if the corresponding property is not valid, but I don't want this highlighting to display when the page is initially loaded... only when a value changes or when the user tries to save / continue...
Right now it's validating the view-model on initial load because I'm specifying data-bind="css: { error: name.isValid() == false }", but I don't know of any other way to get this to work dynamically (similar to how jQuery unobtrusive validation works)...
var foo = { name: ko.observable().extend({required: true}) };
<div data-bind="css: { error: !name.isValid() }">
<input type="text" data-bind="value: name" />
</div>
Any ideas on how to make this work would be appreciated... Thanks!
A better approach is to configure knockout validation to decorate the element with the validationElement class. This is done by adding this configuration option:
ko.validation.configure({ decorateElement: true });
Click here to see a jsfiddle demonstrating this.
****EDIT, IN RESPONSE TO COMMENT FROM QUESTION ASKER***
If you need to decorate the parent element, a more elegant and reusable solution is to apply this custom binding to the parent element.
Javascript
ko.bindingHandlers.parentvalElement = {
update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var valueIsValid = valueAccessor().isValid();
if(!valueIsValid && viewModel.isAnyMessageShown()) {
$(element).addClass("parentError");
}
else {
$(element).removeClass("parentError");
}
}
};
And apply the binding in your HTML like so:
<form data-bind='submit:OnSubmit'>
<label data-bind='parentvalElement:name'>
<span>Name</span>
<input data-bind="value: name" />
</label>
<input type='submit' value='submit' />
<form>
Take a look at this updated jsfiddle to see it in action.
So, here is the solution I came up with:
var Foo = function()
{
this.name = ko.observable().extend({required: true}).isModified(false);
this.validate: function()
{
if (!this.isValid())
{
//... loop through all validated properties and set .isModified(true)
return false;
}
return true;
};
ko.validation.group(foo);
};
var Bar = function()
{
this.foo = new Foo();
this.errors = ko.observableArray([]); //<-- displays errors for entire page
this.save = function()
{
if (!this.foo.validate())
{
this.errors(ko.toJS(this.foo.errors()));
}
};
}
ko.applyBindings(new Bar());
And here is the markup...
<div data-bind="with: foo">
<div class="control-group"
data-bind="css: { error: name.isModified() && !name.isValid() }">
<label class="control-label">Name<span class="help-inline">*</span></label>
<div class="controls">
<input type="text" class="input-block-level" placeholder="Name"
data-bind="value: name, event: { blur: function () { name.isModified(true); }}" />
</div>
</div>
<div class="alert alert-error"
data-bind="visible: $parent.errors().length > 0">
<h5>Errors!</h5>
<ul data-bind="foreach: $parent.errors()">
<li data-bind="text: $data"></li>
</ul>
</div>
</div>
<button type="submit" class="btn btn-primary" data-bind="click: save">Save</button>
and here is the CSS
.error { color: Red; font-weight: bold; }
.help-inline { display: none; }
.error .help-inline { display: inline-block; }
.error input { border-color: Red; }

Resources