I have the problem discribed here but I realized that I need to tackle one problem by one and this one has to be first. I will use a bit easyer example with Contact Us form.
I have a controller:
class Contact extends CI_Controller {
public function __construct()
{
[...]
}
public function index()
{
$this->form_validation->set_rules('name', 'Full name', 'trim|required');
$this->form_validation->set_rules('email', 'Your email', 'trim|required|valid_email');
$this->form_validation->set_rules('subject', 'Subject', 'trim|required');
$this->form_validation->set_rules('msg', 'Message', 'trim|required');
$this->form_validation->set_error_delimiters('<div class="text-danger">', '</div>');
if($this->form_validation->run() == FALSE)
{
$this->load->view('contact', $data);
}
else
{
// Configure email library
[...]
$this->email->send();
$this->load->view('contact_success');
}
}
and view:
<div class="container-fluid">
<div class="row">
<div class="col-sm-12">
<?php echo form_open('contact'); ?>
<div class="form-group">
<label for="name">Full name</label></br>
<input type="text" class="form-control" name="name" placeholder="Enter your full name" value="<?php echo set_value('name') ?>" ></br>
<?php echo form_error('name'); ?>
</div>
<div class="form-group">
<label for="email">Email</label></br>
<input type="text" class="form-control" name="email" placeholder="Enter your email" value="<?php echo set_value('email') ?>"></br>
<?php echo form_error('email'); ?>
</div>
<div class="form-group">
<label for="subject">Subject</label></br>
<input type="text" class="form-control" name="subject" placeholder="subject" value="<?php echo set_value('subject') ?>"></br>
<?php echo form_error('subject'); ?>
</div>
<div class="form-group">
<label for="msg">Message</label></br>
<textarea rows="4" class="form-control" type="text" name="msg" placeholder="Enter your message"><?php echo set_value('msg') ?></textarea></br>
<?php echo form_error('msg'); ?>
</div>
<input type="submit" class="btn btn-default" name="submit" value="send" />
</form>
</div>
</div>
</div>
If I call the controller using url I get nicely working contact us form. However I find it annoying that such a small thing as Contact Us has to be loaded in new page. So I have this jquery in my main page view:
[..]
<a href="#" id="contact-link">register</a>
[..]
<script>
$(document).ready(function(){
$('#contact-link').on('click',function(){
$.get(baseurl + 'index.php/contact', function(response){
$('#popup-div').html(response);
});
});
});
</script>
So now I have "embed" the contact us controller in my main view. However I displays form and actually send email when the form validation run. But if form validation doesn`t run a new page is loaded displaying same form with validation error. I want validation error displayed in my popup div.
I have seen this done in a lot of websites but can not get my head around on how to do it with CI. Do I have to call contact controller after every submit? I think the problem is that $.get is called just once so callback handles response only once. I tried to remove $('#contact-link').on('click',function(){
part but i doesn`t help. I even though about putting $.get inside a function and making it recursive but I am afraid that it would mess up form validation.
What you need is jquery validation, and to send the contact data using ajax.
Here is how you can do it : In your main view, have a hidden div or a hidden bootstrap modal that contains the contact form, when the user clicks that link the modal shows up with the contact form. From here you need a jquery validation plugin that checks the user inputs when clicking on submit, if the user inputs are filled correctly, send an ajax request to a method inside the contact controller which runs the form_validation method, if the form is successful submitted, send the email, and return a response saying contact successful. Then if the contact was made successfully, then close the modal, and show a notification saying contact successfully made.
Your contact controller will look something like this :
public function check_contact()
{
$this->form_validation->set_rules('name', 'Full name', 'trim|required');
$this->form_validation->set_rules('email', 'Your email', 'trim|required|valid_email');
$this->form_validation->set_rules('subject', 'Subject', 'trim|required');
$this->form_validation->set_rules('msg', 'Message', 'trim|required');
if($this->form_validation->run() == FALSE)
{
$response = "KO";
echo $response;
}
else
{
// Configure email library
$this->email->send();
$response = "OK"
echo $response;
}
}
And your jquery ajax would look something like this :
//Fetch the contact form using id="ContactForm"
var form = $('#ContactForm')[0];
var formData = new FormData(form);
$.ajax({
url: 'Your url here/check_contact',
data: formData,
type: 'POST',
success : function(data){
if (data == "KO")
{
$('#ErrorDiv').html("There was an error subbmiting your contact").show();
}
if (data == "OK")
{
$('#ContactModal').hide();
$('#SuccessDiv').delay(800).fadeIn();
}
}
});
Jquery Validation Plugin : https://jqueryvalidation.org/
As I think that this is really nice way to create good user interface I will answer my own question for others to use.
The problem is that my JS requests controller on clicking contact-link but never handles the submit.
I left that as it was but added another JS:
$('#contact-form').on('submit', function(event) {
event.preventDefault();
var formData = $(this).serialize();
var actionUrl = $(this).attr('action');
$.post(actionUrl, formData, function(response){
$('#popup-div').html(response);
});
});
and in my view I changed:
<?php echo form_open('contact', array('id'=>'contact-form')); ?>
Without event.preventDefault();
the controller would validate and continue flow until a load->view
is called and that view is opened in in new page.