i m using dojo toolkit as design with codeigniter.
I am using dojo dialog as input form for particular module
The problem which i am facing is that, dojo validates only the initial input field and rest fields are not validated in the form.
I am using following function to validate text fields of form :
function dialogpartyclose()
{
if(dijit.byId('txtpartyname').validate() == false)
{
dijit.byId('txtpartyname').validate(true);
}
if(dijit.byId('txtpartyfirstname').validate() == false)
{
dijit.byId('txtpartyfirstname').validate(true);
}
if(dijit.byId('txtpartylastname').validate() == false)
{
dijit.byId('txtpartylastname').validate(true);
}
if(dijit.byId('txtpartymobile').validate() == false)
{
dijit.byId('txtpartymobile').validate(true);
}
if(dijit.byId('txtpartyfax').validate() == false)
{
dijit.byId('txtpartyfax').validate(true);
}
if(dijit.byId('txtpartyphone').validate() == false)
{
dijit.byId('txtpartyphone').validate(true);
}
if(dijit.byId('txtpartyemail').validate() == false)
{
dijit.byId('txtpartyemail').validate(true);
}
if(dijit.byId('txtpartycity').validate() == false)
{
dijit.byId('txtpartycity').validate(true);
}
if(dijit.byId('txtpartystate').validate() == false)
{
dijit.byId('txtpartystate').validate(true);
}
if(dijit.byId('txtpartycountry').validate() == false)
{
dijit.byId('txtpartycountry').validate(true);
}
}
now if i will click on submit button once,it will validate input fields.
if i close input form and reopen it then all fields are marked red meaning that last validation of fields are not put into its initial stage and last stage of input form is as it is. The problem is that it validates only the first field while reopening form and rest fields are red marked.
Plz helppppppppp
Thnx in advance
Are you using dijit.form.ValidationTextBox and dijit.form.Form for the input fields and the form.
If so, you do not need the dialogpartyclose() method that seems to be validating all the fields.
Upon submit, dijit.form.Form will invoke the validator function on each of the dijit form fields
For example:
<input type="text"
name="txtpartyname"
id="txtpartyname"
dojoType="dijit.form.ValidationTextBox"
required="true"
constraints="{'constraint1': 'value1'}"
validator=validateName
intermediateChanges=false
invalidMessage="Please enter a valid name. Name must be...." />
Then, you can implement your own validator function as:
function validateName(value, constraints)
{
var isValid = false;
//do the validation here
if ( <name validation code here>)
{
isValid = true;
}
//constraints are optional - they get passed into the validator function
if(constraints && constraints['constraint1'] != null) {
//do constraints based processing if required
}
return isValid;
}
This should take care of proper validations. These validations should only occur when user clicks the submit button
When you close and re-open the dialog, validations will not be run by dijit.form.Form
If you are using a mix of dijit Form input elements and regular HTML input elements you can wire your own validate() function at the form level
Related
I have succesfully rendered my own component as the cellEditor and would like and on-leave I would like it to try to validate the value and prevent the closing if it fails.
If I look at this then https://www.ag-grid.com/javascript-grid-cell-editing/#editing-api there's cancelable callback functions for editing. But in this callback function is there a way to access the current instantiated component? I would think that would be the easiest way to handle this.
I'm using vee-validate so the validation function is async, just to keep in mind.
Use Full row editing.
Create a global variable like
var problemRow = -1;
Then Subscribe to this events:
onRowEditingStarted: function (event) {
if (problemRow!=-1 && event.rowIndex!=problemRow) {
gridOptions.api.stopEditing();
gridOptions.api.startEditingCell({
rowIndex: problemRow,
colKey: 'the column you want to focus',
});
}
},
onRowEditingStopped: function (event) {
if (problemRow==-1) {
if (event.data.firstName != "your validation") {
problemRow = event.rowIndex
gridOptions.api.startEditingCell({
rowIndex: problemRow,
colKey: 'the column you want to focus',
});
}
}
if (problemRow == event.rowIndex) {
if (event.data.firstName != "your validation") {
problemRow = event.rowIndex
gridOptions.api.startEditingCell({
rowIndex: problemRow,
colKey: 'the column you want to focus',
});
}
else{
problemRow=-1;
}
}
},
I had a similar issue - albeit in AngularJS and the non-Angular mode for ag-grid - I needed to prevent the navigation when the cell editor didn't pass validation.
The documentation is not very detailed, so in the end I added a custom cell editor with a form wrapped around the input field (to handle the niceties such as red highlighting etc), and then used Angular JS validation. That got me so far, but the crucial part was trying to prevent the user tabbing out or away when the value was invalid so the user could at least fix the issue.
I did this by adding a value parser when adding the cell, and then within that if the value was invalid according to various rules, throw an exception. Not ideal, I know - but it does prevent ag-grid from trying to move away from the cell.
I tried loads of approaches to solving this - using the tabToNextCell events, suppressKeyboardEvent, navigateToNextCell, onCellEditingStopped - to name a few - this was the only thing that got it working correctly.
Here's my value parser, for what it's worth:
var codeParser = function (args) {
var cellEditor = _controller.currentCellEditor.children['codeValue'];
var paycodeId = +args.colDef.field;
var paycodeInfo = _controller.paycodes.filter(function (f) { return f.id === paycodeId; })[0];
// Check against any mask
if (paycodeInfo && paycodeInfo.mask) {
var reg = new RegExp("^" + paycodeInfo.mask + '$');
var match = args.newValue.match(reg);
if (!match) {
$mdToast.show($mdToast.simple().textContent('Invalid value - does not match paycode format.').position('top right').toastClass('errorToast'))
.then(function(r) {
_controller.currentCellEditor.children['codeValue'].focus();
});
throw 'Invalid value - does not match paycode format.';
}
}
return true;
};
The _controller.currentCellEditor value is set during the init of the cell editor component. I do this so I can then refocus the control after the error has been shown in the toast:
CodeValueEditor.prototype.init = function (params) {
var form = document.createElement('form');
form.setAttribute('id', 'mainForm');
form.setAttribute('name', 'mainForm');
var input = document.createElement('input');
input.classList.add('ag-cell-edit-input');
input.classList.add('paycode-editor');
input.setAttribute('name', 'codeValue');
input.setAttribute('id', 'codeValue');
input.tabIndex = "0";
input.value = params.value;
if (params.mask) {
input.setAttribute('data-mask', params.mask);
input.setAttribute('ng-pattern','/^' + params.mask + '$/');
input.setAttribute('ng-class',"{'pattern-error': mainForm.codeValue.$error.pattern}");
input.setAttribute('ng-model', 'ctl.currentValue');
}
form.appendChild(input);
this.container = form;
$compile(this.container)($scope);
_controller.currentValue = null;
// This is crucial - we can then reference the container in
// the parser later on to refocus the control
_controller.currentCellEditor = this.container;
$scope.$digest();
};
And then cleared in the grid options onCellEditingStopped event:
onCellEditingStopped: function (event) {
$scope.$apply(function() {
_controller.currentCellEditor = null;
});
},
I realise it's not specifically for your components (Vue.js) but hopefully it'll help someone else. If anyone has done it a better way, I'm all ears as I don't like throwing the unnecessary exception!
When I hover the mouse on button, then many options are displayed. Now I want to validate that all the options are displayed or not at single time.
static content = {
timeRangeContainer { $("div.filter-list")[0] }
timeRangeFilterOptions { timeRangeContainer.find ("div.filter-drop li")}
}
def hovermouse(){
interact{
moveToElement(timeRangeFilterButton)
}
def optionDisplayed(){
timeRangeFilterOptions[0].isDisplayed()
}
}
In the above example, I can check only one element whether it displayed or not , But I want to check all the options are displayed or not at single line of code such as (timeRangeFilterOptions.isDisplayed()). Is it possible ?
One way to do it would be:
boolean optionsDisplayed(){
timeRangeFilterOptions*.displayed.every()
}
I'm using, vue-js and element-ui
I would like to check the state of the validation of a form without having to click on a submit button
Example
https://jsfiddle.net/nw8mw1s2/
Steps to reproduce
Click on each field
The verification is triggered with the blur
Start filling the different inputs
Question
How can I do so when the last input is validated, isFormValidated turns to true.
In other words, how can I say "If there is no field with the state error, then turn valudateState to true"
Tips
I guess we can check the validateState of each formItem of the form. But I do not see how to do it concretely.
I would create a new method (say updateIsFormValidated), and bind it to the native focusout event of the form:
<el-form :model="ruleForm2" #focusout.native="updateIsFormValidated" ...>
This method will fire each time any of the inputs in the form loses focus. It will attempt to check that each field in the form component has successfully been validated, firing each 100 milliseconds if the validation status of any of the form items is still pending:
updateIsFormValidated() {
let fields = this.$refs.ruleForm2.fields;
if (fields.find((f) => f.validateState === 'validating')) {
setTimeout(() => { this.updateIsFormValidated() }, 100);
} else {
this.isFormValidated = fields.reduce((acc, f) => {
let valid = (f.isRequired && f.validateState === 'success');
let notErroring = (!f.isRequired && f.validateState !== 'error');
return acc && (valid || notErroring);
}, true);
}
}
Here's a working fiddle.
I have a large Dijit-based form with many Dijits in collapsible TitlePanes.
When the form validates, any invalid items hidden inside closed TitlePanes (obviously) cannot be seen. So it appears as though the form is just dead and won't submit, though, unbeknownst to the user, there's actually an error hidden in a closed TitlePane which is preventing the form processing.
What's the solution here? Is there an easy way to simply open all TitlePanes containing Dijits that are in an error state?
If validation is done by following, it will work:-
function validateForm() {
var myform = dijit.byId("myform");
myform.connectChildren();
var isValid = myform.validate();
var errorFields = dojo.query(".dijitError");
errorFields.forEach(fieldnode){
var titlePane = getParentTitlePane(fieldnode);
//write a method getParentTitlePane to find the pane to which this field belongs
if(titlePane) {
titlePane.set('open',true);
}
}
return isValid;
}
function getParentTitlePane(fieldnode) {
var titlePane;
//dijitTitlePane is the class of TitlePane widget
while(fieldnode && fieldnode.className!="dijitTitlePane") {
fieldnode= fieldnode.parentNode;
}
if(fieldnode) {
mynode = dijit.getEnclosingWidget(fieldnode);
}
return titlePane;
}
Lets say if the following is the HTML and we call the above validateForm on submit of form.
<form id="myform" data-dojo-type="dijit/form/Form" onSubmit="validateForm();">
......
</form>
Here's what I ended up doing (I'm not great with Javascript, so this might sucked, but it works -- suggestions for improvement are appreciated):
function openTitlePanes(form) {
// Iterate through the child widgets of the form
dijit.registry.findWidgets(document.getElementById(form.id)).forEach(function(item) {
// Is this a title pane?
if (item.baseClass == 'dijitTitlePane') {
// Iterate the children of this title pane
dijit.registry.findWidgets(document.getElementById(item.id)).forEach(function(child) {
// Does this child have a validator, and -- if so -- is it valid?
if (!(typeof child.isValid === 'undefined') && !child.isValid()) {
// It's not valid, make sure the title pane is open
item.set('open', true);
}
});
}
});
}
I'm basically trying to create a multi-step form using the CActiveForm class in Yii. The idea is I want to use the built-in functionality to achieve this in the simplest way possible. The requirement I have is as follows:
A multi step ONE PAGE form (using DIVs that show/hide with jQuery)
AJAX validation on EACH step (validate step-specific attributes only)
The validation MUST work using the validateOnChange() and validateOnSubmit() methods
This is a half-working solution I have developed so far:
View:
<div class="form">
<?php $form = $this->beginWidget('CActiveForm', array(
'id'=>'listing-form',
'enableClientValidation'=>false,
'enableAjaxValidation'=>true,
'clientOptions'=>array(
'validateOnChange'=>true,
'validateOnSubmit'=>true,
'afterValidate'=>'js:validateListing',
),
)); ?>
<?php echo $form->errorSummary($model); ?>
<div class="step" id="step-1">
// model input fields
<?php echo CHtml::submitButton('Next Step', array('name'=>'step1')); ?>
</div>
<div class="step" id="step-2" style="display: none;">
// model input fields
<?php echo CHtml::submitButton('Next Step', array('name'=>'step2')); ?>
</div>
<div class="step" id="step-3" style="display: none;">
// model input fields
<?php echo CHtml::submitButton('Submit', array('name'=>'step3')); ?>
</div>
<?php $this->endWidget(); ?>
</div>
JavaScript:
function validateListing(form, data, hasError)
{
if(hasError)
{
// display JS flash message
}
else
{
if($('#step-1').css('display') != 'none')
{
$('#step-1').hide();
$('#step-2').show();
}
else if($('#step-2').css('display') != 'none')
{
$('#step-2').hide();
$('#step-3').show();
}
else if($('#step-3').css('display') != 'none')
{
return true; // trigger default form submit
}
}
}
Controller:
public function actionCreate()
{
$model = new Listing;
// step 1 ajax validation
if(isset($_POST['step1']))
{
$attributes = array('name', 'address1', 'etc');
$this->performAjaxValidation($model, $attributes);
}
// step 2 ajax validation
if(isset($_POST['step2']))
{
$attributes = array('category', 'type', 'etc');
$this->performAjaxValidation($model, $attributes);
}
// step 3 ajax validation
if(isset($_POST['step3']))
{
$attributes = array('details', 'source', 'etc');
$this->performAjaxValidation($model, $attributes);
}
// process regular POST
if(isset($_POST['Listing']))
{
$model->attributes = $_POST['Listing'];
if($model->validate()) // validate all attributes again to be sure
{
// perform save actions, redirect, etc
}
}
$this->render('create', array(
'model'=>$model,
));
}
protected function performAjaxValidation($model, $attributes=null)
{
if(isset($_POST['ajax']) && $_POST['ajax']==='listing-form')
{
echo CActiveForm::validate($model, $attributes);
Yii::app()->end();
}
}
To summarise. Basically what I have is a form with 3 submit buttons (one for each step). In my controller I check which submit button was pressed and I run AJAX validation for the attributes specific to that step.
I use a custom afterValidate() function to show/hide the steps upon submit. On step 3, the default form submit is triggered, which posts all the form attributes to the controller.
This works well, except it won't work with validateOnChange() (since the submit button doesn't get posted). Also I was wondering whether this is actually the best way to do this, or if anyone knows of a better way?
Thanks.
I'd suggesting using scenarios to turn on and off the appropriate rules. Adjust the model scenario based on what is sent to your controller.
Note: this may also be a really good place to use a CFormModel instead of a CActiveRecord, depending on what is in your form.
Edit: can you add a hidden field to each div section that contains the info about what step you are on? Seems like that should work instead of your submit buttons.
OPTION 1
When you do not receive a button, why not validate the entire form, why do you need to validate only specific attributes? Yii will validate the entire model, send back all the errors but only that particular error will be shown by the active form because that is how it works already.
OPTION 2
You can have 3 forms (not 1 like you have now), 1 on each step. Also create 3 scenarios 1 for each step.
Each form has a hidden field that gets posted with the form, it can actually be the scenario name just validate it when it comes in. Validate the model using this hidden field to set the scenario you are on.
You can cache parts on the model when the form is submitted successfully and at the end you have the complete model.
you can always have custom validation and it won't break your normal form validation
in your model
private $step1 = false;
private $step2 = false;
private $all_ok = false;
protected function beforeValidate()
{
if(!empty($this->attr1) && $this->attr2) // if the fields you are looking for are filled, let it go to next
{
$this->step1 = true;
}
if($this->step1)
{
... some more validation
$this->step2 = true;
}
if($this->step2)
{
... if all your logic meets
$this->all_ok = true;
}
// if all fields that your looking for are filled, let parent validate them all
// if they don't go with their original rules, parent will notify
if($this->all_ok)
return parent::beforeValidate();
$this->addError($this->tableSchema->primaryKey, 'please fillout the form correctly');
return false;
}
I think better create specific class for each step of validation and use scenarios with rules. Below is small example.
//protected/extensions/validators
class StepOneMyModelValidator extends CValidator
{
/**
* #inheritdoc
*/
protected function validateAttribute($object, $attribute)
{
/* #var $object YourModel */
// validation step 1 here.
if (exist_problems) {
$object->addError($attribute, 'step1 is failed');
}
...
Create other classes(steps) for validation...
// in your model
public function rules()
{
return array(
array('attr', 'ext.validators.StepOneMyModelValidator', 'on' => 'step1'),
...
How to use in controller:
$model = new Listing();
$steps = array('step1', 'step2', /* etc... */);
foreach($_POST as $key => $val) {
if (in_array($key, $steps)) {
$model->setScenario($key);
break;
}
}
$model->validate();
echo '<pre>';
print_r($model->getErrors());
echo '</pre>';
die();
Or we can validate all steps in one validator.