Let's Make A Simple AJAX Note Taking App

Download

LINKTEXTIn this tutorial we will be making a simple app with PHP and jQuery that lets users write notes. The notes are going to be saved in plain text files on the server. It demonstrates how to read and write files in PHP, how to resize a textarea with jQuery, depending on the text inside it, and how to create a simple AJAX interaction.

Grab a copy of the demo from the button above and read on!

The HTML

To start off, we need to create a regular HTML5 document. I have including only the important bits below, but you can see the rest in index.php. Notice that I have placed the PHP code in the same file for simplicity.

index.php

<div id="pad">
    <h2>Note</h2>
    <textarea id="note"><?php echo $note_content ?></textarea>
</div>

That is all the markup that we need for the note! Of course, we will be heavily styling it with CSS in a few minutes. I've also included the jQuery library further down the page (before the closing body tag) along with our script.js file, but I won't be showing it here. The important thing is that PHP echo statement inside the textarea. It prints the last saved note of the user.

The PHP

The PHP code of the example is straightforward. What it does is to read and present the contents of the note on page load, and to write to it when an AJAX request is sent by jQuery. This will cause the note file to be overridden.

index.php

$note_name = 'note.txt';
$uniqueNotePerIP = true;

if($uniqueNotePerIP){

    // Use the user's IP as the name of the note.
    // This is useful when you have many people
    // using the app simultaneously.

    if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
        $note_name = 'notes/'.md5($_SERVER['HTTP_X_FORWARDED_FOR']).'.txt';
    }
    else{
        $note_name = 'notes/'.md5($_SERVER['REMOTE_ADDR']).'.txt';
    }
}

if(isset($_SERVER['HTTP_X_REQUESTED_WITH'])){
    // This is an AJAX request

    if(isset($_POST['note'])){
        // Write the file to disk
        file_put_contents($note_name, $_POST['note']);
        echo '{"saved":1}';
    }

    exit;
}

$note_content = '';

if( file_exists($note_name) ){
    $note_content = htmlspecialchars( file_get_contents($note_name) );
}

Notice the $uniqueNotePerIP variable. I am using this on the demo so that every user gets a unique note. This setting will cause each note to be saved with the visitor's IP address as a name. You can set it to false, if you want everyone to share a single note, but keep in mind that if two people edit the note simultaneously, the one that saves last will override it, and in rare cases the note itself may get corrupted.

Next up, the jQuery code!

illustration.jpg
AJAX Note Taking App

The jQuery

jQuery's job in this app, would be to listen for changes in the text area, and send them with an AJAX post request back to index.php, where the text is written to a file.

The usual approach would be to bind a handler to the keypress event, but in certain cases this won't be enough as the user may simply paste text into the textarea, choose an auto-correct suggestion by their browser or undo a change. Luckily for us, there is another event that handles all of these cases. It is the input event, which is supported by all modern browsers (read more here). You can see the code below.

assets/js/script.js

$(function(){

    var note = $('#note');

    var saveTimer,
        lineHeight = parseInt(note.css('line-height')),
        minHeight = parseInt(note.css('min-height')),
        lastHeight = minHeight,
        newHeight = 0,
        newLines = 0;

    var countLinesRegex = new RegExp('\n','g');

    // The input event is triggered on key press-es,
    // cut/paste and even on undo/redo.

    note.on('input',function(e){

        // Clearing the timeout prevents
        // saving on every key press
        clearTimeout(saveTimer);
        saveTimer = setTimeout(ajaxSaveNote, 2000);

        // Count the number of new lines
        newLines = note.val().match(countLinesRegex);

        if(!newLines){
            newLines = [];
        }

        // Increase the height of the note (if needed)
        newHeight = Math.max((newLines.length + 1)*lineHeight, minHeight);

        // This will increase/decrease the height only once per change
        if(newHeight != lastHeight){
            note.height(newHeight);
            lastHeight = newHeight;
        }
    }).trigger('input');    // This line will resize the note on page load

    function ajaxSaveNote(){

        // Trigger an AJAX POST request to save the note
        $.post('index.php', { 'note' : note.val() });
    }

});

Another useful thing that the above code does, is to count the number of new lines in the text and to enlarge the textarea automatically, depending on the value of the line-height CSS property.

And here is the CSS.

The CSS

In this section we will style the three elements you see in the HTML part of the tutorial. Each of the three elements you see there, are styled and added a background image. For the bottom part of the notepad, I am using an :after element. When the textarea is resized by jQuery, the bottom part is automatically pushed down.

assets/css/styles.css

#pad{
    position:relative;
    width: 374px;
    margin: 180px auto 40px;
}

#note{
    font: normal 15px 'Courgette', cursive;
    line-height: 17px;
    color:#444;
    background: url('../img/mid.png') repeat-y;
    display: block;
    border: none;
    width: 329px;
    min-height: 170px;
    overflow: hidden;
    resize: none;
    outline: 0px;
    padding: 0 10px 0 35px;
}

#pad h2{
    background: url('../img/header.png') no-repeat;
    overflow: hidden;
    text-indent: -9999px;
    height: 69px;
    position: relative;
}

#pad:after{
    position:absolute;
    content:'';
    background:url('../img/footer.png') no-repeat;
    width:100%;
    height:40px;
}

In addition, I have included the Courgette font from Google Web Fonts, which you can see referred in the #note block.

Done!

I hope that you liked this simple example and are full of ideas for improvements. If you need to support older IE versions that don't have the input event, I suggest you change the code so that the AJAX request is sent automatically with a timeout every 5 or 10 seconds.

Bootstrap Studio

The revolutionary web design tool for creating responsive websites and apps.

Learn more

Related Articles