Javascript driven forms in Django - javascript

Django uses his forms API for input validation. The form is sent to the template, and it is rendered as an html (as_p and friends).
When the user is ready, he POST the form, the data is validated, and the form is re-rendered on the template if it is not valid.
This is odd when the form is not valid just because lack of enough caracteres (i.e. min_length) on a field or invalid characters: one POST too much just to tell the user it is missing something very basic.
So, is there any available way (Django or app) of rendering a form with javascript code that "tests"[*] some of the form' fields on the client-side? I.e. have a form which is rendered as_javascript(...) that dynamically shows error messages that would be shown by form.errors?
This should not work for all fields because some require a database hit, but it should work on simple (and most common) fields, namely CharField, TextField, etc.
[*] "tests" because validation has always to be made also on the server-side.

So you want to validate something in JS before submitting. Here's one way to do that.
Instead of putting an input of type submit in the form you should put a button of type button:
<form id="my-form" submit="...">
...
<input type='button' id='submit-button' value="Save">
</form>
Note that unless you specify the type as "button", it will still try to submit.
Then in a JS file you write something like this (include jQuery in your HTML file):
$('#submit-button').click(function() {
var errors = testErrors(); // this function tests for the errors.
if (errors != "") {
alert(errors);
} else {
$('#my-form').submit();
}
}
Example testErrors():
function testErrors() {
var country = $("#id_country").val();
var city = $("#id_city").val();
var errors = "";
if (country == "") {
errors += "- Please select a country\n";
}
if (city.length <= 10 ) {
errors += "- Your city name is too short\n";
}
return errors;
}
So in testErrors you define your own tests for each field. In this example there are two, country and city. For country the code tests whether it's blank and for city whether it's longer than 10 characters. You can define further tests of your own. Please refer to jQuery documentation as well on how to retrieve values from different types of form fields.

Related

How to detect Event Listeners and their actions on input fields

I have purchased a booking plugin (wordpress) to add to a site.
https://wpamelia.com/
I cannot show the site I am working on, but here a demo from plugin developers
https://sports.wpamelia.com/#book
Once you have chosen your date and time, you end up on a form with input fields.
I was able to pre-fill this form with data that I could pass via the URL.
My URL would look something like this: https://sports.wpamelia.com/?first=Jim&last=Tester&email=something%40something.com&phone=0222222222#book
But here is the problem:
Even though I managed to use jQuery to pre-fill the input fields of the form, as soon as I click confirm the fields' content is erased and the error "Please enter... " appears for each of them.
So again:
STEP 1: I open the booking page with an URL containing data in the query string
STEP 2: Using jQuery, I manage to pre-fill the form that appears after having chosen date and time (first name, last name ...)
STEP 3: I click "Confirm"
RESULT: all the fields are empty and for each one the error message "Please enter first name" (etc..) appears
I've messaged the plugin developers. Only answer was that there is indeed no functionality to take the data from the Query String into the form fields yet.
MY QUESTIONS:
1) How could I find out, with chrome inspector or other tools, why exactly the content I pre-fill into the form is ignored?
---> I've tried things like getEventListeners in the chrome inpector's console, but I don't really see how to get information out of that
2) Would anyone know what the issue is and/or how I could bypass it?
---> there is a lot of javascript from the plugin developers behind that and something is expecting manual entering of the data into the fields...
---> but even when trying to fake manual entering with things like $(this).trigger("change").val(function(i,val){return 'aaaa';}); this didn't solve the problem....
(If anyone is interested, I can post later my javascript/jQuery functionality to get the form fields pre-filled with data from Query String... interesting code as you have to wait until the fields appear for jQuery to recognise them..)
Thanks so much for any help!
cheers
Admino
#Admino - this may not be the best solution and I know this is an old question so you may not need it now but after not finding a better one it at least worked for me.
function getUrlVars() {
var vars = {};
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
vars[key] = value;
});
return vars;
}
function valueOutput(element) {
element.dispatchEvent(new Event('input'));
}
jQuery(function() {
jQuery(document).on('change', 'input', function(e) {
valueOutput(e.target);
});
// you may want to perform more validations here if needed
// just checking here if email is present (but not checking for valid email address)
var fname = getUrlVars()["first"];
var lname = getUrlVars()["last"];
var email = getUrlVars()["email"];
var phone = getUrlVars()["phone"];
var custom1 = getUrlVars()["custom1"]; // you know this field label is Order Number
if (email.length > 0) {
// run an interval until the elements are present on the page (form displayed)
var checkInputs = setInterval(function() {
if (jQuery('.amelia-app-booking label[for="customer.email"]').length > 0) {
var em = jQuery('.amelia-app-booking label[for="customer.email"]').closest('.el-form-item').find('.el-input__inner');
// this checks to see if an Amelia customer is already present
if (em.val() == '') {
em.prop('value', email).val(email).trigger('change');
jQuery('.amelia-app-booking label[for="customer.firstName"]').closest('.el-form-item').find('.el-input__inner').prop('value', fname).val(fname).trigger('change');
jQuery('.amelia-app-booking label[for="customer.lastName"]').closest('.el-form-item').find('.el-input__inner').prop('value', lame).val(lame).trigger('change');
jQuery('.amelia-app-booking label[for="customer.phone"]').closest('.el-form-item').find('.el-input-group__prepend').siblings('.el-input__inner').prop('value', phone).val(phone).trigger('change');
}
// for custom fields I check the label text to find the correct input
if (custom1 != '') {
jQuery('.amelia-app-booking label:contains("Order Number")').closest('.el-form-item').find('.el-input__inner').prop('value', custom1).val(custom1).trigger('change');
}
// form info is updated so clear the interval
clearInterval(checkInputs);
}
}, 500);
}
});
You may want to try a different method than url params to sync this info so it's not so public in the url string. This code may not need both the prop and val jquery setters but I just left them for you to try. Hope it helps (and to others I'm open to a better solution)!

Angular JS form running only first time

I am at the very beginning with my Angular learning and I implemented this form:
http://codepen.io/jgrecule/pen/WxgqqO
What it is supposed to do is very basic: it consumes Flickr public JSONP feed as per Flicker specs https://www.flickr.com/services/feeds/docs/photos_public/ and renders the retrieved pictures thumbnails
The form I implemented has a submit button as well as a reset one. My problems I am trying too find solutions in the order of their importance are:
The very first time when you typing tags everything works but when u try to submit the request again by either adding a new tag or an user Id or anything it no longer works. I can see this warning in the logs but I have no idea what is causing it WARNING: Tried to load angular more than once.
The reset only works for the thumbnails but not for the other controls in my page
I would like to find a way to show an error message when the user pushes on the search flicker button and both tags and user ids input fields are empty. I tried to implement a custom directive but it was no way to get it working.
Thank you in advance for your inputs.
You are loading Angular more than once.
Your resetForm function doesn't reset the form at all. It just calls $setValidity on two of the form elements. It looks like it does try and reset the form in another part of your code with
document.getElementById("searchCriteriaTags").innerHTML = "";
document.getElementById("searchCriteriaIds").innerHTML = "";
document.getElementById("images").innerHTML = "";
which means you are modifying the DOM directly, about which see point 4.
You can add a simple check as to whether $scope.form.tags === '' and so the same for the other fields in your form.
Having addressed your 3 points, I'm afraid to say your code has bigger problems. You are modifying the DOM directly all over the place and you have a lot of duplicate code, plus lots of very complex conditionals.
EDIT 1 in response to OP's comment:
The Angular way of clearing form fields would be to simply clear the scope objects that the form fields are bound to. In other words it is as simple as doing something like:
$scope.tags = [] // for arrays
$scope.name = '' // for strings
Because the form fields are bound to these scope variables through the ng-model directive, changing the variables will also change the form fields.
Setting an error message when two fields are empty you can do like this:
$scope.checkFields = function(field1, field2) {
var oneEmpty = field1 === '';
var twoEmpty = field2 === '';
if (oneEmpty && twoEmpty) {
// call the failure message here
}
}
EDIT 2 in response comments:
Firstly good to see that your code is looking a lot cleaner. Secondly, the reason it fails is because in your search function you set the search fields to null, eg searchCriteria.tags = null;. You should set them to empty strings instead: searchCriteria.tags = '';.
I don't know what the purpose of checkFields is so I don't know where you want to place it. If you want to show an error message if the fields are empty then I'd say have checkFields() return a boolean and use ng-show to display the error div if checkFields() === false.
HTML:
<div ng-show="checkFields() === false">Fields can't be empty</div>
JS:
$scope.checkFields = function(field1, field2) {
var oneEmpty = field1 === '';
var twoEmpty = field2 === '';
return (oneEmpty || twoEmpty);
}

Clear validation error messages after errors have been corrected

I have a custom validator in asp.net that validates address client side, which works perfectly. Except, when i correct the error by filling up the text box, the error message doesn't disappear like it does for required field validators. The reason i use a custom validation is because i have separate boxes for street name, number, suburb etc and want to validate all of them at once.
Here is my JS:-
function ValidateAddress(src, args) {
var unit = document.getElementById('TextUnit');
var street = document.getElementById('TextStreet');
var sub = document.getElementById('TextSuburb');
var pc = document.getElementById('TextPC');
if (unit.value == "" || street.value == "" || sub.value == "" || pc.value == "")
{ args.IsValid = false; }
else { args.IsValid = true;}
}
Is there a way of making the error message disappear without using jquery? I solely have to use JS or HTML
It looks like your ValidateAddress function is called from somewhere else - probably a hook your validation framework has put on the form submit action or something similar. If your validation framework is handling re-validation of most of your controls after they have changed, it must be hooking the onchange event for those controls somehow. You will need to investigate how your validation framework is finding the controls it needs to watch for changes and update your address controls so that your validation framework detects and monitors them. Once your validation framework is handling onchange events for your address input controls the validation will be re-run and the error cleared when the user enters enough information.
Without more details about what validation framework you're using - or if you're using a homegrown validation framework, as seems likely - it'll be hard to give you a more specific answer.

POST JSON to controller with jquery and also use built in validation

I have a form which collects some data, most importantly an address which needs to be geocoded to obtain the lat and long.
Suppose the user inputs something like:
123 main st
SomEwheRE, NY 12345
My client-side javasript goes out to the Google Geocoding service and attempts to get the lat and long for that address. In return I also get back more addition information including the properly formatted address:
123 Main St
Somewhere, NY 12345
What I want to do is replace the values in their respective textboxes so that the user can verify the data is good and then finally submit via jQuery.post("My/Controller/", myJSONData, function(){}); but I'm getting some strange behavior.
If I type in an address and don't include a zip code (it's required in the database but not necessary to geocode the address) I get a validation error. The thing is I would like to defer validation until after I obtain the information from the geocode service and replace the values in the textbox.
Right now, if I only type in a partial address (and hit "Submit") this is what happens:
Validation errors occur on the missing required fields and all my textboxes go blank
Hit submit again and this time the textboxes are properly filled in with the geocoded information BUT ALL fields produce validation errors.
Hit submit a 3rd time and now the validation errors go away and everything is as expected. At this point, I want to consider the form valid and allow the POST to the Controller.
Code:
$(document).ready(function () {
$("form").submit(function (e) {
e.preventDefault();
var geoCodedAddress = geoCodeAddress($("#Address1").val(), $("#City").val(), $("#State").val());
console.log(geoCodedAddress);
geoCodedAddress.Name = $("#Name").val();
geoCodedAddress.Phone = $("#Phone").val();
$("#Address1").val(geoCodedAddress.Address1);
$("#City").val(geoCodedAddress.City);
$("#State").val(geoCodedAddress.State);
$("#ZipCode").val(geoCodedAddress.ZipCode);
});
});
geoCodeAddress() returns the JSON object with the required fields filled in and that works. I believe the problem lies somewhere between my ineptitude and the block of code I posted.
Well, after much tinkering this is what I came up with. Basically, when someone hits submit (or enter) I stop the form from being submitted (by e.preventDefault()) and check to see if it's valid. If the form data is valid, I then process what the user entered, fill in the form fields with the acquired data (this doesn't do anything functional, it just flashes the new data in the form). I couldn't figure out how to submit the form, so I posted it myself using $.post(). If there is a better way please leave a comment or answer and I will vote. Here is my complete code:
$(document).ready(function () {
$("form").submit(function (e) {
e.preventDefault();
if ($("form").valid()) {
geoCodeAddress($("#Address1").val(), $("#City").val(), $("#State").val(), function (geoCodedAddress) {
geoCodedAddress.Name = $("#Name").val();
$("#Address1").val(geoCodedAddress.Address1);
$("#City").val(geoCodedAddress.City);
$("#State").val(geoCodedAddress.State);
$("#ZipCode").val(geoCodedAddress.ZipCode);
$("#Longitude").val(geoCodedAddress.Longitude);
$("#Latitude").val(geoCodedAddress.Latitude);
$.post("/Controller/Action/", geoCodedAddress, function () { $(window).attr("location", "/Controller/"); });
});
}
});
});

Check the form has saved or not in CRM 2011 Javascript

I'm writing a Javascript to call external link on click of custom ribbon button in CRM 2011 entity form. In javascript I'm checking the form is dirty or not. If the form is dirty,(means some fields are modified by user) then JScript will save the form forcefully using Xrm.Page.data.entity.save(). But, when the mandatory fields have not filled, force save will not be happened and I have to show some custom message to fill those fields, terminate the flow of control and should not open the external link. How to get whether the form has saved or not..?
Piece of code as below:
function buttonOnClick() {
if (Xrm.Page.data.entity.getIsDirty())
{
Xrm.Page.data.entity.save();
}
else
{
window.open('http://www.google.com', 'name', 'width=900,height=800');
}
}
When you say 'form has been saved' do you mean for the first time? If so you can query the form type:-
Xrm.Page.ui.getFormType();
(Is it in Create or Update for example). If the form is already in Update mode then you can check if the form is dirty as you say. If you want to know which mandatory fields have not been completed you can also potentially loop over the attributes on the form and query whether they are Business Required or not:-
Xrm.Page.data.entity.attributes.get("myAttribute").getRequiredLevel();
and add this to a warning message to the user.
You could add your own OnSave method to validate the fields and return a value based on whether they are valid or not.
e.g.
Xrm.Page.data.entity.addOnSave(function() {
var isValid = VerifyOnSave();
if (isValid) {
//continue
}
else {
//show errors, cancel save
}
);
function VerifyOnSave()
{
//<insert validation logic here>
return true;
}
That doesn't explicitly tell you the form saved, but lets you know whether the form is valid, which may or may not be close enough.
You could try this way:
var entitySaved;
function OnLoad(){
entitySaved=false;
}
function OnSave(){
entitySaved=true;
}
function myFunction(){
if(entitySaved){
//do your logic here
}
}
Of course, you will have to add the form events from your CRM solution, by clicking in form properties.

Categories

Resources