I'm using CakePHP and AngularJS and I need to validate my multi-model form.
For example, this is the way elements are created:
echo $this->Form->input(
$model . '.{{$index}}.url',
array(
'value' => '{{link.url}}',
'label' => 'URL',
'div' => array(
'class' => 'short'
)
)
);
The validation is OK. The output for:
var_dump($this->Staticpage->validationErrors)
is
array(1) { ["StaticpageLink"]=> array(1) { [1]=> array(2) { ["title"]=> array(1) { [0]=> string(27) "This is a mandatory field." } ["url"]=> array(1) { [0]=> string(27) "This is a mandatory field." } } } }
The problem is: if I use that {{$index}}
, it is evaluated correctly, but no validation message appears. If I set, for instance, 1
, the message appears.
What is the problem? What would be the correct way to evaluate an index with AngularJS?
Update: here is a more specific part of the view:
<div ng-repeat="link in links track by $index">
<div ng-hide="link.remove">
<?php
echo $this->Form->hidden(
$model . '.{{$index}}.id',
array(
'value' => '{{link.id}}'
)
);
echo $this->Form->hidden(
$model . '.{{$index}}.remove',
array(
'value' => '{{link.remove}}'
)
);
echo $this->Form->input(
$model . '.{{$index}}.title',
array(
'value' => '{{link.title}}',
'label' => 'Título',
'div' => array(
'class' => 'short'
)
)
);
//continue...
As you see, it is inside ng-repeat
.
I'm using CakePHP and AngularJS and I need to validate my multi-model form.
For example, this is the way elements are created:
echo $this->Form->input(
$model . '.{{$index}}.url',
array(
'value' => '{{link.url}}',
'label' => 'URL',
'div' => array(
'class' => 'short'
)
)
);
The validation is OK. The output for:
var_dump($this->Staticpage->validationErrors)
is
array(1) { ["StaticpageLink"]=> array(1) { [1]=> array(2) { ["title"]=> array(1) { [0]=> string(27) "This is a mandatory field." } ["url"]=> array(1) { [0]=> string(27) "This is a mandatory field." } } } }
The problem is: if I use that {{$index}}
, it is evaluated correctly, but no validation message appears. If I set, for instance, 1
, the message appears.
What is the problem? What would be the correct way to evaluate an index with AngularJS?
Update: here is a more specific part of the view:
<div ng-repeat="link in links track by $index">
<div ng-hide="link.remove">
<?php
echo $this->Form->hidden(
$model . '.{{$index}}.id',
array(
'value' => '{{link.id}}'
)
);
echo $this->Form->hidden(
$model . '.{{$index}}.remove',
array(
'value' => '{{link.remove}}'
)
);
echo $this->Form->input(
$model . '.{{$index}}.title',
array(
'value' => '{{link.title}}',
'label' => 'Título',
'div' => array(
'class' => 'short'
)
)
);
//continue...
As you see, it is inside ng-repeat
.
- 2 I believe $index is used internally inside of things like ng-repeat, and you setting them programatically isn't going to work. Also, your question is a bit vague and seems to be a PHP question rather than an angularjs question. – SoluableNonagon Commented Jan 15, 2014 at 15:39
- 3 @EliteOctagon I just added more pieces of the View, so it's possible to see that code is inside a ng-repeat. It seems that the main problem is about Cake trying to put the error messages on the elements before Angular's process of evaluating {{$index}}. – felipe.zkn Commented Jan 16, 2014 at 10:25
-
1
I don't know the syntax, but possible concept would be to
json_encode
thevalidationErrors
in your view and pass it to some JS variable accessible by AngularJs. Then in the repeat loop you can check if there is present validation error for thatindex
and display the HTML error div or not (just reuse the HTML for it from cake). Hope it helps, or somebody skilled in AngularJS can give you better guidance;) – lp1051 Commented Jan 21, 2014 at 11:11
4 Answers
Reset to default 4 +50The problem is;
You want to display server-side error validation using client-side code.
$index
is client-side code, which is AngularJS-specific javascript code.
and you want the server-side code, which is php, to understand what $index is.
The server-side, cakePHP or any php, does never know what $index means and will never know $index will be 1,2,3,4,5 or what so ever.
In php side, your code in <? ... ?>
will happen only ONCE.
When it es to client-side, then ng-repeat
will iterate by number of times for links.
so, you CANNOT validate your input in php X number of times using ng-repeat
.
Please try different approach.
---- EDIT ------
I suggest a different approach, although you may disagree.
generate client-side form without any server-side validation.
render client-side as it is generated by server-side code.
AngularJS provides lots of validation tools on client-side, use as much as possible, so that when it is submitted to server, it is as valid as possible.
However a bad user can submit your form without using your client-side code, so when it is submitted, validate user input on server-side assuming input is not always correct. You need a separate validation logic without using view(html). You can use this part as an ajax call.
If there is an error, send message back to user with error, so that client-side can display error properly. i.e. "There is unknown error with 3rd party API call"
$index - is the special angular variable, loop counter. I suppose that using it in the tracking function not the best idea...
truck by
is the way to manage loop index/sequence. E.g. you could write smth like
<div ng-repeat="link in links track by link.id">
In this way the loop counter will be id field of you links
if you want to get only loop counter (loop index) just use $index
in the code. E.g.:
<div ng-repeat="item in ['one', 'two', 'tree', 'four']">
<div>Index of {{ item }} is <b>{{ $index }}</b>
</div>
UPD
Oh my... I just see your aim. You want to have valiadtion on EACH itteration in links loop... So @allenhwkim provide a descriptive answer.
Also you could call a js function on each itteration that will send AJAX to server just for form validation and than you could show an errors given from ajax response. This way @allenhwkim mentioned too.
I wrote an AngularJS directive to add validation messages to a default response from a CakePHP 3 (RC) REST API.
Assumption is you get a JSON response containing {data:{errors:x}} (default CakePHP response):
https://gist.github./stefanvangastel/3fd27e9c02fe999dde53
Based on class selection of a Bootstrap powered template.
I managed to use $index var to name fields with regular Cake naming conventions. I used an Angular directive and a 'dynamic-name' attribute. However, i'm not sure it plays well with CakePHP magic Form input helper, so you might have to use plain old HTML syntax :
<form name="orderForm">
<div class="product" ng-repeat="product in formData.data.Product">
<div class="row">
<div class="input text" ng-class="{ 'error': orderForm[ 'data[Product][' + $index + '][number]' ].$invalid }">
<input type="text" placeholder="Product number" class="form-control" ng-model="product.number" dynamic-name="'data[Product][' + $index + '][number]'">
<div class="error-message" ng-show="orderForm[ 'data[Product][' + $index + '][number]' ].$invalid">{{ errorMessage( 'data[Product][' + $index + '][number]' ) }}</div>
</div>
</div>
</div>
</form>
Below is the directive. It basically renders the 'dynamic-name' attribute you set on your field.
productsApp.directive( "dynamicName", function( $pile ){
return {
restrict:"A",
terminal:true,
priority:1000,
link:function( scope,element,attrs ){
element.attr( 'name', scope.$eval( attrs.dynamicName ) );
element.removeAttr( "dynamic-name" );
$pile( element )( scope );
}
};
} );
In your Angular controller, you can access fields for setting $valid and $error with this syntax :
$scope.orderForm[ field ].$error // Field : 'data[Product][0][number]' (string)