0
\$\begingroup\$

I am trying to use AJAX with CodeIgniter. I have some code, but I am not sure that the code is in proper way / officially correct according to the programming way. All I want is that if someone in the community is already expert in CodeIgniter or uses AJAX with CodeIgniter, then please review the below code.

Model

<?php

defined('BASEPATH') OR exit('No direct script access allowed');

class Task_model extends CI_Model {

        public $name;
        public $description;
        public $date_created;
        public $date_updated;

        public function get_tasks()
        {
                $query = $this->db->get('tasks');
                return $query->result();
        }

        public function create_task()
        {
                $json = array();
                $this->form_validation->set_rules('name', 'Name', 'required');
                $this->form_validation->set_rules('description', 'Description', 'required');
                if($this->form_validation->run()){
                        $this->name            = $this->input->post('name'); // please read the below note
                        $this->description          = $this->input->post('description');
                        $res = $this->db->insert('tasks', $this);
                        if($res){
                                $insert_id = $this->db->insert_id(); 
                                $json = array(
                                        'type' => 'success',
                                        'message' => $this->db->get_where('tasks', ['id' => $insert_id])->row_array()
                                );
                        } else {
                                $json = array(
                                        'type' => 'error',
                                        'message' => 'Sorry! Cannot Insert the Task'
                                );
                        }
                } else{
                        $json = array(
                                'type' => 'error',
                                'message' => validation_errors()
                        );
                }
                header('Content-Type: application/json');
                echo json_encode($json);
        }

        public function update_task()
        {
                $json = array();
                $this->form_validation->set_rules('task_id', 'ID', 'required');
                $this->form_validation->set_rules('name', 'Name', 'required');
                $this->form_validation->set_rules('description', 'Description', 'required');
                if($this->form_validation->run()){
                        $id                    = $this->input->post('task_id');
                        $data['name']          = $this->input->post('name');
                        $data['description']   = $this->input->post('description');
 //                       $data['date_updated']  = time();
                        $update_id = $this->db->update('tasks', $data, array('id' => $id));
                        if($update_id){
                                $json = array(
                                        'type' => 'success',
                                        'message' => $this->db->get_where('tasks', ['id' => $id])->row_array()
                                );
                        } else {
                                $json = array(
                                        'type' => 'error',
                                        'message' => 'Sorry! Cannot Update the Task'
                                );
                        }
                } else{
                        $json = array(
                                'type' => 'error',
                                'message' => validation_errors()
                        );
                }
                header('Content-Type: application/json');
                echo json_encode($json);
        }

        public function delete_task(){
                $json = array();
                $id = $this->input->post('id');
                if($id > 0){
                        $res = $this->db->delete('tasks', ['id' => $id]);
                        if($res != FALSE){
                                $json = array(
                                        'type' => 'success',
                                        'message' => 'Task Deleted Successfully'
                                );   
                        } else {
                                $json = array(
                                        'type' => 'error',
                                        'message' => 'Sorry! Cannot Delete the Task'
                                );                                  
                        }    
                } else{
                        $json = array(
                                'type' => 'error',
                                'message' => 'Invalid ID'
                        );   
                }
                header('Content-Type: application/json');
                echo json_encode($json);
        }

}

View

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- Required meta tags -->
    <title>Task</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
    <h1 class="text-center">Tasks</h1>
    <hr>
    <div class="container">
        <div class="row">
            <div class="col-sm-12" id="message2"></div>
            <div class="col-sm-12" style="padding-bottom: 5px;">
                <button class="btn btn-success btn-sm pull-right" data-toggle="modal" data-target="#createModel">
                    <span class="glyphicon glyphicon-plus"></span>&emsp;Create Task
                </button>
            </div>
        </div>
        <table class="table table-striped" style="border: 1px solid black;">
            <thead>
                <tr>
                    <th>Name</th>
                    <th>Description</th>
                    <th>Date Created</th>
                    <th>Date Updated</th>
                    <th>Actions</th>
                </tr>
            </thead>
            <tbody id="tableBody">
                <?php foreach($tasks as $task): ?>
                    <tr id="tsk_<?= $task->id ?>">
                        <td class="task_name"><?= $task->name ?></td>
                        <td class="task_desc"><?= $task->description ?></td>
                        <td class="date_created"><?= $task->date_created ?></td>
                        <td class="date_updated"><?= $task->date_updated ?></td>
                        <td>
                            <button class="btn btn-primary edit_task" data-id="<?= $task->id ?>" data-toggle='modal' data-target='#editModel'>Edit</button>
                            <button class="btn btn-danger delete_task" data-id="<?= $task->id ?>" data-toggle="modal" data-target="#deleteModel">x</button>
                        </td>
                    </tr>
                <?php endforeach; ?>
            </tbody>
        </table>
        <div class="col-xs-12 text-center h3" id="table_status"><?= count($tasks) > 0 ? '' : 'No Tasks' ?></div>
    </div>

<!-- Create Task Modal -->
<div class="modal fade" id="createModel" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <!-- Modal Header -->
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal">
                    <span aria-hidden="true">&times;</span>
                    <span class="sr-only">Close</span>
                </button>
                <h4 class="modal-title">
                    Create Task
                </h4>
            </div>

            <!-- Modal Body -->
            <div class="modal-body">
                <form role="form" id="taskForm">
                    <div class="form-group">
                        <label for="name">Name</label>
                        <input type="text" class="form-control" id="name" name="name" placeholder="Task Name"/>
                    </div>
                    <div class="form-group">
                        <label for="description">Description</label>
                        <textarea class="form-control" id="description" name="description" placeholder="Task Description"></textarea>
                    </div>
                </form>
                <div id="message1">
                </div>
            </div>
            <!-- Modal Footer -->
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">
                    Close
                </button>
                <button type="button" id="create_task" class="btn btn-success">
                    Create Task
                </button>
            </div>
        </div>
    </div>
</div>  

<!-- Edit Task Modal -->
<div class="modal fade" id="editModel" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <!-- Modal Header -->
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal">
                    <span aria-hidden="true">&times;</span>
                    <span class="sr-only">Close</span>
                </button>
                <h4 class="modal-title">
                    Edit Task
                </h4>
            </div>

            <!-- Modal Body -->
            <div class="modal-body">
                <form role="form" id="editTaskForm">
                    <div class="form-group">
                        <label for="name">Name</label>
                        <input type="text" class="form-control" id="m_task_name" name="name" placeholder="Task Name"/>
                    </div>
                    <div class="form-group">
                        <label for="description">Description</label>
                        <textarea class="form-control" id="m_task_description" name="description" placeholder="Task Description"></textarea>
                    </div>
                    <input type="hidden" id="m_task_id" name="task_id">
                </form>
                <div id="message1">
                </div>
            </div>
            <!-- Modal Footer -->
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">
                    Close
                </button>
                <button type="button" id="update_task" class="btn btn-success">
                    Update Task
                </button>
            </div>
        </div>
    </div>
</div>

<!-- Delete Task Modal -->
<div class="modal fade" id="deleteModel" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <!-- Modal Header -->
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal">
                    <span aria-hidden="true">&times;</span>
                    <span class="sr-only">Close</span>
                </button>
                <h4 class="modal-title" id="myModalLabel">
                    Create Task
                </h4>
            </div>

            <!-- Modal Body -->
            <div class="modal-body">
                <p>Are you sure you want to delete the selected Task?</p>
            </div>
            <!-- Modal Footer -->
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">
                    Cancel
                </button>
                <button type="button" id="del_btn" class="btn btn-danger">
                    Delete
                </button>
            </div>
        </div>
    </div>
</div>


<script src="https://code.jquery.com/jquery-3.2.1.min.js" crossorigin="anonymous"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<script>

    $(function(){

        /* The following function inserts a new task on click */
        $('#create_task').on('click', function(e){
            e.preventDefault();
            var formData = $("#taskForm").serialize();
            $.ajax({
                type: 'post',
                url: 'crud/create_task',
                data: formData
            }).then(function(res){
                if(res.type == 'success'){
                    appendRow(res.message);
                    $("#message2").html("<div class='alert alert-success' id='success-alert'>Task "+res.message.name+" created Successfully!</div>");
                    $("#taskForm").get(0).reset();
                    $('#createModel').modal('toggle');
                    hideAlert("#success-alert");
                } else{
                    $("#message1").html("<div class='alert alert-danger'>"+res.message+"</div>");
                }
            }, function(){
                alert('Sorry! Some Error Occured');
            })
        });

        $('#tableBody').on('click', '.edit_task', function(e){
            e.preventDefault();
            var rowId = $(this).data('id');
            var name = $('#tsk_'+rowId).find('.task_name').text();
            var desc = $('#tsk_'+rowId).find('.task_desc').text();
            $("#editTaskForm").find('#m_task_id').val(rowId);
            $("#editTaskForm").find('#m_task_name').val(name);
            $("#editTaskForm").find('#m_task_description').val(desc);
        });

        /* The following function Updates the Selected Task */
        $('#update_task').on('click', function(e){
            e.preventDefault();
            var formData = $("#editTaskForm").serialize();
            $.ajax({
                type: 'post',
                url: 'crud/update_task',
                data: formData
            }).then(function(res){
                if(res.type == 'success'){
                    updateRow(res.message);
                    $("#message2").html("<div class='alert alert-success' id='success-alert'>Task "+res.message.name+" updated Successfully!</div>");
                    $("#editTaskForm").get(0).reset();
                    $('#editModel').modal('toggle');
                    hideAlert("#success-alert");
                } else{
                    $("#message1").html("<div class='alert alert-danger'>"+res.message+"</div>");
                }
            }, function(){
                alert('Sorry! Some Error Occured');
            })
        });



        $('#tableBody').on('click', '.delete_task', function(e){
            e.preventDefault();
            var id = $(this).data('id');
            $('#deleteModel #del_btn').data('id', id);
        });

        $('#del_btn').click(function(e){
            e.preventDefault();
            var id = $(this).data('id');
            $('#deleteModel').modal('toggle');
            $.ajax({
                type: 'post',
                url: 'crud/delete_task',
                data: {'id': id}
            }).then(function(res){
                if(res.type == 'success'){
                    $("#message2").html("<div class='alert alert-success' id='success-alert'>Task deleted Successfully!</div>");
                        $('#tsk_'+id).remove();
                    hideAlert("#success-alert");
                } else{
                    $("#message2").html("<div class='alert alert-danger' id='success-alert'>Cannot Delete the Task!</div>");
                    hideAlert("#success-alert");
                }
            }, function(){
                alert('Sorry! Some Error Occured');
            })
        });

        function appendRow(message){
            $('#tableBody').append([
                "<tr id='tsk_"+message.id+"'>", 
                    "<td class='task_name'>"+message.name+"</td>",
                    "<td class='task_desc'>"+message.description+"</td>",
                    "<td class='date_created'>"+message.date_created+"</td>",
                    "<td class='date_updated'>"+message.date_updated+"</td>",
                    "<td>",
                    "<button class='btn btn-primary edit_task' data-id='"+message.id+"' data-toggle='modal' data-target='#editModel'>Edit</button>&nbsp;",
                    "<button class='btn btn-danger delete_task' data-id='"+message.id+"' data-toggle='modal' data-target='#deleteModel'>x</button>",
                    "</td>",
                "</tr>"].join('')
            );
        }       

        function updateRow(message){
            var row = $('#tableBody').find('#tsk_' + message.id);
            row.find('.task_name').text(message.name);
            row.find('.task_desc').text(message.description);
            row.find('.date_created').text(message.date_created);
            row.find('.date_updated').text(message.date_updated);
        }

        function hideAlert(id){
                $(id).fadeTo(2000, 500).slideUp(500, function(){
                    $(id).slideUp(500);
                });
        }

        $('#tableBody').bind('DOMSubtreeModified', function(e) {
          if ($("#tableBody > tr").length > 0) {
            $("#table_status").text('');
          } else{
            $("#table_status").text('No Tasks');
          }
        });


    });

</script>
</body>
</html>

Controller

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Crud extends CI_Controller {

    public function __construct(){
        parent::__construct();
        $this->load->model('task_model');
    }

    public function index()
    {
        $data['tasks'] = $this->task_model->get_tasks();
        $this->load->view('index', $data);
    }

    public function create_task(){
        $this->task_model->create_task();
    }

    public function update_task(){
        $this->task_model->update_task();
    }

    public function delete_task(){
        $this->task_model->delete_task();
    }
}

The code is working fine, but the way it is selecting data..I am in doubt of it.

Please provide some code / Git / solution using CodeIgniter with AJAX, only the basic CRUD operations.

Any help will be highly appreciated.

UPDATE

Please do not edit the Post Title, because this question is FUTURE ORIENTED.It will really help people in future especially newbie who are interested in working on CodeIgniter. So when ever they search for

CodeIgniter Crud with Ajax

they will find a nice, proper and refine code.

My only Aim is to conform the AJAX interaction with CodeIgniter. The way it is used in the above code is correct / appreciated / official way, or there might be some better way to perform CRUD operation using AJAX.

\$\endgroup\$
2
\$\begingroup\$

I'm normally using Bonfire (an HMVC Framework on top of CodeIgniter), so I'm sometimes confused what is CodeIgniter specific and what is not. Anyway some remarks to your code:

Your model is already named task_model so that there is no need to call all methods create_task, update_task, etc. It would be enough to simply call them create, update, etc. You should also keep your methods as general as possible. For example the line $this->db->get('tasks'); could be $this->db->get($this->table_name) where table name is a property of the Model. Same goes with the setting of form validation rules. You could simply provide a method set_form_validation(). This may seem unnecessary for now, but once you create a new entity (e.g. a project the task is assigned to) you may want to copy your model and just change the few special things (like validation, table names) without going through your whole code.

Your model should never output anything. It would be better to return the data and let the controller handle what to do with it. This also means, that you should not write error/success messages in your model. Return the information to your controller.

Your controller should be named in a more meaningful way. I would suggest naming it Task. This way the methods name do not have to contain the word task.

You should also think about splitting your view and creating a header and footer file.

One general thought (for your PHP code as well as your JavaScript): You should use === and !== where it is possible.

\$\endgroup\$
1
\$\begingroup\$

I agree with the answer by D B. The model should not handle the output - leave that to the controller. And the word task in the model methods is redundant, given that the name is Task_model...

As far as the JavaScript/jQuery code goes, I recommend caching the DOM lookups. For more information about that subject, see this article under the heading Cache DOM Lookups (as well as the other information, which might be useful).

$(function(){ //DOM-ready callback function start
    //move DOM-lookups here so they only happen once instead of every time
    //an action occurs
    var message1Container = $("#message2");
    var message2Container = $("#message2");
    var taskForm = $("#taskForm");
    var createModelContainer = $('#createModel')


    /* The following function inserts a new task on click */
    $('#create_task').on('click', function(e){

Then later on use those variables - for example, the following line:

$("#message2").html("<div class='alert alert-success' id='success-alert'>Task "+res.message.name+" created Successfully!</div>");

could be re-written as:

message2Container.html("<div class='alert alert-success' id='success-alert'>Task "+res.message.name+" created Successfully!</div>");

And one could also use the EcmaScript 2015 keyword const for those DOM references (unless browser compatibility is an issue), since they don't change.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.