So, instead of having a form in the HTML, I decided to create the form on fly and append it to another element (in my case a <section>, but that will be an option in the near future).
I'm using this method:
var formWrapper = ['<div class="content-login">','</div>'];
var form = [
'<form name="login-form" class="login-form" method="post" action="#">',
'<fieldset class="login-fields">',
'<fieldset class="username-wrapper">',
'<label for="username" class="user-img"><img src="assets/gfx/user.png" alt="Username" /></label>',
'<input type="text" name="username" class="username" placeholder="Username" value="" autocomplete="off" />',
'</fieldset>',
'<fieldset class="password-wrapper">',
'<label for="password" class="pass-img"><img src="assets/gfx/password.png" alt="Password" /></label>',
'<input type="password" name="password" class="password" placeholder="Password" value="" autocomplete="off" />',
'</fieldset>',
'<fieldset class="login-wrapper">',
'<button type="submit" name="login" class="login">Login</button>',
'</fieldset>',
'</fieldset>',
'</form>'
];
setTimeout(function () {
$(formWrapper.join('')).appendTo('section').hide();
$(form.join('')).appendTo('.content-login');
$('.content-login').fadeIn('slow');
}, 1500);
This way I have a nice fade in effect and it will give me the opportunity to change whatever I want after I fully develop it.
But my question is in fact the following: I have a form, so of course I will use Ajax to submit it, and I already have the script for that. The thing is now, when I click on the button, the .click event does not occur, it only takes me to the default action of the form which is "#" in my case. Why is that ?
Here is the other part of the script, for a better understanding :
$('.login-form .login').click(function(){
if($('input.username').val() == "" || $('input.password').val() == "")
{
console.log('Please enter Username & Password');
$('.login-form').effect("shake", { distance: 40, times: 2 }, 100);
return false;
}
else {
$('.login-fields').fadeOut();
$('.login-form').spin("login", "#ffffff");
$.ajax
({
type: 'POST',
url: 'assets/class/login/process.php',
dataType: 'json',
data:
{
username: $('input.username').val(),
password: $('input.password').val()
},
success:function(data)
{
if(!(data.lockdown == true)) {
if(data.error === true) {
console.log(data.message);
$('.login-form').spin(false);
$('.login-fields').fadeIn();
$('.login-form').effect("shake", { distance: 40, times: 2 }, 100);
}
else {
console.log(data.message);
$('.login-form').spin(false);
$('.login-fields').fadeIn();
$('.content-login').fadeOut();
var structure = [
'<div class="after-login">',
'<div class="inside">',
'<div class="row-one">',
'<h1>',data.message,'</h1>',
'</div>',
'<div class="row-two">',
'<a class="cancel" href="',links.cancel,'?logout">Cancel</a>',
'<a class="continue" href="',links.proceed,'">Continue</a>',
'</div>',
'</div>',
'</div>'
];
setTimeout(function () {
$(structure.join('')).appendTo('section').fadeIn('slow');
}, 1500);
}
}
else {
console.log(data.message);
$('.login-form').spin(false);
$('.content-login').fadeOut();
var structure = [
'<div class="system-lockdown">',
'<div class="inside">',
'<div class="row-one">',
'<h1>',data.message,'</h1>',
'</div>',
'<div class="row-two">',
'<a class="back" href="',links.goback,'">Back</a>',
'</div>',
'</div>',
'</div>'
];
setTimeout(function () {
$(structure.join('')).appendTo('section').fadeIn('slow');
}, 1500);
}
},
error:function(XMLHttpRequest,textStatus,errorThrown)
{
console.log('A PHP error triggered this, check your PHP log file for more information');
}
});
return false;
}
});
$.click() will only work on elements that have been created before the handler was created.
Instead, use $.live() instead:
$('.login-form .login').live('click', function() {
// Your code
});
If you're using jQuery 1.7 or above, you can also use $.on() in a similar way:
$('.login-form .login').on('click', function() {
// Your code
});
The preferred way to handle events with dynamically added content is with on()—or delegate, since you're on jQuery 1.6
$(document).delegate('.login-form .login', 'click', function(){
});
Note that this will listen to every single click anywhere in your document. Ideally you'd like to identify some more narrow container from which all clicks will come, and listen to that. So if all these clicks will be coming from your section, you'd do this
$("section").delegate('.login-form .login', 'click', function(){
});
Related
I send information to the page via livewire and display it via jQuery in loop.
<ul class="custom-control-group" id="networlist">
</ul>
<script>
let networks
window.addEventListener('networksEvent' , event => {
networks = event.detail.networks;
});
$(window).on('load', function() {
$.each(networks, function( index, network ) {
var checked = index == 0 ? "checked" : ''
$('#networlist').append('<li>' +
'<div class="custom-control custom-checkbox custom-control-pro no-control">'+
'<input type="radio" '+checked+' class="custom-control-input" name="coinNetwork" value="'+network.id+'" id="'+network.id+'">'+
'<label class="custom-control-label english" for="'+network.id+'">'+network.name+'</label>'+
'</div>'+
'</li>');
});
});
$('.coinNetwork').on('change', function(event) {
console.log($('input[name=coinNetwork]:checked', '#networlist').val())
});
</script>
But when I click on the radio button, nothing happens and it does not show me the value in the console.. what is problem?
You already had the correct selector inside your final console.log but you bind the event a little too late, because the list does not exist when you try to bind it. Either move the event handler inside your load handler, or handle it dynamically:
let networks = [{id: 1, name: 'network1'}, {id: 2, name: 'network2'}];
$(window).on('load', function() {
$.each(networks, function( index, network ) {
var checked = index == 0 ? "checked" : ''
$('#networlist').append('<li>' +
'<div class="custom-control custom-checkbox custom-control-pro no-control">'+
'<input type="radio" '+checked+' class="custom-control-input" name="coinNetwork" value="'+network.id+'" id="'+network.id+'">'+
'<label class="custom-control-label english" for="'+network.id+'">'+network.name+'</label>'+
'</div>'+
'</li>');
});
$('input[name=coinNetwork]').on('click', function(event) {
console.log($('input[name=coinNetwork]:checked', '#networlist').val())
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="custom-control-group" id="networlist">
For binding to a dynamically added element:
let networks = [{id: 1, name: 'network1'}, {id: 2, name: 'network2'}]
$(window).on('load', function() {
$.each(networks, function( index, network ) {
var checked = index == 0 ? "checked" : ''
$('#networlist').append('<li>' +
'<div class="custom-control custom-checkbox custom-control-pro no-control">'+
'<input type="radio" '+checked+' class="custom-control-input" name="coinNetwork" value="'+network.id+'" id="'+network.id+'">'+
'<label class="custom-control-label english" for="'+network.id+'">'+network.name+'</label>'+
'</div>'+
'</li>');
});
});
//bind it to networlist
$('#networlist').on('click', 'input[name=coinNetwork]', function(event) {
console.log($('input[name=coinNetwork]:checked', '#networlist').val())
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="custom-control-group" id="networlist">
Also notice I changed the event from change to click so you get the correct selected value (instead of the last one).
I tried using jquery validate but i've spent more than 4 hours to search how to solve my problem but couldn't find it. The problem is when I tried using jquery validate for filesize in multidimensional array, it doesn't work. It can still submit the form and not showing the error message.
Here is it my field
var numberIncr = 1;
$('#add-berkas').click(function () {
var box_html = $('<div class="text-box form-group row">\n' +
' <div class="col-sm-8">\n' +
' <input type="text" name="berkas['+numberIncr+'][nama]" placeholder="Nama File" class="form-control" required>\n' +
' </div>\n' +
' <div class="col-sm-4">\n' +
' <input type="file" name="berkas['+numberIncr+'][file]" id="berkasfile'+numberIncr+'" accept="application/pdf" required/>\n' +
' <button id="remove-berkas" class="btn btn-sm btn-danger remove-box" type="button"><i class="fa fa-trash"></i></button>\n' +
' </div>\n' +
' </div>');
$('.text-box:last').after(box_html);
box_html.fadeIn('slow');
numberIncr++;
});
And this is the validate
$.validator.addMethod('filesize', function (value, element, param) {
return this.optional(element) || (element.files[0].size <= param)
}, 'File size must be less than {0}');
var berkas = $('input[name^="berkas"]');
berkas.filter('input[name$="[file]"]').each(function() {
$(this).rules("add", {
extension: "pdf", filesize:1048576,
messages: "Berkas must be PDF and less than 1MB"
});
});
$("#form").validate({
rules: {
surat: {extension: "pdf", filesize: 1048576, },
},
messages: {
surat: "Surat must be PDF and less than 1MB",
},
errorPlacement: function(error,element){
showErrorMessage(error.text());
},
submitHandler: function(form) {
form.submit();
},
highlight: function(element, errorClass) {
return false;
}
});
Your problem is caused by presumably only calling this code once on page load, when the fields don't yet exist...
berkas.filter('input[name$="[file]"]').each(function() {
$(this).rules("add", {
extension: "pdf", filesize:1048576,
messages: "Berkas must be PDF and less than 1MB"
});
});
There are no matching fields at the time you call this code. The whole point of this method is for you to dynamically add the rules after you create each field.
You must call it immediately after adding a new field. Put it inside the click handler near the bottom.
var numberIncr = 1;
$('#add-berkas').click(function () {
var box_html = $('<div class="text-box form-group row">\n' +
.....
' </div>');
$('.text-box:last').after(box_html);
box_html.fadeIn('slow');
// add rules to new field here
$('[name="berkas[' + numberIncr + '][file]"]').rules("add", {
extension: "pdf", filesize:1048576,
messages: "Berkas must be PDF and less than 1MB"
});
numberIncr++;
});
You wouldn't need an .each() since you only create one field on each click. Just target the new field and add the rule.
This question already has answers here:
Event binding on dynamically created elements?
(23 answers)
Closed 3 years ago.
I have 3 input fields inside a table row that are needed to validate on the client-side without pressing the submit button:
<td>
<input name="clr" type="number" class="form-control" min="27" step="any">
</td>
<td>
<input name="litre" type="number" class="form-control" min="0.5" step="any">
</td>
<td>
<input name="fat" type="number" class="form-control" min="3.0" max="7.0" step="any">
</td>
So I attach blur and invalid events. I also need to attach those two events on the dynamically created input fields.
Below code is work for static input fields:
$('input[name="clr"], input[name="litre"], input[name="fat"]').on('blur', function(event) {
event.target.checkValidity();
$(event.target).removeClass("errorClass");
}).on('invalid', function(event) {
setTimeout(function() {
$(event.target).focus().addClass("errorClass");
}, 50);
});
For dynamically created elements I tried this code:
$(document).on({
'blur': function(event) {
event.target.checkValidity();
$(event.target).removeClass("errorClass");
},
'invalid': function(event) {
setTimeout(function() {
$(event.target).focus().addClass("errorClass");
}, 50);
}
},
'input[name="clr"], input[name="litre"], input[name="fat"]'
);
BUT this won't work!
Can anyone give me suggestion how can I overcome this problem?
EDIT: Heres, how I created the dynamically elements:
let clrTd = '<td><input name="clr" type="number" class="form-control" min="27" step="any"></td>';
let litreTd = '<td><input name="litre" type="number" class="form-control" min="0.5" step="any"></td>';
let fatTd = '<td><input name="fat" type="number" class="form-control" min="3.0" max="7.0" step="any"></td>';
$(document).on('blur', 'input[name="code"]', function () {
if ($(this).closest("tr").is(":last-child") && $(this).val() != '') {
var markup = "<tr>" + clrTd + litreTd + fatTd + "</tr> ";
$("#editableTable tbody").append(markup);
}
});
The reason why it is not working is because you are attaching an event handler to specific elements during the initial phase of the webpage creation. Identification of specific elements and attaching the Event handler needs to happen after the elements have been added.
You can create new function and reuse them in such a case like this:
function handleBlur(event){
event.target.checkValidity();
$(event.target).removeClass("errorClass");
}
function handleInvalid(event){
setTimeout(function() {
$(event.target).focus().addClass("errorClass");
}, 50);
}
Changes for attaching these event handlers to specific elements:
$('input[name="clr"], input[name="litre"], input[name="fat"]')
.on('blur',function(event) {
handleBlur(event);
})
.on('invalid', function(event) {
handleInvalid(event);
});
In the end of dynamically added content
$(document).on('blur', 'input[name="code"]', function () {
if ($(this).closest("tr").is(":last-child") && $(this).val() != '') {
var markup = "<tr>" + clrTd + litreTd + fatTd + "</tr> ";
$("#editableTable tbody").append(markup);
$('#editableTable tbody').find('input[name="clr"], input[name="litre"], input[name="fat"]')
.on('blur',function(event) {
handleBlur(event);
})
.on('invalid', function(event) {
handleInvalid(event);
});
}
});
I am using a 'required' and 'email' validators on the 'email' input field. The validators make use of parsers and formatters and they work fine. However, I also have some validation on 'bind' event.
Here is the directive:
angular.module('simpleRepairApp')
.directive('uniqueEmail', function (Checker) {
return {
require:'ngModel',
restrict:'A',
link:function ($scope, element, attrs, model) {
var last = '';
var current = '';
element.bind('blur', function() {
current = element.val();
console.log(current, last);
if(current !== last){
Checker.email({ email:current }).then(
function(response) {
model.$setValidity('uniqueEmail', response.available);
}
);
}
last = current;
});
}
};
});
I need to check if the email already exists in the database or not after user clicks out of the field (I do not want to check upon every key press or change).
The problem I am having is, after the unique validation is performed, it shows the unique error message, but after you type to correct the email, the model value stays undefined. You have to click out of the input, then the value in the model in defined again.
Anyone can help me solve this, it is driving me nuts!:)
WORKING SOLUTION:
angular.module('simpleRepairApp')
.directive('emailUnique', function () {
return {
restrict: 'E',
require: ['form', 'ngModel'],
scope: {
'form': '=form',
'model': '=ngModel',
'labelClass': '#',
'inputClass': '#'
},
compile: function(element, attrs)
{
if (!attrs.labelClass) { attrs.labelClass = 'col-sm-4'; }
if (!attrs.inputClass) { attrs.inputClass = 'col-sm-8'; }
attrs.required = attrs.required == 'true';
},
controller: function($scope, Checker) {
$scope.checkEmail = function() {
var email = $scope.form.email.$viewValue;
var checkField = $scope.form.emailCheck;
Checker.email({ email:email }).then(
function(response) {
checkField.$setValidity('unique', response.available);
$scope.form.$setValidity('check', true);
checkField.hasVisit = true;
}
);
};
$scope.setUnchecked = function() {
console.log($scope.form);
$scope.form.emailCheck.hasVisited = false;
$scope.form.$setValidity('check', false);
$scope.form.emailCheck.$setValidity('unique', true);
};
},
template: '<div ng-class="{ \'has-error\' : !form.email.$valid || !form.emailCheck.$valid }">' +
'<label class="{{ labelClass }} control-label required" for="email" translate>E-mail</label>' +
'<div class="{{ inputClass }}">' +
'<input name="email" class="form-control" type="email" id="email" ng-model="model" ng-change="setUnchecked()" ng-blur="checkEmail()" ng-required="true" autocomplete="off">' +
'<div class="help-block" ng-show="(!form.email.$valid || !form.emailCheck.$valid) && !form.email.$pristine">' +
'<div ng-messages="form.email.$error">' +
'<div ng-message="required"><span translate>Please enter your e-mail.</span></div>' +
'<div ng-message="email"><span translate>Please enter a valid e-mail.</span></div>' +
'</div> ' +
'<div ng-messages="form.emailCheck.$error">' +
'<div ng-message="check"><span translate>E-mail will be checked upon blur.</span></div>' +
'<div ng-message="unique"><span translate>This e-mail is already in use.</span></div>' +
'</div> ' +
'</div>' +
'<input name="emailCheck" type="hidden" class="form-control" ng-model="checked">' +
'<div class="help-block" ng-messages="form.emailCheck.$error" ng-show="!form.emailCheck.$valid">' +
'</div>' +
'</div>' +
'</div>'
};
});
I think you might be complicating things a bit by making a directive, why don't you simply add a watcher to your controller?
Note: I'm not familiar if any of these methods will work for you, but I'm adding them as an illustrative purpose of not binding to the "blur" event, but rather have the events get triggered when the MODEL changes. Which is what angular is designed to do. I'm also making an assumption that your Checker is handling the promises correctly
First alternative method (using $watch)
<form name="myForm" ng-controller="ExampleController">
<input type="email" name="input" ng-model="text" required />
</form>
Then in your ng-app controller:
function isNullOrUndefined(value) {
return (value == 'undefined' || value == null);
}
//listener on the ng-model='text', waiting for the data to get dirty
$scope.$watch('text', function (newValue, oldValue) {
if (newValue != oldValue)
{
var truthyVal = !(isNullOrUndefined(newValue));
if (truthyVal) {
//angular's way of checking validity as well
//$scope.myForm.text.$valid
Checker.email({ email:current }).then(
function(response) {
model.$setValidity('textErr', response.available);
}
}
}
}, true);
Second alternative method (using ng-change):
<form name="myForm" ng-controller="ExampleController">
<input type="email" name="input" ng-model="text" ng-change="checkEmail()" required />
</form>
$scope.checkEmail = function(){
Checker.email({ email:current }).then(
function(response) {
model.$setValidity('textErr', response.available);
}
}
Because you are binding on the blur event, the validation won't work the way you want. You will have to click out of the field before that function can run. If you indeed want it to validate when they finish typing the email, then you will have to bind to some sort of key event.
My suggestion is to bind to keyup, and only do the server-side check when the email address appears to be of valid syntax.
I'd like to create a webpage where the user can add and remove sets of form fields by means of one add button and remove buttons related to the set to be removed. Entered values will be checked by means jquery validate, for which rules are added dynamically as well. pls see an an simplified example below of my targeted form:
What is a good structure of javascript code for adding, removing and validate sets of forms fields? I googled -also on this site- and there are many javascript examples for adding sets of formfields. I like the example I found at view-source:http://www.coldfusionjedi.com/demos/jqueryvalidation/testadd.cfm, which uses a form template. But I struggle in particular with the javascript coding for the removing buttons..(which are not in the example)
my targeted (simplified) form (template with 1 set of 3 formfields):
<form name="myForm" id="myForm" method="post" action="">
<input id="name1" name="name1" />
<input id="email1" name="email1" />
<input id="phone1" name="phone1" />
<input type="submit" value="Save">
</form>
I think that you should template the form. I.e. wrap it in a function, so you can create it again and again. Here is a jsfiddle http://jsfiddle.net/krasimir/2sZsx/4/
HTML
<div id="wrapper"></div>
add form
JS
var wrapper = $("#wrapper");
var addForm = $("#add-form");
var index = 0;
var getForm = function(index, action) {
return $('\
<form name="myForm" id="myForm" method="post" action="' + action + '">\
<input id="name' + index + '" name="name' + index + '" />\
<input id="email' + index + '" name="email' + index + '" />\
<input id="phone' + index + '" name="phone' + index + '" />\
<input type="submit" value="Save">\
remove form\
</form>\
');
}
addForm.on("click", function() {
var form = getForm(++index);
form.find(".remove").on("click", function() {
$(this).parent().remove();
});
wrapper.append(form);
});
Simple validation can be done when your form is submitted, thus:
$('#myForm').submit({
var n1 = $('#name1').val();
var e1 = $('#email1').val();
var p1 = $('#phone1').val();
if (n1=='' || e1=='' || p1=='') {
alert('Please complete all fields');
return false;
}
});
Note that the return false will abort the submit and return user to the document.
Great code for adding/removing form fields can be found in this question: https://stackoverflow.com/questions/18520384/removing-dynamically-generated-textboxes-in-jquery
jsFiddle here
If you are using KeenThemes (maybe Metronic theme)
https://preview.keenthemes.com/good/documentation/forms/formvalidation/advanced.html
You can do like this.
var form = document.getElementById('form_id');
var validator = FormValidation.formValidation(
form,
{
fields: {
name: {
validators: {
notEmpty: {
message: 'Please enter template name'
},
stringLength: {
min: 3,
trim: true,
message: 'Please enter a longer name.'
},
}
},
...
more fields here
...
},
plugins: {
trigger: new FormValidation.plugins.Trigger(),
bootstrap: new FormValidation.plugins.Bootstrap(),
},
});
function addNewFieldDynamically() {
// add new field here
...
validator.addField('field_name', {
validators : {...}
})
}
function removeFieldDynamically() {
// remove a field here
...
validator.removeField('field_name')
}