A Generic JQuery AJAX form validaton for F3

697 views
Skip to first unread message

karthick b

unread,
Feb 20, 2016, 3:19:39 AM2/20/16
to f3-fra...@googlegroups.com
Hi,

I am trying to figure out how to make this Generic JQuery AJAX form validator work in fat free. Can't figure out why this is not working as expected. Is it because of Fatfree Cache/Buffer or due to my improper coding.

the form with script
<!DOCTYPE html> 
<html>
       
<head>
               
<title>Page Title</title>
               
<meta name="viewport" content="width=device-width, initial-scale=1">            
               
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css" />
               
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
               
<script src="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>          
               
<script>
                $(document).ready(function(){
                        $("form.userform").change(function() {
                                $.post("ajaxtest", $("form.userform").serialize(), function( data ) {
                                        if( data.name== "Anatol :-)" )                                                
                                                alert('test');                                                  
                                }, "json");
                        });
                });
               
</script>
       
</head>
       
<body>
               
<div data-url="panel-fixed-page1" data-role="page" id="panel-fixed-page1" data-title="Menu and Login">            

                         
<div data-role="panel" data-position="right" data-position-fixed="true" data-display="overlay" data-theme="a" id="add-form">
                               
<form class="userform">
                                       
<h2>Login</h2>
                                       
<label for="name">Username:</label>
                                       
<input name="name" id="name" value="" data-clear-btn="true" data-mini="true" type="text">
                                       
<label for="password">Password:</label>
                                       
<input name="password" id="password" value="" data-clear-btn="true" autocomplete="off" data-mini="true" type="password">
                                       
<div class="ui-grid-a">
                                               
<div class="ui-block-a"><a href="#" data-rel="close" class="ui-btn ui-shadow ui-corner-all ui-btn-b ui-mini">Cancel</a></div>
                                               
<div class="ui-block-b"><a href="#" data-rel="close" class="ui-btn ui-shadow ui-corner-all ui-btn-a ui-mini">Save</a></div>
                                       
</div>
                               
</form>
                       
</div><!-- /panel -->
                       
               
</div><!-- /page -->
       
</body>
       
</html>


The PHP server side
<?php

class Ajaxtest {

   
public function ajaxtest()
   
{
        $data
= array("name" => "");
        $data
["name"]="Anatol :-)";
        echo json_encode
($data);            
   
}

}


Response on Firefox firebug
{"name":"Anatol :-)"}{"name":"Anatol :-)"}

Well this seems to correct but there is no JSON object returned. I am just getting the text. thats why the below part of the script seems not firing IMHO.

if( data.name== "Anatol :-)" )                                                
   alert('Hi');    

I am attaching the firebug screenshot in the tutorial pointing earlier in this post, for showing how the response should be.

Can you please throw some light on whats wrong, please. Thanks.

response.png

Anatol Buchholz

unread,
Feb 20, 2016, 7:04:52 AM2/20/16
to Fat-Free Framework
Dear Karthick,

I think you´re super close. I haven´t changed something in your js / html markup but expect your´re not returning json ;)

try this:

$f3->route('GET /',
   
function($f3) {
        echo
\Template::instance()->render('test.html');
   
}
);

// SET AN ASSOC NAME FIRST THAT YOU`RE JOSON RETURN CAN LOOL LIKE: {"name":"Anatol :-)"}
$f3
->route('POST /ajaxtest',
   
function($f3) {
        $arr
['name'] = $f3->get('POST.name');
        echo json_encode
($arr);
   
}
);


cheers,

– a

karthick b

unread,
Feb 20, 2016, 12:13:45 PM2/20/16
to f3-fra...@googlegroups.com
Dear Anantol,

I am afraid the problem is deeper.

First whatever I do output is coming as HTML not JSON.

So I added the line

header("Content-Type: application/json", true);

Now the output become JSON but I am getting the attached (screenshot) JSON parsing error in firebug.

Think I am going to give up this.

:-(

EDIT: notice that there is two outputs of same data everytime and the JSON output error column number is proportional to the output column.
response.png

Anatol Buchholz

unread,
Feb 20, 2016, 12:24:19 PM2/20/16
to f3-fra...@googlegroups.com
mhhmh ... do you render some html template as return? – or just return something from your controller how I did?
And did you use json_encode()?

Try die() instead of echo:

$f3->route('POST /ajaxtest',
   
function($f3) {
        $arr
['name'] = $f3->get('POST.name');

       
die(json_encode($arr));
   
}
);

Next to this, can you post  what you have in your /ajaxtest route? 

Think I am going to give up this.

Relax, we´ll manage to get this running ;) 

karthick b

unread,
Feb 20, 2016, 1:31:17 PM2/20/16
to Fat-Free Framework
Hi Anatol,

It worked.

die(json_encode($data)); did the trick. :-)

here is the working code
<?php
class Ajaxtest {
   
function ajaxtest() {
        $f3
=Base::instance();

        $data
= array( "name" => "");

        $data
["name"]=$f3->get("POST.name");
       
die(json_encode($data));
   
}
}
?>

To answer your question:-

1) No. I did not have render any html template. The ajaxtest controller has no more code other than the above.

2) when I extend Ajaxtest controller from controller where I am having a template file, its throwing up error. So I did not extend it.

3) Also I mention all routes in my central routes config file, so no route is mentioned  in the class.

Anatol Buchholz

unread,
Feb 20, 2016, 5:39:40 PM2/20/16
to Fat-Free Framework
Great! So this seams to be fixed ... Post the finished site when you´re done ;)

karthick b

unread,
Feb 24, 2016, 4:23:12 PM2/24/16
to Fat-Free Framework
Sorry for late revert. Sure thing Anatol.

I am using bootstrap for the frontend. So for input text you can have required keyword which very much does the same thing. Why reinvent wheel. So I am not implementing this. It saves server round trip as well.

<div class="controls">
                       
<input type="text" id="first_name" name="first_name" placeholder="firstname" class="form-control input-xlarge" value="{{ @POST.first_name }}" required autofocus />
                   
</div>

Anatol Buchholz

unread,
Feb 25, 2016, 6:55:54 AM2/25/16
to Fat-Free Framework
Hi karthick,

Maybe it´s interesting for you that with html5 you have even more fields than required. Have a look at this: http://www.the-art-of-web.com/html/html5-form-validation/
One could allow f.e. only E-Mail pattern in a certain field. As you write there is no need to reinvent the wheel but for me it´s some best practice to not trust the client. Even more if it´s a shopping cart. Before processing the form I would check if everything is as I expect serverside. F3 audit class could be of help here, Respect Validation (https://github.com/Respect/Validation ) is also a nice peace of code. Further as sending error messages back to the client can be cumbersome have a look at ikkez Flash class (https://github.com/ikkez/F3-Sugar/tree/master-v3/Flash) which does a great job.

cheers,

– anatol

karthick b

unread,
Mar 3, 2016, 12:41:58 AM3/3/16
to Fat-Free Framework
Dear Anatol,

I have implemented as much as HTML5 validation as possible. I also changed from messages to Flash. However I am now struck with server side (Respect) validation.

use Respect\Validation\Validator as v;

class EmployeeController extends Controller {

public function create()
   
{
           
       
if($this->f3->exists('POST.create'))
       
{
            $employee
= new Employee($this->db);
            $this
->f3->set('POST.created_by', $this->f3->get('SESSION.id'));
               
            $employee
->set('firstname',$this->f3->get('POST.firstname'));
            $employeeValidator
= v::attribute('firstname', v::stringType()->length(1,32));
           
if($employeeValidator->validate($employee)) {                
                $employee
->add();                            
                $this
->f3->reroute('/employee');
           
}   else { echo $this->f3->get('POST.firstname'); }
           
       
} else
       
{                        
            $this
->f3->set('page_head','Create');
            $this
->f3->set('view','employee/form.htm');
        echo
Template::instance()->render('layout.htm');    
       
}

   
}

Employee Model
<?php

class Employee extends DB\SQL\Mapper {

   
public function __construct(DB\SQL $db) {
        parent
::__construct($db,'employees');
   
}

   
public function add() {
        $this
->copyFrom('POST');
        $this
->save();
   
}
....
}



If not, can you please suggest me with a another F3 server side validation that consists of Required, stripslashes, integer check, filters etc.

Thanks.

Anatol Buchholz

unread,
Mar 3, 2016, 3:16:28 AM3/3/16
to Fat-Free Framework
Dear Karthick,

nice you taking it serious! Can you post the fields you like to validate and how they should look like to be valid.
Further which way would you prefer? Would you like to use respect class or f.e. pure php regex?

cheers,

– anatol

karthick b

unread,
Mar 3, 2016, 4:03:21 AM3/3/16
to f3-fra...@googlegroups.com
Dear Anatol,

Thanks for your encouraging words. Just after I posted the question I realized that I was trying to get the POST.firstname which was not even there. It is actually POST.first_name. I was pulling my hair yesterday whole night without any luck on the Respect Validator. Earlier I have decided not to use f3-validate plugin because i thought it supports only Cortex. But when I looked at it closer the first example is a generic one and could be used for DB:Sql as well. But now I have a small problem which is making f3-validate work with Flash.

Employee Controller

    public function update()

   
{

        $employee
= new Employee($this->db);


       
if($this->f3->exists('POST.update'))
       
{            
            $this
->f3->set('POST.updated_by', $this->f3->get('SESSION.id'));
           
            $data
= $this->f3->get('POST');
            $valid
= Validate::is_valid($data, array(                      
               
'first_name' => 'required|valid_name',                
               
'last_name' => 'valid_name',                
               
'mobile' => 'phone_number',                
               
'email' => 'valid_email',    
               
'permenant_address'=> 'required|street_address',
               
'communication_address' => 'street_address',
               
'parent_name'=> 'valid_name',
               
'reference_name'=> 'valid_name',
               
'reference_number'=>'phone_number'          
           
));
           
           
if($valid === true) {
                $employee
->edit($this->f3->get('POST.id'));

        $this
->f3->reroute('/employee');            
           
} else {

                $error
= implode('. ',$valid);
               
\Flash::instance()->addMessage($error, 'warning');      
                $this
->f3->set('page_head','Create');

                $this
->f3->set('view','employee/form.htm');
                echo
Template::instance()->render('layout.htm');    
           
}

           
           
       
} else
       
{
            $employee
->getByid($this->f3->get('PARAMS.id'));
            $this
->f3->set('employee',$user);
            $this
->f3->set('page_head','Update');

            $this
->f3->set('view','employee/form.htm');
            echo
Template::instance()->render('layout.htm');    
       
}

   
}

The problem is just in this part where the validate object has errors in an array and \Flash expects string. So when I implode the array to string before feeding it to Flash I get a HTML markup <span class="gump-field">fieldname</span>. Please see attached screen shot. However there is validator method to just get the error message without the <span> part but I do not know how to call it.

Here is another attempt by using validate->get_errors_array().

if($valid === true) {
                $employee
->edit($this->f3->get('POST.id'));

        $this
->f3->reroute('/employee');            
           
} else {

               
//$error = implode('. ',$valid);
               
foreach ($valid->get_errors_array() as $field=>$error) {
               
#Handle Your errors
               
\Flash::instance()->addMessage($error,'warning');  # Uncomment if you are using Flash

               
}    
                $this
->f3->set('page_head','Create');
                $this
->f3->set('view','employee/form.htm');
                echo
Template::instance()->render('layout.htm');    
           
}

Note: I just enclosed the \Flash warning message with a foreach loop. Other than that there is not much in the code posted earlier. Can you advise if you know how to get only the error message without the span.


EDIT: Problem solved by using PHP's own strip_tags() function before feeding to \Flash.
$error = strip_tags($error);
Screenshot from 2016-03-03 14:25:06.png

Anatol Buchholz

unread,
Mar 3, 2016, 5:37:44 AM3/3/16
to Fat-Free Framework
Hi karthick

EDIT: Problem solved by using PHP's own strip_tags() function before feeding to \Flash.

so this is done?  Unfortunately I do not know the F3 validation plugin yet.
As always there are more routes to rome.

If you run into problems I´m there to help you.

cheers,

– anatol
Reply all
Reply to author
Forward
0 new messages