Validation

Allikas: Juhised

Description[muuda]

We use the validation of form fields two times. First, the fields will be validated on the client's side without a need to make any new requests to the server. Second, the fields will be validated on the server's side in order to ensure the correctness.

On the client's side[muuda]

Description[muuda]

On the client's side, we use JavaScript for the validation. Our chosen validation framework is Validanguage 1.0.2. Although it is a third-party software we have to have made some changes into it manually. So that be careful while updating to a newer version by comparing the source codes!

Form[muuda]

In the form we define all the fields. Every field that Validanguage uses must have an id:

							<input id="conditions" name="conditions" type="checkbox"{CHECKED-CONDITIONS}/>

The given id will be used by Validanguage's element definitions.

Directly after the form-element we use a script-element and describe the needed validations:

  1. validanguage.el =
  2. {
  3.  
  4. 	conditions:
  5. 	{
  6. 		errorMsg: 'Selleks, et liituda, pead olema nõus meie äritingimustega.',
  7. 		onblur: true,
  8. 		onclick: true,
  9. 		onsubmit: true,
  10. 		required: true
  11. 	},
  12. 	school{SUFFIX}:
  13. 	{
  14. 		validations: [{ 
  15. 			errorMsg: 'Palun vali kool.',
  16. 			name: "checkField('school', '{SUFFIX}')",
  17. 			onblur: true,
  18. 			onsubmit: true,
  19. 			required: true
  20. 		}]
  21. 	}
  22.  
  23. }

In the example, there are validations of different types:

  1. a checkbox (lines 4-11): The onclick event makes sense because the user clicks the checkbox;
  2. a user-defined validation method (lines 12-21).

Explicit JavaScript[muuda]

If we want our own function to validate a field then we define that function explicitly in our JavaScript file:

  1. function checkField(id, suffix)
  2. {
  3.  
  4. 	if (document.getElementById('Hidden_' + id + suffix).value == '')
  5. 	{
  6. 		return false;
  7. 	}
  8. 	else
  9. 	{
  10. 		return true;
  11. 	}
  12.  
  13. }
  14. The return value ''false'' gives an error message for the user.

Controller[muuda]

In the controller, it is necessary to load the needed JavaScript files:

  1. 					$schoolCardView->buildPage(
  2. 						array (
  3. 							'php', // required by getPathToRootDir
  4. 							'sport', // for getting the root dir path
  5. 							'tooltip', // for menus
  6. 							'validanguage' // for the form field validation
  7. 						),
  8. 						$page,
  9. 						array (
  10. 							'validanguage' // for the form field errors
  11. 						),
  12. 						'NewsInAdmin',
  13. 						FALSE,
  14. 						$news,
  15. 						FALSE,
  16. 						$pos
  17. 					);

If we use a user-defined function then we need sport.js, too (line 4).

For the error messages, the system has to load validanguage.css, too (line 10).

Toggling[muuda]

Once, I discovered a deficiency in Validanguage's manual I informed about it its developer:

You can test it: http://ikka.mine.nu/sooduskaart/haldus/kasutajad/?users&function=buildFormOfAddingUser

Kalmer Piiskop wrote:

Hi again![muuda]

I landed in a situation where I needed to display different fields in the same form according to the value of a field. It is a form that makes possible to create an account. There are some common fields and other fields depend on the type of the user: either a human or a company. By choosing human for the type, it was not possible to submit the form because of failed fields in the company part that were invisible. Then I found in the advanced features that Validanguage supports visibility toggling.

I spent many hours to test the toggling functionality and the final result with only using the information provided on the web site of Validanguage was working toggling only with comment-based API. But I use the JSON-API. I do not know what do you mean by complexity by using JSON-API. Maybe you can explain it. But I spent many more hours to find a solution for JSON-API.

Earlier, I used a-elements for toggling between the form parts. Now, I created two radio buttons into the same form:

                <input id="userTypeContact" name="userType" type="radio" value="contact"{CONTACT}/>
                <label for="userTypeContact">ettevõtja</label>
                <input id="userTypePupilStudent" name="userType" type="radio" value="pupil/student"{HUMAN}/>
                <label for="userTypePupilStudent">õpilane/tudeng</label>

Next, I wanted to set the conditions for toggling:

validanguage.el =
{
    userTypeContact:
    {
        onclick: validanguage.toggle,
    },
    userTypePupilStudent:
    {
        onclick: validanguage.toggle,
    }
}

I did also set the array of conditions but unfortunately, it ended up either by complaining about missing toggleArgs or with this result:

this.$(id) is undefined

anonymous(Object name=id)validang...ressed.js (line 871)

anonymous([Object target=formForInsertingContact toggle=Object, Object target=formForInsertingHuman toggle=Object])validang...ressed.js (line 1902)

function onclick(event) { validanguage.toggle(togglingConditions.userTypePupilStudent); }(click clientX=440, clientY=313)kasutaja...ent/seq/2 (line 2)

[Break on this error] var formName = ( this.$(id).nodeName.toLowerCase()=='form' ) ? \n

Somehow it should be possible to tell Validanguage both the conditions as the radio button element. It did not work by giving these parameters in the parenthesis to the function call. It did neither work by writing the onclick event directly into the input box definition. What I then did was:

validanguage.togglingConditions =
{
    userTypeContact:
    [
        {
            target: 'formForInsertingHuman',
            toggle:
            {
                visible: 'unchecked'
            }
        },
        {
            target: 'formForInsertingContact',
            toggle:
            {
                visible: 'checked'
            }
        }
    ],
    userTypePupilStudent:
    [
        {
            target: 'formForInsertingContact',
            toggle:
            {
                visible: 'unchecked'
            }
        },
        {
            target: 'formForInsertingHuman',
            toggle:
            {
                visible: 'checked'
            }
        }
    ]
}

In order the function toggle to read the correct array I added the following line into the toggle function to the very beginning:

    toggleArgs = validanguage.togglingConditions[this.id];

Now, Validanguage knew about the conditions and also the radio button was known for it. What I also wanted was to hide both the company (contact) and human part after the page loading. Your example as shown below did not do anything:

<script type="text/javascript">
    // Hide all 3 checkboxes onload if none are checked
    validanguage.settings.onload = function() {
        if (!document.getElementById('radio1').checked) 
    }
</script>

I wanted to simulate the onclick event after the page loading but it had no influence to Validanguage. Then I wrote the following lines:

if (document.getElementById('userTypeContact') && document.getElementById('userTypeContact').checked)
{
    validanguage.toggleDisplay("formForInsertingPupilStudent", "none");
}
if (document.getElementById('userTypePupilStudent') && document.getElementById('userTypePupilStudent').checked)
{
    validanguage.toggleDisplay("formForInsertingContact", "none");
}

I am not sure whether my solution is good enough for you to fulfill the web site documentation with this example but it works or at least seams to work (FF). If you have a better solution please update me about it.

--

Kalmer Piiskop, MSc.

Eduard Vilde tee 53-96

EE13412 Tallinn

European Union

+372  652 4228

+372  5620 4556

callto://pandeero

Danske Bank A/S Eesti filiaal (FORE EE 2X): 336314570000

Hansapank (S.W.I.F.T.: HABA EE2X): 1107112667 (IBAN: EE182200001107112667)

__________________________________________________________________


--

Kalmer Piiskop, MSc.

Eduard Vilde tee 53-96

EE13412 Tallinn

European Union

+372  652 4228

+372  5620 4556

callto://pandeero

Danske Bank A/S Eesti filiaal (FORE EE 2X): 336314570000

Hansapank (S.W.I.F.T.: HABA EE2X): 1107112667 (IBAN: EE182200001107112667)

__________________________________________________________________

On the server's side[muuda]

Form[muuda]

Autocompletion[muuda]

  1. 							<div id="inf_school">
  2. {ERROR-OF-SCHOOL}
  3. 							</div>
  4.  
  5. 							<input id="suffix" name="suffix" type="hidden" value="{SUFFIX}"/>
  6.  
  7. 							<input id="school{SUFFIX}"
  8. 									name="school{SUFFIX}"
  9. title="Kui hakkad kirjutama, ilmub olemasolevate koolide nimekiri, millest tuleb kool valida.
  10. Kui sinu kooli nimekirjas pole, siis saad selle lisada vajutades koolide nupule."
  11. 									type="text" value="{VALUE-OF-SCHOOL}"/>
  12.  
  13. 							<input id="Hidden_school{SUFFIX}"
  14. 									name="Hidden_school{SUFFIX}"
  15. 									type="hidden"
  16. 									value="{HIDDEN-VALUE-OF-SCHOOL}"/>

Files[muuda]

  1. 							<div id="inf_doc" class="viga">
  2. {ERROR-OF-DOCUMENT}
  3. 							</div>
  4.  
  5. 							<img id="imgODocInForm"
  6. 									src="{SRC-OF-IMAGE-OF-DOCUMENT-IN-FORM}" alt=""
  7. 									{SIZES-OF-IMAGE-OF-DOCUMENT-IN-FORM}/>
  8.  
  9. <!-- BEGIN non-image-file -->
  10. 						<a href="{HREF}" target="doc">{FILE-NAME}<a/>
  11. <!-- END non-image-file -->
  12.  
  13. 							<input id="imgODocInFormHidden"
  14. 									name="imgODocInFormHidden" type="hidden"
  15. 									value="{PATH-TO-PREVIEW-IMAGE}"/>
  16.  
  17. 							<iframe
  18. src="?module=images&amp;function=buildFormForUploadingImage&amp;idsOImgFields[]=imgODocInForm&amp;idsOImgFields[]=iconForRemovingImgFromSchoolCard&amp;pathToFinalFolder={PATH-TO-FINAL-FOLDER}&amp;obj=document_of_school_card&amp;idObj={ID-OF-SCHOOL-CARD}&amp;idHuman={ID-OF-HUMAN}&amp;pathToImages={PATH-TO-IMAGES}{CONDITIONS}"
  19. 									frameborder="0"></iframe>
  20.  
  21. 							<img id="iconForRemovingImgFromSchoolCard"
  22. 									alt="Eemalda dokumendipilt!"
  23. 									title="Eemalda dokumendipilt!"
  24. 									class="DrasticImg"
  25. 									onclick="delImgFromSystem('{URL}', ['imgODocInForm'], this)"
  26. 									onmouseover="this.src = '{PATH-TO-IMAGES}del2.gif';"
  27. 									onmouseout="this.src = '{PATH-TO-IMAGES}del.gif';"
  28. 									src="{PATH-TO-IMAGES}del.gif"
  29. 									style="visibility: {VISIBILITY-OF-ICON-FOR-REMOVING-IMAGE-FROM-SCHOOL-CARD};"/>

View[muuda]

Autocompletion[muuda]

First, we define the values:

		$valOSchool = '';
		$hiddenValOSchool = '';
 
		if (isset ($validatedElements))
		{
 
			$hiddenFieldOSchool = sprintf(
				'Hidden_school%1$s',
				$validatedElements['suffix']->value
			);
 
			$fieldOSchool = sprintf(
				'school%1$s',
				$validatedElements['suffix']->value
			);
 
		}
 
		if (!isset ($validatedElements) && isset ($schoolCard->idSchool))
		{
			require_once dirname(__FILE__) . '/../haldus/kasutajad/School.php';
 
			$school = new School($schoolCard->idSchool);
 
			$valOSchool = $school->name;
			$hiddenValOSchool = $school->idSchool;
		}
		else if (isset ($validatedElements) && isset ($validatedElements[$fieldOSchool]->value))
		{
			$valOSchool = $validatedElements[$fieldOSchool]->value;
		}
 
		if (isset ($validatedElements) && isset ($validatedElements[$hiddenFieldOSchool]->value))
		{
			$hiddenValOSchool = $validatedElements[$hiddenFieldOSchool]->value;
		}

Then, we assign the values to the template variables:

		$tplForSchoolCard->setVariable(array (
			'CONDITIONS'                                                  =>
					'&amp;conditions[]=' . implode('&conditions[]=', $conditions),
			'ERROR-OF-SCHOOL'                                             => (!isset ($validatedElements) ||
					!isset ($validatedElements[$hiddenFieldOSchool]->error)) ?
					'&#160;' : $validatedElements[$hiddenFieldOSchool]->error,
			'HIDDEN-VALUE-OF-SCHOOL'                                      => $hiddenValOSchool,
			'VALUE-OF-SCHOOL'                                             => $valOSchool
		));

Files[muuda]

		$conditions = array (
			VALIDATING_TYPE_FILE,
			VALIDATING_TYPE_UNIQUE_FILE
		);
 
		$tplForSchoolCard->setVariable(array (
			'ERROR-OF-DOCUMENT-IMAGE'                                     => (!isset ($validatedElements) ||
					!isset ($validatedElements['imgODocInFormHidden']->error)) ?
					'&#160;' : $validatedElements['imgODocInFormHidden']->error,
			'PATH-TO-FINAL-FOLDER'                                        => Support::getPathToSchoolCards()
		));

Controller[muuda]

In the beginning of the file before we start the session, there must be included the file ElementToValidate.php otherwise the system will complain about an incomplete object:

  1. require_once dirname(__FILE__) . '/../validation/ElementToValidate.php';
  2.  
  3. session_start();

For the view:

  1. 					$newsContent = $schoolCardView->buildFormForSchoolCard(
  2. 						isset ($_SESSION['elements to validate']) ? $_SESSION['elements to validate'] : NULL,
  3. 						'order',
  4. 						$userToHandle
  5. 					);
  6.  
  7. 					if (isset ($_SESSION['elements to validate']))
  8. 					{
  9. 						unset ($_SESSION['elements to validate']);
  10. 					}

For the model:

					$result = $schoolCard->order();
 
					switch ($result)
					{
 
						case UNSUCCESSFUL_VALIDATION:
						{
							require_once dirname(__FILE__) . '/../View.php';
 
							View::redirect(
								'buildFormForSchoolCardAdd&module=schoolcards&idHuman=' .
										$_GET['idHuman']
							);
 
							exit;
						}
 
						default:
						{
							require_once dirname(__FILE__) . '/../View.php';
 
							View::redirect(
								'buildFormForSchoolCardEdit&module=schoolcards&ordered'
							);
 
							exit;
						}
 
					}

Model[muuda]

Description[muuda]

  1. 		require_once dirname(__FILE__) . '/../validation/Validation.php';
  2.  
  3. 		require_once dirname(
  4. 			__FILE__
  5. 		) . '/../validation/ElementToValidate.php';
  6.  
  7. 		$validation = new Validation(array (
  8. 			new ElementToValidate('imgOPicInFormHidden', $this->pic, array (
  9. 				VALIDATING_TYPE_REQUIRED
  10. 			)),
  11. 		));
  12.  
  13. 		$validationCode = $validation->validate();
  14.  
  15. 		switch ($validationCode)
  16. 		{
  17.  
  18. 			case 0:
  19. 			{
  20. 				break;
  21. 			}
  22.  
  23. 			default:
  24. 			{
  25. 				$_SESSION['elements to validate'] = $validation->elementsToValidate;
  26.  
  27. 				return UNSUCCESSFUL_VALIDATION;
  28. 			}
  29.  
  30. 		}

In the case 0, we add the processing code. The code 0 means that everything is good.

Autocomplete[muuda]

  1. 		if (isset ($this->idSchool))
  2. 		{
  3. 			require_once dirname(__FILE__) . '/../haldus/kasutajad/School.php';
  4.  
  5. 			$school = new School($this->idSchool);
  6. 		}
  7.  
  8. 		$validation = new Validation(array (
  9. 			new ElementToValidate(
  10. 				sprintf(
  11. 					'Hidden_school%1$s',
  12. 					$this->suffix // 1
  13. 				),
  14. 				isset ($school) ? $school->idSchool : NULL,
  15. 				array (
  16. 					VALIDATING_TYPE_REQUIRED
  17. 				)
  18. 			),
  19. 			new ElementToValidate(
  20. 				sprintf(
  21. 					'school%1$s',
  22. 					$this->suffix // 1
  23. 				),
  24. 				isset ($school) ? $school->name : ''
  25. 			),
  26. 			new ElementToValidate('suffix', $this->suffix),
  27. 		));

Files[muuda]

  1. 		$validation = new Validation(array (
  2. 			new ElementToValidate(
  3. 				'conditions',
  4. 				$this->conditions,
  5. 				array (
  6. 					VALIDATING_TYPE_REQUIRED
  7. 				)
  8. 			),
  9. 			new ElementToValidate('imgOPicInFormHidden', $this->pic, array (
  10. 				VALIDATING_TYPE_REQUIRED
  11. 			))
  12. 		));

Configuration[muuda]

define('VALIDATING_TYPE_REQUIRED', 'required');

Validation class[muuda]

Into the validate-method:

					case VALIDATING_TYPE_REQUIRED:
					{
 
						if (!isset ($elementToValidate) ||
								is_array($elementToValidate->value) &&
								(sizeof($elementToValidate->value) == 0) ||
								($elementToValidate->value == '') ||
								(($elementToValidate->value == "\r\n") && ($elementToValidate->value != 1)))
						{
							$elementToValidate->error = 'Palun täida väli.';
 
							$this->elementsToValidate[$i] = $elementToValidate;
 
							$numOfErrors++;
 
							continue 3;
						}
 
						break;
					}

There, we also define custom validation methods.