Ajax saving with jQuery and Kohana

Difficulty: Advanced

Yesterday a post dealing with ajax saving with jQuery and CakePHP popped up on my rss-feeds. The same thing can of course be done with Kohana and jQuery and the approach is quite similar.

Similar conditions to the last ajax post apply. All examples will be based on this previous tutorial so you might want to read it.

Anyway, this tutorial requires basic knowledge of ORM and the Template_Controller. Furthermore, if you use Kohana 2.1 you should download the request helper.

We’ll continue with the students table of last time.

--
-- Table structure for table `students`, dorm_id will not be used today 
--
 CREATE TABLE IF NOT EXISTS `students` (
  `id` mediumint(9) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) collate utf8_unicode_ci NOT NULL,
  `dorm_id` mediumint(9) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=4 ;
 
INSERT INTO `students` (`id`, `name`, `dorm_id`) VALUES
(1, 'student 1', 1),
(2, 'student 2', 1);

And the model again is:

//models/student.php
class Student_Model extends ORM{     
}

The template is also the same, only one difference

//views/template.php
<html>
<head>
<title>Kohana jQuery Ajax tutorial</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
<script type="text/javascript" src="http://example.com/assets/js/jquery.form.js"></script>
<style type='text/css' media='all'>
#flash-message{
	width:300px;
	height:30px;
	padding-top:15px;
	text-align:center;
	margin-bottom:20px;
	font-weight: Bolder;
}
.flash-error{
	color:Red;
	background-color: #f6c0c9;
	border:1px solid #d32f4a;	
}
.flash-notify{
	color:Blue;
	background-color: #bfbaf5;
	border:1px solid #4237d8;	
}</style>
<? echo isset($head) ? $head : ''  ?>
</head>
<body>
<?= $content ?>
</body>
</html>

Again, you can see I have a variable $head which is where all the jQuery code is going to be. The difference lies in the form plugin. Make sure you put it in the right place. I also added a little styling for the flash messages. Will be covered later.

Anyway, on to the controller:

//controllers/student.php
class Student_Controller extends Template_Controller {
	public function index()
	{
		$this->template->content=new View('student/index');
		$this->template->content->students=ORM::factory('student')->find_all();
	}
}

The view for /student/index is the same as last time only now has a edit link instead of delete

//views/student/index.php
<table id="students"><?php
foreach ($students as $student)
{
	echo "<tr><td>".$student->id."</td><td>".$student->name."</td><td>".html::anchor('student/edit/'.$student->id,'Edit')."</td></tr>";
} ?>
</table>

This means we’ll need an edit method in our controller.

public function edit($id)
{
        //$this->template->head=new View('student/ajax_save'); //uncomment later on
	$student=ORM::factory('student',(int) $id);
	$form=new Forge(url::current(), 'Edit', 'POST');
	$form->input('name')->value($student->name);
	$form->submit('submit');
 
	if($form->validate())
	{
		$student->name=$form->name->value; //get value of form element
		$student->save();
		url::redirect('student/index');
	}
	else
	{
		$this->template->content=$form;
	}	
 
}

When you click on an edit link in the index method you’ll see a form to change the name of the student. I created the form with Forge for ease but any form will do. This is all fully functional without javascript.

Next step is adding the ajax. Like last time we’ll fill the $head variable in the template. Uncomment the first line in the ‘edit’ method and create a view ‘views/student/ajax_save.php’

<script type="text/javascript">
//views/student/ajax_save.php
$(document).ready(function() 
	{ 
      //attach onSubmit to the form
      $('#edit_form').submit(function(){
                  //When submitted do an ajaxSubmit
                  $(this).ajaxSubmit({
                      dataType: 'json',
                      success: function(data, responseCode) {
                                //Show flash message as first element after body
                      		jQuery('<div id="flash-message" class="flash-'+data.flash_class+'">').hide().html(data.text).prependTo('body').fadeIn();
                          //Show for 5 seconds
                          setTimeout(function(){
                              $('#flash_message').fadeOut();
                          }, 5000);
                     }
                  });
                  //return false to prevent normal submit
                  return false;
              })
	}
); 
</script>

You’ll see it resembles the js in the Cakephp tutorial but there are some differences. We replace the functionality of the submit button with an ajax submit instead of adding another button. Also we use json to return a message and a class. The code will show a div for a couple of seconds when submitting the form through ajax, form will either be red or blue depending on whether the an error was given or not.

Let’s look at the new controller code.

public function edit($id)
{
	$student=ORM::factory('student',(int) $id);
 
	$form=new Forge(url::current(), 'Edit', 'POST');
	$form->set_attr('id','edit_form');
	$form->input('name')->value($student->name);
	$form->submit('submit');
 
	if(request::is_ajax())
	{
		if($form->validate())
		{
			$student->name=$form->name->value; //get value of element
			$student->save();		
			echo json_encode(array('flash_class'=>'flash-notify','text'=>'Saved succesfully'));
		}
		else
		{
			$errors=$form->errors();
			echo json_encode(array('flash_class'=>'flash-error','text'=>'Error during saving') );
		}
		$this->auto_render=false; //Disable the auto renderer, we don't want a layout in our ajax response
		return;
	}
 
	$this->template->head=new View('student/ajax_save');
 
 
	if($form->validate())
	{		
		$student->name=$form->name->value;
		$student->save();
		url::redirect('student/index');
	}
	else
	{
		$this->template->content=$form;
	}	
}

You can see that we return a json object on success and failure. The json object contains the class we want to attach to the flash message, and the message itself.

You see that using the power of jQuery this stuff becomes incredibly easy. Again, we have accomplished code that will work with or without javascript.

I hope this was clear. I kept the code a little more verbose to maintain clarity.


8 Responses to “Ajax saving with jQuery and Kohana”

  1. Pages tagged "ajax" Says:

    [...] bookmarks tagged ajax Ajax saving with jQuery and Kohana saved by 3 others     gli0444 bookmarked on 07/17/08 | [...]

  2. Alex Says:

    Shouldn’t this:
    $student=ORM::factory(’student’,(int) $id);

    Be before:
    if(request::is_ajax())

    As far as I can see php would throw some kind of ‘calling method on non object’ error.

    Otherwise it seems like a nice introduction to ajax :)

  3. dlib Says:

    You’re right, missed that :) Thx, I’ll fix it.

  4. sean Says:

    $(’#edit-form’).submit(function(){
    should be
    $(’#edit_form’).submit(function(){

  5. dlib Says:

    Fixed! Thanks for the close read

  6. Hasibul Kabir Says:

    When I click on a edit link a error message shown stated that:

    Fatal error: Class ‘Form_Input’ not found in C:\xampp\htdocs\Kohana\system\libraries\Forge.php on line 93

    I have downloaded the Forge class and kept it in Library folder. So why this is happening? Would someone help me?

  7. Hasibul Kabir Says:

    I think I have overcome from the first problem. Now I am facing another problem when I click on the edit link. An error message is displayed stated that:

    //views/template.php
    Fatal error: Method Forge::__toString() must not throw an exception in C:\xampp\htdocs\Kohana\application\views\template.php on line 32

    How can I overcome this situation?

  8. Hasibul Kabir Says:

    Yes :) Finally I have made it! :) This tutorial is awesome!!!;)

Leave a Comment