Jquery validate error messages not showing up - html

i have an array of inputs generated upon a press of a button. the index is maintained using a global variable numInput set to 0. This is the first HTML of the input.
<label><span>First name</span>
<input placeholder="First name" type="text" name="fName[0]" id="fName"></label>
This is the addmore button, which increments numInput and appends the new and mostly the same HMTL with different index
$(document).on('click','#addmore',function(){
numInput++;
var html = '<label><span>First name</span>
<input placeholder="First name" type="text" name="fName['+numInput+']" id="fName"></label>';
$("#frm").append(html);
rerunRules();
});
Here is my validate method. I did not create the message object here...
$(document).ready(function() {
$('#frm').validate({
highlight: function(element, errorClass) {
$(element).fadeOut(function() {
$(element).fadeIn();
});
},
errorPlacement: function(error, element) {
error.appendTo(element.prev("span"));
},
});
});
rerunRules();
instead I changed the defaults:
<script>
jQuery.extend(jQuery.validator.messages, {
required: "- This field is required."
});
</script>
The rerunRules() is a function that I had to call to "reinject" the rules everytime a new HTML is generated. It is also called right after validate() because the fName rules are in it.
function rerunRules(){
$.each( $('input[name^="fName"]'), function () {
$(this).rules('add', {
required: true
})
});
}
Contrary to what I expected, the error message appears on the first fName[0] just as where its meant to be (to the previous span) but doesnt appear on the next generated HTML from the button. The validate works (wont proceed when I dont enter proper data), the highlight works, but no error message.

Related

show the list of files selected from different directories and ability to remove the files

I am trying to attach some files (zero/single/multiple) and send them as attachments to an email using ANGULARJS and spring.
One thing noticed is when selecting the files from multiple directories only the recently selected file is shown and previous selected file is not shown. How can I show all the files selected by the user from different directories too and give the ability to delete the file (all files or one file) before submitting the form.
Demo:http://plnkr.co/edit/M3f0TxHNozRxFEnrqyiF?p=preview
html:
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
TO: <input type="text" name="to" id="to" ng-model="to" required ></input><br>
Subject : <input type="text" name="subject" id="subject" ng-model="subject"></input>
<br>Attachment: <input type="file" ng-file-model="files" multiple /> <br>
<p ng-repeat="file in files">
{{file.name}}
</p>
<textarea rows="20" maxlength=35000 name="message" ng-model="message" ></textarea>
<button type="button" ng-click="upload()">Send</button>
</body>
js:
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.files = [];
$scope.upload=function(){
alert($scope.files.length+" files selected ... Write your Code to send the mail");
};
});
app.directive('ngFileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var model = $parse(attrs.ngFileModel);
var isMultiple = attrs.multiple;
var modelSetter = model.assign;
element.bind('change', function () {
var values = [];
angular.forEach(element[0].files, function (item) {
var value = {
// File Name
name: item.name,
//File Size
size: item.size,
//File URL to view
url: URL.createObjectURL(item),
// File Input Value
_file: item
};
values.push(value);
});
scope.$apply(function () {
if (isMultiple) {
modelSetter(scope, values);
} else {
modelSetter(scope, values[0]);
}
});
});
}
};
}]);
The default browser behavior is showing currently selected files, to cahnge that you've to customize that filed. And also, I saw your custom directive code, it doesn't allow to select multiple files from different directories.
So, what you can do is, create another scope variable & every time user selects file/files you push those files to this array. In this way you've have set of all selected files from same/different directories and then you can have delete functionality over each file which's ultimately going to be updated.
Updated html view part:
Attachment: <input type="file" ng-file-model="files" multiple /><br>
<p ng-repeat="file in filesToUpload track by $index">
{{file.name}} <span class="delete-file" ng-click="deleteFile($index)">X</span>
</p>
And for this new array update directive scope.$apply part as:
scope.$apply(function () {
if (isMultiple) {
modelSetter(scope, values);
} else {
modelSetter(scope, values[0]);
}
if(values){
scope.filesToUpload = scope.filesToUpload.concat(values);
}
});
In controller have deleteFile function as:
$scope.deleteFile = function(index){
$scope.filesToUpload.splice(index, 1);
};
Working Demo Example
Now user'll be able to delete files anytime. But the input field will still show the last selected file/files and after deleting particular file also it'll not change its status so for that you can just hide field by opacity: 0; css & then create customized Upload button & from that trigger click on actual hidden file input element.
Update: Check this update of same code with custom upload button:
Plunker Example

HTML form validation with Google Apps Script's HTML Service

I'm trying to use HTML form validation when using Google Apps Script's HTML Service. As another user asked, according to the documentation example, you must use a button input instead of a submit input. Using a submit button seems to do the validation, but the server function is called anyway. The answer given to that user didn't work for me. Also, I want to call two functions when submitting the form and this can make it more complex.
This is what I'm trying to do: The user fills a form and I generate a Google Doc and give him the URL. When he clicks the submit button, I show him a jQuery UI dialog saying "Your document is being created" with a nice spinner. Then, when the document is generated, I give him the link. I use the success handler to show the result when the Google Doc stuff is finished, but meanwhile I need a function to show the spinner. I don't know if there is a better way to do that than adding another function to the onclick event and maybe it can be damaging the process in some way. Is there a way not to call any of these functions if the form is not valid (using HTML validation)?
This is a simplified version of my code:
Code.gs
function generateDocument(formObject) {
var doc = DocumentApp.create("Document name");
...
return doc.getUrl();
}
Page.html
<main>
<form id="myForm">
...
<input type="button" value="Generate document"
onclick="showProgress();
google.script.run
.withSuccessHandler(openDocument)
.generateDocument(this.parentNode);"/>
</form>
<div id="dialog-confirm" title="Your document">
<div id="dialog-confirm-text"></div>
</div>
Javascript.html
$( "#dialog-confirm" ).dialog({ autoOpen: false, resizable: false, modal: true });
function showProgress() {
$( "#dialog-confirm" ).dialog({ buttons: [ { text: "Cancel", click: function() { $( this ).dialog( "close" ); } } ] });
$( "#dialog-confirm" ).dialog( "open" );
$( "#dialog-confirm-text" ).html( "<br />Wait a second, your document is being generated...<br /><br /><img src='http://i.stack.imgur.com/FhHRx.gif' alt='Spinner'></img>" );
return false;
}
function openDocument(url) {
$( "#dialog-confirm" ).dialog({ autoOpen: false, resizable: false, width: 400, buttons: [ { text: "Ok", click: function() { $( this ).dialog( "close" ); } } ] });
$( "#dialog-confirm-text" ).html( '<br />Click here to open and print your document!' );
return false;
}
All three HTML docs are joined together (and working with its respective tags) with the include function as recommended in the documentation.
The Cancel button in the dialog will close it but won't stop the doc being created. Is it possible to stop this process?
Here's a solution that I found:
"<input type='submit' onclick='if(verifyForm(this.parentNode)===true){google.script.run.withSuccessHandler(YOUROUTPUT).YOURFUNCTION(this.parentNode); return false;}' value='Submit'></form>";
JavaScript side
function verifyForm(){
var elements = document.getElementById("myForm").elements;
for (var i = 0, element; element = elements[i++];) {
if (element.hasAttribute("required") && element.value === ""){
resetInputs();
return false;
}
if (element.hasAttribute("pattern")){
var value = element.value;
if(value.match(element.pattern)){
}else{
resetInputs();
return false;
}
}
}
return true;
}
Calling the window has issues in iOS sometimes, which is why I investigated this further.
Move the function call to the <form> element; remove any function call from the submit input element; and put intermediary JavaScript code into a <script> tag:
<input tabindex="9" type="submit" value="Save Input" id='idInputBtn'>
<form id="myInputForm" name="input" onsubmit="fncWriteInput(this)">
<script>
window.fncWriteInput= function(argTheInfo) {
// Do additional checks here if you want
var everythingIsOk = . . . . . . . ;
if (everythingIsOk) {
google.script.run
.withSuccessHandler(openDocument)
.generateDocument(argTheInfo);
};
};
Notice that this.parentNode gets removed to the arg of the function call, and just use this in the function argument because the function is getting called from the <form> element, which is the parent.
If there are any errors, the form will not be submitted, and the user will get a msg that something was wrong. No code will run.
This is pseudo code, but I do use a set up like this in my application. But use developer tools and you can put a break point right in your browser and step through every line to test it without needing to put in console.log statements.

How to validate form when user clicks elsewhere

For the sign up form I am making, I want to validate passwords so that a user must enter a password that includes at least one capital letter and at least one number.
I have implemented this here:
http://jsfiddle.net/k9aHV/1/
<form action="login.php" method="post">
<p><b>UserName:</b> <input type="text" required pattern="\w+" name="fname"/></p>
<p><b>Password:</b> <input type="password" required pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z])\w{6,}" name="password" onblur="this.setCustomValidity(this.validity.patternMismatch ? 'Password must contain at least 6 characters, including UPPER/lowercase and numbers' : '');if(this.checkValidity()) form.password1.pattern = this.value;"></p>
<p><b>Confirm Password:</b> <input type="password" required pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z])\w{6,}" name="password1" onblur="
this.setCustomValidity(this.validity.patternMismatch ? 'Please enter the same password as above' : '');"/></p>
<p><b>Email:</b> <input type="email" name="email"/></p>
<input type="submit"/>
</form>
At the moment, the field is validated only when the user presses submit.
How can I adjust my code so that the code is validated as soon as the user tabs or clicks away from the input field?
You can trigger native validation on blur like so
input.addEventListener('blur', function(e) {
e.target.checkValidity();
});
The problem is you can't trigger the validation error popup programmatically.
One workaround is to programmatically click the submit button BUT the popup will only show the first invalid input element!
A more user friendly solution is to show the validation message in an element.
See this JSFiddle
var idx;
var passwordInputs = document.querySelectorAll('input[type="password"]');
for(idx=0; idx< passwordInputs.length; idx++) {
//set custom validation
passwordInputs[idx].addEventListener('input', function(e) {
if(e.target.validity.patternMismatch) {
e.target.setCustomValidity('Password must contain at least 6 characters, including UPPER/lowercase and numbers');
}
else {
e.target.setCustomValidity('');
}
});
}
//code starting here is to show the validation message in a span element
function showValMessage(elem, msg) {
var span = elem.parentNode.querySelector('span');
span.innerText = msg;
}
var inputs = document.querySelectorAll('input');
for(idx=0; idx< inputs.length; idx++) {
var input = inputs[idx];
//validate on blur
input.addEventListener('blur', function(e) {
e.target.checkValidity();
});
//show validation message
input.addEventListener('invalid', function(e) {
showValMessage(e.target, e.target.validationMessage);
});
//hide validation message. There is on valid event :(
input.addEventListener('input', function(e) {
if(e.target.validity.valid) {
showValMessage(e.target, '');
}
});
}

How can I detect keydown or keypress event in angular.js?

I'm trying to get the value of a mobile number textbox to validate its input value using angular.js. I'm a newbie in using angular.js and not so sure how to implement those events and put some javascript to validate or manipulate the form inputs on my html code.
This is my HTML:
<div>
<label for="mobile_number">Mobile Number</label>
<input type="text" id="mobile_number" placeholder="+639178983214" required
ngcontroller="RegisterDataController" ng-keydown="keydown">
</div>
And my controller:
function RegisterDataController($scope, $element) {
console.log('register data controller');
console.log($element);
$scope.keydown = function(keyEvent) {
console.log('keydown -'+keyEvent);
};
}
I'm not sure how to use the keydown event in angular.js, I also searched how to properly use it. And can i validate my inputs on the directives? Or should I use a controller like what I've done to use the events like keydown or keypress?
Update:
ngKeypress, ngKeydown and ngKeyup are now part of AngularJS.
<!-- you can, for example, specify an expression to evaluate -->
<input ng-keypress="count = count + 1" ng-init="count=0">
<!-- or call a controller/directive method and pass $event as parameter.
With access to $event you can now do stuff like
finding which key was pressed -->
<input ng-keypress="changed($event)">
Read more here:
https://docs.angularjs.org/api/ng/directive/ngKeypress
https://docs.angularjs.org/api/ng/directive/ngKeydown
https://docs.angularjs.org/api/ng/directive/ngKeyup
Earlier solutions:
Solution 1: Use ng-change with ng-model
<input type="text" placeholder="+639178983214" ng-model="mobileNumber"
ng-controller="RegisterDataController" ng-change="keydown()">
JS:
function RegisterDataController($scope) {
$scope.keydown = function() {
/* validate $scope.mobileNumber here*/
};
}
Solution 2. Use $watch
<input type="text" placeholder="+639178983214" ng-model="mobileNumber"
ng-controller="RegisterDataController">
JS:
$scope.$watch("mobileNumber", function(newValue, oldValue) {
/* change noticed */
});
You were on the right track with your "ng-keydown" attribute on the input, but you missed a simple step. Just because you put the ng-keydown attribute there, doesn't mean angular knows what to do with it. That's where "directives" come into play. You used the attribute correctly, but you now need to write a directive that will tell angular what to do when it sees that attribute on an html element.
The following is an example of how you would do that. We'll rename the directive from ng-keydown to on-keydown (to avoid breaking the "best practice" found here):
var mod = angular.module('mydirectives');
mod.directive('onKeydown', function() {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
// this next line will convert the string
// function name into an actual function
var functionToCall = scope.$eval(attrs.ngKeydown);
elem.on('keydown', function(e){
// on the keydown event, call my function
// and pass it the keycode of the key
// that was pressed
// ex: if ENTER was pressed, e.which == 13
functionToCall(e.which);
});
}
};
});
The directive simple tells angular that when it sees an HTML attribute called "ng-keydown", it should listen to the element that has that attribute and call whatever function is passed to it. In the html you would have the following:
<input type="text" on-keydown="onKeydown">
And then in your controller (just like you already had), you would add a function to your controller's scope that is called "onKeydown", like so:
$scope.onKeydown = function(keycode){
// do something with the keycode
}
Hopefully that helps either you or someone else who wants to know
You can checkout Angular UI # http://angular-ui.github.io/ui-utils/ which provide details event handle callback function for detecting keydown,keyup,keypress
(also Enter key, backspace key, alter key ,control key)
<textarea ui-keydown="{27:'keydownCallback($event)'}"></textarea>
<textarea ui-keypress="{13:'keypressCallback($event)'}"></textarea>
<textarea ui-keydown="{'enter alt-space':'keypressCallback($event)'}"> </textarea>
<textarea ui-keyup="{'enter':'keypressCallback($event)'}"> </textarea>
JavaScript code using ng-controller:
$scope.checkkey = function (event) {
alert(event.keyCode); //this will show the ASCII value of the key pressed
}
In HTML:
<input type="text" ng-keypress="checkkey($event)" />
You can now place your checks and other conditions using the keyCode method.

passing data with JSON

What I want to be abl
e to do is passing the form data to a php file and then having the results passed back into app so that the user isnt directly accessing the php file at any point.
This is what I came up with but I cant get it too pass the data. I used chrome with -disable-web-security. It always returns false so I guess the data isnt being passed to the php file. Any help would be great. Also. when it forwards to the results page, it goes blank after a few seconds. thank you.
HTML
<form id="form" method="POST" data-ajax="false" data-transition="pop" data-direction="reverse">
<fieldset>
<label for="name" class="ui-hidden-accessible">Name</label>
<input type="text" name="name" id="name" value="" class="required" placeholder="Name"/>
<label for="email" class="ui-hidden-accessible">E-Mail</label>
<input type="email" name="email" id="email" value="" class="required" placeholder="E-Mail"/>
<label for="memory" class="ui-hidden-accessible">Memory</label>
<textarea name="memory" name="memory" id="memory" class="required" placeholder="Your Memory..."></textarea>
<label for="submit" class="ui-hidden-accessible">Submit</label>
<input type="submit" name="submit" id="submit" value="SEND">
</fieldset>
</form>
JS
$(document).on('pagebeforeshow', '#formPage', function(){
$(document).on('click', '#submit', function() { // catch the form's submit event
if($('#name').val().length > 0 && $('#email').val().length > 0 && $('#memory').val().length > 0){
var that = $(this),
contents = that.serialize();
// Send data to server through ajax call
// action is functionality we want to call and outputJSON is our data
$.ajax({
url: 'http://www....',
dataType: 'json',
type: 'post',
data: contents,
async: true,
beforeSend: function() {
// This callback function will trigger before data is sent
$.mobile.showPageLoadingMsg(true); // This will show ajax spinner
},
complete: function() {
// This callback function will trigger on data sent/received complete
$.mobile.hidePageLoadingMsg(); // This will hide ajax spinner
},
success: function(data) {
console.log(data);
},
error: function (request,error) {
// This callback function will trigger on unsuccessful action
alert('Network error has occurred please try again!');
}
});
} else {
alert('Please fill all nececery fields');
}
return false; // cancel original event to prevent form submitting
});
});
PHP
header('Content-type: text/javascript');
$json = array(
'success' => false,
'result' => 0
);
if(isset($_POST['name'], $_POST['email'], $_POST['memory'])){
$name = $_POST['name'];
$email = $_POST['email'];
$memory = $_POST['memory'];
$json['success'] = true;
$json['result'] = $name;
}
echo json_encode($json);
You are not serializing the form data correctly and the result is that the contents variable is empty.
Change this code:
var that = $(this),
contents = that.serialize();
To this:
//var that = $(this), // <-- delete this line
contents = $('#form').serialize();
YOU ALSO NEED TO FIX ..
You haven't realized it yet but you have created a multiple click binding issue by placing your click handler in the bagebeforeshow event. In order to prevent that from occuring you need to
Change this code:
$(document).on('pagebeforeshow', '#formPage', function(){
To this:
$(document).on('pageinit', '#formPage', function(){
This way your $(document).on('click', '#submit', function() { is only ever bound once regardless of how many times a user leaves and returns to the '#formPage' page
EDITED
No, the data submitted to your backend PHP program via ajax is not json encoded. It is standard HTTP POST data and is accessed via $_POST (or $_REQUEST).
I have your code (with the changes I outlined in my answer above) working on my server. I have placed the two files I setup to test your code in a pastbin for your reference:
The php file:
(edit the path to the included javascript file for your environment)
sandbox_ajax_form.php
The javascript file:
(edit the path that the form data is sent to)
sandbox_ajax_form.js