PHP

How to Use CKEditor with AngularJS and PHP

How to Use CKEditor in AngularJS and PHP?

In my last tutorial I have given details on how you can work with AngularJs using crud application, In this tutorial I am going to provide solution on how to use CKEditor while using AngularJS into your application, here I will provide a sample demo using PHP to demonstrate use of CKEditor in angularJS.

Tutorial Features:

We will create a quick sample demo of creating Blog Post, which is going to have few basic operations listing below:

  • Create New Blog Post (Use CKEditor for description field of the blog post)
  • Delete Blog Post
  • List Existing Blog Post
  • Update Blog Post (Again Use CKEditor while updating the description field of the blog post and it should be pre populated)

Live Demo:

Things used:

  • PHP
  • AngularJS
  • CKEditor
  • Bootstrap V3
  • jQuery

Let’s get started:

Step 1 – Setup Database Table:

Create new Database and add new table called `posts` or you can simply use following script to create new table.

CREATE TABLE `posts` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL DEFAULT '',
  `description` text,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
MySQL Posts Table

Let’s start by creating the folder for the application to store sample application files, so go ahead and create new folder to in your php environment setup it can be lamp, xampp, mamp or homestead totally depend on your system php environment.

I am assuming you have your application folder ready to go along with the database that you have created the in the first step.

Step 2 – Design User interface:

Create new file called index.php inside the application folder and setup basic html page according to the given script.

`/index.php`

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CKEditor with AngularJS and PHP</title>

    <!-- Latest compiled and minified CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>


<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="//cdn.ckeditor.com/4.7.1/standard/ckeditor.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js"></script>
</body>
</html>

In the above script we have added bootstrap, AngularJS and CKEditor, jQuery Library to use and to reference this libraries I am using there CDN version, if you want you visit there website to download source and reference them into the page, it’s all depend on your requirements. it doesn’t matter either on will work.

Let’s design our page using bootstrap, update index.php page according to the following script:

`/index.php`

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CKEditor with AngularJS and PHP</title>

    <!-- Latest compiled and minified CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>

<div ng-app="App">
    <div ng-controller="postController">

        <div class="container">
            <h1>Posts</h1>

            <div class="panel panel-default">
                <div class="panel-heading">
                    <button class="btn btn-primary btn-xs pull-right" ng-click="initAddPost()">Add Post</button>
                    <h3 class="panel-title">All Post</h3>
                </div>
                <div class="panel-body">

                </div>
            </div>
        </div>


        <div class="modal fade" tabindex="-1" role="dialog" id="new_post">
            <div class="modal-dialog modal-lg" role="document">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
                                aria-hidden="true">&times;</span></button>
                        <h4 class="modal-title">Create New Post</h4>
                    </div>
                    <div class="modal-body">
                        <div class="form-group">
                            <label>Name:</label>
                            <input type="text" ng-model="post.name" class="form-control">
                        </div>
                        <div class="form-group">
                            <label>Post Details:</label>
                            <textarea ck-editor ng-model="post.description"></textarea>
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                        <button type="button" ng-click="publishPost()" class="btn btn-primary">Publish</button>
                    </div>
                </div>
                <!-- /.modal-content -->
            </div>
            <!-- /.modal-dialog -->
        </div>
        <!-- /.modal -->

    </div>
</div>


<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="//cdn.ckeditor.com/4.7.1/standard/ckeditor.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js"></script>
<script src="js/ng-script.js"></script>

</body>
</html>

If you review above file line by line you will see at the start of the body section I have added ng-app directive to define angularJS module and next I have added ng-controller directive, keep in mind we are going to use those while writing our angularJS script.

Next I have added basic design with bootstrap panel and a button to open up the modal popup along with the ng-click event and then I have added the modal popup to be able to perform the add new post functionality.

If you notice under model popup we have `<textarea ck-editor ng-model=”post.description”></textarea>` element here we have added custom directive for CkEditor, just keep in mind about this directive you have to notice we are going to create that in the angularJS script and this would be the directive which is going to be the responsible to replacing this textarea element to CKEditor.

Step 3- Write Required AngularJS Script:

In this step we are going to write basic require angularJs script to start, so go ahead and add new folder called `js` and a file under the same folder called `ng-script.js` if you notice clearly we have already added reference to this file in the above step.

Go ahead and open this file into your editor and add following script:

`/js/ng-script.js:`

var app = angular.module('App', []);

app.controller('postController', ['$scope', '$http', function ($scope, $http) {

    $scope.post = {
        name: '',
        description: ''
    };

    $scope.initAddPost = function () {
        var element = angular.element('#new_post');
        element.modal("show");
    };

}]);

In the above script at the very beginning we have declared angular module which is going to reference to the `ng-app` directive which we added inside index.php page and next we have a declaration of `postController` again same we have added inside index.php along with the `ng-controller`directive.

PostController:

This is the place where we are going to have our script to handle post basic operations, right now we have added a post object and method to handle add post click event to open up the model popup.

Step 4 – Create CKEditor AngularJS Directive:

In this step we will needs to create a directive which is responsible for replacing the html element to CKEditor, go ahead and open up the our script file and add following directive right after the postController.

`/js/ng-script.js:`

app.directive('ckEditor', function () {
    return {
        require: '?ngModel',
        link: function (scope, elm, attr, ngModel) {
            var ck = CKEDITOR.replace(elm[0]);

            if (!ngModel) return;

            ck.on('pasteState', function () {
                scope.$apply(function () {
                    ngModel.$setViewValue(ck.getData());
                });
            });

            ngModel.$render = function (value) {
                ck.setData(ngModel.$viewValue);
            };
        }
    };
});

With this above directive we all set to go and play with the our demo to added basic add, edit, list and delete feature.

If you go ahead and run the application with the current state and click on add post button you see the following output, which is exactly what we want a CKEditor element where we can add our post detail content.

Modal Popup with CKEditor

Step 5 – Create PHP CRUD API:

In this step we will create a very basic api using PHP and PDO connection to handle create, read, update and delete post operations:

Go ahed and create folder called script inside the application directory and add following files:

  1. /script/database_connection.php
  2. /script/library.php
  3. /script/create.php
  4. /script/list.php
  5. /script/update.php
  6. /script/delete.php

Open Database Connection file into your editor and add following script and make sure you update the database connection setting variables according to the your php environment settings.

`/script/database_connection.php:`

<?php
/*
 * DATABASE connection script
 * */
// ...

// database Connection variables
define('HOST', 'localhost'); // Database Host name ex. localhost
define('USER', 'root'); // Database User ex. root
define('PASSWORD', 'secret'); // Database User Password  (if password is not set for user then keep it empty )
define('DATABASE', 'test_db'); // Database Name

function DB()
{
    static $instance;
    if ($instance === null) {
        $opt = array(
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_EMULATE_PREPARES => FALSE,
        );
        $dsn = 'mysql:host=' . HOST . ';dbname=' . DATABASE;
        $instance = new PDO($dsn, USER, PASSWORD, $opt);
    }
    return $instance;
}

?>

Open up the library.php file and use following script:

`/script/library.php:`

<?php

require __DIR__ . '/database_connection.php';

/**
 * Class Post
 */class Posts
{

    /**
     * @var mysqli|PDO|string
     */    protected $db;

    /**
     * Post constructor.
     */    public function __construct()
    {
        $this->db = DB();
    }

    /**
     * Add new Post
     *
     * @param $name
     * @param $description
     *
     * @return string
     */    public function Create($name, $description)
    {
        $query = $this->db->prepare("INSERT INTO posts(name, description) VALUES (:name,:description)");
        $query->bindParam("name", $name, PDO::PARAM_STR);
        $query->bindParam("description", $description, PDO::PARAM_STR);
        $query->execute();

        return json_encode(['post' => [
            'id'          => $this->db->lastInsertId(),
            'name'        => $name,
            'description' => $description
        ]]);
    }

    /**
     * List Posts
     *
     * @return string
     */    public function Read()
    {
        $query = $this->db->prepare("SELECT * FROM posts");
        $query->execute();
        $data = array();
        while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
            $data[] = $row;
        }

        return json_encode(['posts' => $data]);
    }


    /**
     * Update Post
     *
     * @param $name
     * @param $description
     * @param $id
     */    public function Update($name, $description, $id)
    {
        $query = $this->db->prepare("UPDATE posts SET name = :name, description = :description WHERE id = :id");
        $query->bindParam("name", $name, PDO::PARAM_STR);
        $query->bindParam("description", $description, PDO::PARAM_STR);
        $query->bindParam("id", $id, PDO::PARAM_STR);
        $query->execute();
    }

    /**
     * Delete Post
     *
     * @param $id
     */    public function Delete($id)
    {
        $query = $this->db->prepare("DELETE FROM posts WHERE id = :id");
        $query->bindParam("id", $id, PDO::PARAM_STR);
        $query->execute();
    }
}

Open up the create.php file into your editor to add following script:

`/script/create.php:`

<?php

$data = json_decode(file_get_contents('php://input'), TRUE);

if (isset($data['post'])) {

    require __DIR__ . '/library.php';

    $name = (isset($data['post']['name']) ? $data['post']['name'] : NULL);
    $description = (isset($data['post']['description']) ? $data['post']['description'] : NULL);

    // validated the request
    if ($name == NULL) {
        http_response_code(400);
        echo json_encode(['errors' => ["Name Field is required"]]);

    } else {

        $post = new Posts();

        echo $post->Create($name, $description);
    }
}
?>

`/script/list.php:`

<?php
require __DIR__ . '/library.php';

$post = new Posts();

echo $post->Read();
?>

`/script/update.php:`

<?php

$data = json_decode(file_get_contents('php://input'), TRUE);

if (isset($data['post'])) {

    require __DIR__ . '/library.php';

    $name = (isset($data['post']['name']) ? $data['post']['name'] : NULL);
    $description = (isset($data['post']['description']) ? $data['post']['description'] : NULL);
    $id = (isset($data['post']['id']) ? $data['post']['id'] : NULL);

    // validations
    if ($name == NULL) {
        http_response_code(400);
        echo json_encode(['errors' => ["Name Field is required"]]);

    } else {

        $post = new Posts();

        $post->Update($name, $description, $id);
    }
}

?>

`/script/delete.php:`

<?php

$data = json_decode(file_get_contents('php://input'), TRUE);

if (isset($data['post'])) {

    require __DIR__ . '/library.php';

    $id = (isset($data['post']['id']) ? $data['post']['id'] : NULL);

    $post = new Posts();

    $post->Delete($id);
}

?>

So our PHP api is all set to handle backend operations, now we just need to call this api from angular js and to work on the posts.

okay let’s get back on to the AngularJs Script:

Step 6 – Add new Post:

Go ahead and open up the ng-script.js file into your editor and update PostController it according to the following script:

app.controller('postController', ['$scope', '$http', function ($scope, $http) {

    $scope.post = {
        name: '',
        description: ''
    };

    $scope.posts = [];
    $scope.errors = [];

    // init add post model
    $scope.initAddPost = function () {
        var element = angular.element('#new_post');
        element.modal("show");
    };

    // publish the the post
    $scope.publishPost = function () {

        $http.post('script/create.php', {
            post: $scope.post
        })
            .then(function success(e) {

                $scope.errors = [];

                $scope.posts.push(e.data.post);

                var modal_element = angular.element('#new_post');
                modal_element.modal('hide');

            }, function error(e) {
                $scope.errors = e.data.errors;
            });

    };


}]);

Now if you run the application and try to add new post it should work, but you won’t see the list right after adding new post, following next step to list all the post.

Step 7 – List all post:

Add following method inside postController after publish post method:

 // list all post
    $scope.listPost = function () {
        $http.get('script/list.php', {})
            .then(function success(e) {
                $scope.posts = e.data.posts;
            }, function error(e) {

            });
    };
    $scope.listPost();

Next open up the index.php page and update the all post panel section according to the following:

  <div class="panel panel-default">
                <div class="panel-heading">
                    <button class="btn btn-primary btn-xs pull-right" ng-click="initAddPost()">Add Post</button>
                    <h3 class="panel-title">All Post</h3>
                </div>
                <div class="panel-body">
                    <table ng-if="posts.length > 0" class="table table-bordered table-responsive table-striped">
                        <tr>
                            <th>No</th>
                            <th>Name</th>
                            <th>Description</th>
                            <th>Action</th>
                        </tr>
                        <tr ng-repeat="post in posts">
                            <td>{{ $index + 1 }}</td>
                            <td>{{ post.name }}</td>
                            <td>{{ post.description }}</td>
                            <td>
                                <button ng-click="edit($index)"  class="btn btn-primary btn-xs">Edit</button>
                                <button ng-click="delete($index)" class="btn btn-danger btn-xs">Delete</button>
                            </td>
                        </tr>
                    </table>
                </div>
            </div>
        </div>

Now if your run or refresh the application you will see the list will be there and if you try to add new post it will be append to the existing list.

Step 8 – Update the Post:

Open up the index.php page into your editor and add new bootstrap model to have update feature:

`index.php:`

  <div class="modal fade" tabindex="-1" role="dialog" id="update_post">
            <div class="modal-dialog modal-lg" role="document">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
                                aria-hidden="true">&times;</span></button>
                        <h4 class="modal-title">Update Post</h4>
                    </div>
                    <div class="modal-body">

                        <ul class="alert alert-danger" ng-if="errors.length > 0">
                            <li ng-repeat="error in errors">
                                {{ error }}
                            </li>
                        </ul>

                        <div class="form-group">
                            <label>Name:</label>
                            <input type="text" ng-model="update_post.name" class="form-control">
                        </div>
                        <div class="form-group">
                            <label>Post Details:</label>
                            <textarea ck-editor ng-model="update_post.description"></textarea>
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                        <button type="button" ng-click="updatePost()" class="btn btn-primary">Publish Changes</button>
                    </div>
                </div>
                <!-- /.modal-content -->
            </div>
            <!-- /.modal-dialog -->
        </div>
        <!-- /.modal -->

Update the Post Controller from ng-script.js:

$scope.edit = function (index) {
        $scope.update_post = $scope.posts[index];
        var modal_element = angular.element('#update_post');
        modal_element.modal('show');
    };

    $scope.updatePost = function () {
        $http.post('script/update.php', {
            post: $scope.update_post
        })
            .then(function success(e) {

                $scope.errors = [];

                var modal_element = angular.element('#update_post');
                modal_element.modal('hide');

            }, function error(e) {
                $scope.errors = e.data.errors;
            });
    };

Give it a try to update your existing post from the demo it should work as showing below:

Update Post Model

Step 9 – Delete Post

Finally let’s add delete feature into the demo, open up the ng-script.js file add following method into the postController after updatePost method:

$scope.delete = function (index) {

        var conf = confirm("Do you really want to delete the post?");

        if (conf == true) {
            $http.post('script/delete.php', {
                post: $scope.posts[index]
            })
                .then(function success(e) {

                    $scope.errors = [];

                    $scope.posts.splice(index, 1);

                }, function error(e) {
                    $scope.errors = e.data.errors;
                });
        }
    };

Now if you try to delete the post from the list it should work.

let me know if you have any question related to this tutorial using comment box below:

Yogesh Koli

Software engineer & Blogger live in India, has 8+ years of experience working with the Front-end and Back-end Web Application Development.

View Comments

Recent Posts

Complete guide of using Laravel 6 Eloquent Subquery Enhancements

Learn How to use laravel frameworks new improved feature called Eloquent Subquery and get example…

3 years ago

3 Useful examples of using Array Map function in PHP – Best Practices

Learn how to use php array map function with easy and essential tutorial to modify…

3 years ago

Working with PHP Array Filter Function – Best Practices

Learn how to use php array filter function with easy and essential tutorial to filter…

3 years ago

How to add Access Modifiers with Constructor Parameters in TypeScript

Want to know how to refactor your Typescript class, Learn here utilising Typescript of the…

3 years ago

What is Access Modifiers and how to use Access Modifiers in TypeScript ?

What is Access Modifiers in typescript, how to use Access Modifiers, when to use them,…

3 years ago

Top 10 Super Useful Packages to Improve Laravel applications in 2019

This tutorial provide ultimate list of package those are top 10 on packagist and super…

3 years ago