Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yii2
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
PSDI Army
yii2
Commits
e2bf1120
Commit
e2bf1120
authored
Jul 31, 2014
by
Qiang Xue
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'Alex-Code-deferred-validation'
parents
201f0abb
f74e2081
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
125 additions
and
51 deletions
+125
-51
input-validation.md
docs/guide/input-validation.md
+52
-0
CHANGELOG.md
framework/CHANGELOG.md
+1
-0
yii.activeForm.js
framework/assets/yii.activeForm.js
+71
-50
ActiveField.php
framework/widgets/ActiveField.php
+1
-1
No files found.
docs/guide/input-validation.md
View file @
e2bf1120
...
...
@@ -487,6 +487,7 @@ predefined variables:
- `attribute`: the name of the attribute being validated.
- `value`: the value being validated.
- `messages`: an array used to hold the validation error messages for the attribute.
- `deferred`: an array which deferred objects can be pushed into.
In the following example, we create a `StatusValidator` which validates if an input is a valid status input
against the existing status data. The validator supports both server side and client side validation.
...
...
@@ -535,6 +536,57 @@ JS;
]
```
### Deferred validation
If you need to perform any asynchronous validation you can use a
[
deferred object
](
http://api.jquery.com/category/deferred-object/
)
.
deferred objects must be pushed to the
```deferred```
array for validation to use them.
Once any asynchronous validation has finished you must call
```resolve()```
on the Deferred object for it to complete.
This example shows reading an image to check the dimensions client side (
```file```
will be from an input of type=file).
```
php
...
public
function
clientValidateAttribute
(
$model
,
$attribute
,
$view
)
{
return
<<<JS
var def = $.Deferred();
var img = new Image();
img.onload = function() {
if (this.width > 150) {
messages.push('Image too wide!!');
}
def.resolve();
}
var reader = new FileReader();
reader.onloadend = function() {
img.src = reader.result;
}
reader.readAsDataURL(file);
deferred.push(def);
JS;
}
...
```
Ajax can also be used and pushed straight into the deferred array.
```
deferred.push($.get("/check", {value: value}).done(function(data) {
if ('' !== data) {
messages.push(data);
}
}));
```
The
```deferred```
array also has a shortcut method
```add```
.
```
deferred.add(function(def) {
//Asynchronous Validation here
//The context of this function and the first argument is the Deferred object where resolve can be called.
});
```
> Note: `resolve` must be called on any deferred objects after the attribute has been validated or the main form validation will not complete.
### Ajax validation
Some kind of validation can only be done on server side because only the server has the necessary information
...
...
framework/CHANGELOG.md
View file @
e2bf1120
...
...
@@ -165,6 +165,7 @@ Yii Framework 2 Change Log
-
Enh #4317: Added
`absoluteAuthTimeout`
to yii
\w
eb
\U
ser (ivokund, nkovacs)
-
Enh #4360: Added client validation support for file validator (Skysplit)
-
Enh #4436: Added callback functions to AJAX-based form validation (thiagotalma)
-
Enh #4485: Added support for deferred validation in
`ActiveForm`
(Alex-Code)
-
Enh #4520: Added sasl support to
`yii\caching\MemCache`
(xjflyttp)
-
Enh: Added support for using sub-queries when building a DB query with
`IN`
condition (qiangxue)
-
Enh: Supported adding a new response formatter without the need to reconfigure existing formatters (qiangxue)
...
...
framework/assets/yii.activeForm.js
View file @
e2bf1120
...
...
@@ -270,7 +270,20 @@
});
},
data
.
settings
.
validationDelay
);
};
/**
* Returns an array prototype with a shortcut method for adding a new deferred.
* The context of the callback will be the deferred object so it can be resolved like ```this.resolve()```
* @returns Array
*/
var
deferredArray
=
function
()
{
var
array
=
[];
array
.
add
=
function
(
callback
)
{
this
.
push
(
new
$
.
Deferred
(
callback
));
};
return
array
;
};
/**
* Performs validation.
* @param $form jQuery the jquery representation of the form
...
...
@@ -280,70 +293,78 @@
var
validate
=
function
(
$form
,
successCallback
,
errorCallback
)
{
var
data
=
$form
.
data
(
'yiiActiveForm'
),
needAjaxValidation
=
false
,
messages
=
{};
messages
=
{},
deferreds
=
deferredArray
();
$
.
each
(
data
.
attributes
,
function
()
{
if
(
data
.
submitting
||
this
.
status
===
2
||
this
.
status
===
3
)
{
var
msg
=
[];
messages
[
this
.
id
]
=
msg
;
if
(
!
data
.
settings
.
beforeValidate
||
data
.
settings
.
beforeValidate
(
$form
,
this
,
msg
))
{
if
(
this
.
validate
)
{
this
.
validate
(
this
,
getValue
(
$form
,
this
),
msg
);
this
.
validate
(
this
,
getValue
(
$form
,
this
),
msg
,
deferreds
);
}
if
(
msg
.
length
)
{
messages
[
this
.
id
]
=
msg
;
}
else
if
(
this
.
enableAjaxValidation
)
{
if
(
this
.
enableAjaxValidation
)
{
needAjaxValidation
=
true
;
}
}
}
});
if
(
needAjaxValidation
&&
(
!
data
.
submitting
||
$
.
isEmptyObject
(
messages
)))
{
// Perform ajax validation when at least one input needs it.
// If the validation is triggered by form submission, ajax validation
// should be done only when all inputs pass client validation
var
$button
=
data
.
submitObject
,
extData
=
'&'
+
data
.
settings
.
ajaxParam
+
'='
+
$form
.
prop
(
'id'
);
if
(
$button
&&
$button
.
length
&&
$button
.
prop
(
'name'
))
{
extData
+=
'&'
+
$button
.
prop
(
'name'
)
+
'='
+
$button
.
prop
(
'value'
);
$
.
when
.
apply
(
this
,
deferreds
).
always
(
function
()
{
//Remove empty message arrays
for
(
var
i
in
messages
)
{
if
(
0
===
messages
[
i
].
length
)
{
delete
messages
[
i
];
}
}
$
.
ajax
({
url
:
data
.
settings
.
validationUrl
,
type
:
$form
.
prop
(
'method'
),
data
:
$form
.
serialize
()
+
extData
,
dataType
:
data
.
settings
.
ajaxDataType
,
complete
:
function
(
jqXHR
,
textStatus
)
{
if
(
data
.
settings
.
ajaxComplete
)
{
data
.
settings
.
ajaxComplete
(
$form
,
jqXHR
,
textStatus
);
}
},
beforeSend
:
function
(
jqXHR
,
textStatus
)
{
if
(
data
.
settings
.
ajaxBeforeSend
)
{
data
.
settings
.
ajaxBeforeSend
(
$form
,
jqXHR
,
textStatus
);
}
},
success
:
function
(
msgs
)
{
if
(
msgs
!==
null
&&
typeof
msgs
===
'object'
)
{
$
.
each
(
data
.
attributes
,
function
()
{
if
(
!
this
.
enableAjaxValidation
)
{
delete
msgs
[
this
.
id
];
}
});
successCallback
(
$
.
extend
({},
messages
,
msgs
));
}
else
{
successCallback
(
messages
);
}
},
error
:
errorCallback
});
}
else
if
(
data
.
submitting
)
{
// delay callback so that the form can be submitted without problem
setTimeout
(
function
()
{
if
(
needAjaxValidation
&&
(
!
data
.
submitting
||
$
.
isEmptyObject
(
messages
)))
{
// Perform ajax validation when at least one input needs it.
// If the validation is triggered by form submission, ajax validation
// should be done only when all inputs pass client validation
var
$button
=
data
.
submitObject
,
extData
=
'&'
+
data
.
settings
.
ajaxParam
+
'='
+
$form
.
prop
(
'id'
);
if
(
$button
&&
$button
.
length
&&
$button
.
prop
(
'name'
))
{
extData
+=
'&'
+
$button
.
prop
(
'name'
)
+
'='
+
$button
.
prop
(
'value'
);
}
$
.
ajax
({
url
:
data
.
settings
.
validationUrl
,
type
:
$form
.
prop
(
'method'
),
data
:
$form
.
serialize
()
+
extData
,
dataType
:
data
.
settings
.
ajaxDataType
,
complete
:
function
(
jqXHR
,
textStatus
)
{
if
(
data
.
settings
.
ajaxComplete
)
{
data
.
settings
.
ajaxComplete
(
$form
,
jqXHR
,
textStatus
);
}
},
beforeSend
:
function
(
jqXHR
,
textStatus
)
{
if
(
data
.
settings
.
ajaxBeforeSend
)
{
data
.
settings
.
ajaxBeforeSend
(
$form
,
jqXHR
,
textStatus
);
}
},
success
:
function
(
msgs
)
{
if
(
msgs
!==
null
&&
typeof
msgs
===
'object'
)
{
$
.
each
(
data
.
attributes
,
function
()
{
if
(
!
this
.
enableAjaxValidation
)
{
delete
msgs
[
this
.
id
];
}
});
successCallback
(
$
.
extend
({},
messages
,
msgs
));
}
else
{
successCallback
(
messages
);
}
},
error
:
errorCallback
});
}
else
if
(
data
.
submitting
)
{
// delay callback so that the form can be submitted without problem
setTimeout
(
function
()
{
successCallback
(
messages
);
},
200
);
}
else
{
successCallback
(
messages
);
},
200
);
}
else
{
successCallback
(
messages
);
}
}
});
};
/**
...
...
framework/widgets/ActiveField.php
View file @
e2bf1120
...
...
@@ -703,7 +703,7 @@ class ActiveField extends Component
}
}
if
(
!
empty
(
$validators
))
{
$options
[
'validate'
]
=
new
JsExpression
(
"function (attribute, value, messages) {"
.
implode
(
''
,
$validators
)
.
'}'
);
$options
[
'validate'
]
=
new
JsExpression
(
"function (attribute, value, messages
, deferred
) {"
.
implode
(
''
,
$validators
)
.
'}'
);
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment