Wulf

Saving Data to the Server

This is the second of five phases of the Model View Controller Tutorial series. Last time, we made an extremely simple MVC in JavaScript to help us:

  1. Cache data from the server to minimize AJAX calls
  2. Separate our model code, view code, and business logic code
  3. Maximize reuse of code

This is all well and good, but we only dealt with meaningless “item” data - our application didn’t do anything. This time we’ll begin building a simple web app to actually do something: manage simple text notes. Our app will let the user view, create, edit, and delete notes.

Demo

Check out the live demo to see it working in action. The ajax calls are programmed to fail 10% of the time to show how the UI recovers.

Architecture

Since this application does so much more than the last phase, the Controller will contain much more application logic than last time. We’ll also make extensive use of the Listener Pattern for communication between parts.

The Source Code

I highly recommend downloading the source and following along. I’ll just be including specific parts of the source in each of the next steps of the tutorial, so this is your chance to see the full source in one go.

Download It HereJQuery MVC Phase 2

Next Steps

Each of the next steps will walk through a specific user action, from mouse-click to database. Since Phase 1 covered loading in data from the server, we won’t recover that. This time, we’ll look at how a note is saved, then how it’s edited, and finally how it’s deleted.

Close
jQuery.extend({

	Note : function(json, model){

		// keep a reference to ourself
		var that = this;

		// the data of the Note
		var data = json;

		// manage undo history
		var revert_actions = new Array();

		// be able to create undo actions
		function createRevertAction(func, value){
			return function(){ func(value); }
		}

		/**
		 * return the Id of this Note
		 */
		this.getId = function(){
			return data.note_id;
		}

		/**
		 * returns the subject of this Note
		 */
		this.getSubject = function(){
			return data.subject;
		}

		/**
		 * returns the body of this Note
		 */
		this.getBody = function(){
			return data.body;
		}

		/**
		 * set the subject of this Note
		 * and keep an undo history
		 */
		this.setSubject = function(subj){
			revert_actions.push(createRevertAction(function(val){ data.subject = val; }, data.subject));
			data.subject = subj;
		}

		/**
		 * set the body of this Note
		 * and keep an undo history
		 */
		this.setBody = function(body){
			revert_actions.push(createRevertAction(function(val){ data.body = val; }, data.body));
			data.body = body;
		}

		/**
		 * update this Note with new data
		 * loaded from a json object
		 */
		this.update = function(newJson){
			data = $.extend(data, newJson);
		}

		/**
		 * confirm all changes, so notify
		 * the Model that we need to save
		 * to the server
		 */
		this.confirm = function(){
			model.updateNote(that);
		}

		/**
		 * we don't need to save our undo history anymore
		 * probably b/c a save to server went ok
		 */
		this.clearRevertActions = function(){
			revert_actions = new Array();
		}

		/**
		 * undo all changes since the last
		 * successful save
		 */
		this.revert = function(){
			while(revert_actions.length > 0){
				var action = revert_actions.pop();
				action();
			}
		}

	},

	Model: function(){
		// our local cache of $.Note objects
		var cache = new $.HashTable();

		// a reference to ourselves
		var that = this;

		// the datetime that we last
		// loaded everything
		var lastLoad = null;

		// a list of who is listening to us
		var listeners = new Array();

		// load a json response from an ajax call
		function loadResponse(data){
			lastLoad = data.dt;
			var out = new Array();
			$.each(data.notes, function(item){
				var newNote = data.notes[item];
				var cachedNote = cache.get(newNote.note_id);
				if(cachedNote){
					 // already cached, just update it
					cachedNote.update(newNote);
				}else{
					cachedNote = new $.Note(newNote, that);
					// not yet in cache, add it
					cache.put(newNote.note_id, cachedNote);
				}
				out.push(cachedNote);
				that.notifyNoteLoaded(cachedNote);
			});
			return out;
		}

		/**
		 * load lots of data from the server
		 * or return data from cache if it's already
		 * loaded
		 */
		this.getAll = function(){
			that.notifyLoadBegin();
			$.ajax({
				url: 'ajax.php',
				data : { load : true },
				type: 'GET',
				dataType: 'json',
				timeout: 1000,
				error: function(){
					that.notifyLoadFail();
				},
				success: function(data){
					if(data.error) return that.notifyLoadFail();
					that.notifyLoadFinish(loadResponse(data));
				}
			});
			return cache.toArray();
		}

		/**
		 * add a new Note with the input:
		 * @param subj the subject of the new note
		 * @param body the body of the new note
		 */
		this.addNote = function(subj, body){
			that.notifyAddingNote();
			$.ajax({
				url: 'ajax.php',
				data : { add : true,
						 subject : subj,
						 body : body },
				type: 'POST',
				dataType: 'json',
				timeout: 1000,
				error: function(){
					that.notifyAddingFailed();
				},
				success: function(data){
					if(data.error) return that.notifyAddingFailed();
					that.notifyAddingFinished(loadResponse(data));
				}
			});
			return cache.toArray();
		}

		/**
		 * delete a note with the input:
		 * @param note_id the id of the note to delete
		 */
		this.deleteNote = function(note_id){
			that.notifyDeletingNote(note_id);
			$.ajax({
				url: 'ajax.php',
				data : { 'delete' : true,
						 note_id : note_id },
				type: 'POST',
				dataType: 'json',
				timeout: 1000,
				error: function(){
					that.notifyDeletingFailed(note_id);
				},
				success: function(data){
					if(data.error) return that.notifyDeletingFailed(note_id);
					that.notifyDeletingFinished(note_id);
				}
			});
		}

		/**
		 * save a note
		 * @param a Note object
		 */
		this.updateNote = function(note){
			that.notifySavingNote(note);
			$.ajax({
				url: 'ajax.php',
				data : { edit : true,
						 note_id : note.getId(),
						 subject : note.getSubject(),
						 body : note.getBody() },
				type: 'POST',
				dataType: 'json',
				timeout: 1000,
				error: function(){
					that.notifySavingFailed(note_id);
				},
				success: function(data){
					if(data.error) return that.notifySavingFailed(note);
					note.update(data);
					that.notifySavingFinished(note);
				}
			});
		}

		/**
		 * load lots of data from the server
		 */
		this.clearAll = function(){
			cache = new $.HashTable();
		}

		/**
		 * add a listener to this model
		 */
		this.addListener = function(list){
			listeners.push(list);
		}

		/**
		 * notify everone that we're starting
		 * to load some data
		 */
		this.notifyLoadBegin = function(){
			$.each(listeners, function(i){
				listeners[i].loadBegin();
			});
		}

		/**
		 * we're done loading, tell everyone
		 */
		this.notifyLoadFinish = function(notes){
			$.each(listeners, function(i){
				listeners[i].loadFinish(notes);
			});
		}

		/**
		 * we're done loading, tell everyone
		 */
		this.notifyLoadFail = function(){
			$.each(listeners, function(i){
				listeners[i].loadFail();
			});
		}

		/**
		 * tell everyone the item we've loaded
		 */
		this.notifyNoteLoaded = function(note){
			$.each(listeners, function(i){
				listeners[i].loadNote(note);
			});
		}

		/**
		 * we're beginning to add a new note
		 */
		this.notifyAddingNote = function(){
			$.each(listeners, function(i){
				listeners[i].addingNote();
			});
		}

		/**
		 * notify everyone that we failed to
		 * add new notes
		 */
		this.notifyAddingFailed = function(){
			$.each(listeners, function(i){
				listeners[i].addingFailed();
			});
		}

		/**
		 * we're done adding new notes, tell
		 * listeners what they are
		 */
		this.notifyAddingFinished = function(newNotes){
			$.each(listeners, function(i){
				listeners[i].addingFinished(newNotes);
			});
		}

		/**
		 * notify everyone that we're starting
		 * to delete a note
		 */
		this.notifyDeletingNote = function(note_id){
			$.each(listeners, function(i){
				listeners[i].deletingNote(note_id);
			});
		}

		/**
		 * notify everyone that the delete
		 * didn't work
		 */
		this.notifyDeletingFailed = function(note_id){
			$.each(listeners, function(i){
				listeners[i].deletingFailed(note_id);
			});
		}

		/**
		 * notify everyone that the note deleted
		 */
		this.notifyDeletingFinished = function(note_id){
			$.each(listeners, function(i){
				listeners[i].deletingFinished(note_id);
			});
		}

		/**
		 * notify everyone that we're saving a note
		 */
		this.notifySavingNote = function(note){
			$.each(listeners, function(i){
				listeners[i].savingNote(note);
			});
		}

		/**
		 * notify everyone that we're saving a note
		 */
		this.notifySavingFailed = function(note){
			$.each(listeners, function(i){
				listeners[i].savingFailed(note);
			});
		}

		/**
		 * notify everyone that we're saving a note
		 */
		this.notifySavingFinished = function(note){
			$.each(listeners, function(i){
				listeners[i].savingFinished(note);
			});
		}
	},

	/**
	 * let people create listeners easily
	 */
	ModelListener: function(list) {
		if(!list) list = {};
		return $.extend({
			loadBegin : function() { },
			loadFinish : function() { },
			loadNote : function() { },
			loadFail : function() { },
			addingNote : function() { },
			addingFailed : function() { },
			addingFinished : function() { },
			deletingNote : function() { },
			deletingFailed : function() { },
			deletingFinished : function() { },
			savingNote : function() { },
			savingFailed : function() { },
			savingFinished : function() { }
		}, list);
	}
});
Close
jQuery.extend({

	/**
	 * manages an <li> element for a note
	 * @param note the Note to manage
	 * @clickFunc a function that should
	 * be called when the user clicks
	 * on the note
	 */
	NoteLI : function(note, clickFunc){
		var dom = $("<li><a href='javascript:;'></a></li>");

		dom.find('a').click(function(){ clickFunc(note) });

		this.getNote = function(){
			return note;
		}

		this.refresh = function(){
			dom.find('a').text(note.getSubject());
		}

		this.getDOM = function(){
			return dom;
		}
		this.refresh();
	},

	View: function(){

		// this will hold the dom nodes that
		// we use to display notes in the
		// list
		var doms = new $.HashTable();

		// keep a reference to ourselves
		var that = this;

		// a list of who is listening to us
		var listeners = new Array();

		// get the console
		$console = $("#ui #console");

		// get the list of notes
		$notes = $('#ui #notes ul');

		// get the add form
		$addform = $("#ui #addform");

		// get the edit form (hide it by default)
		$editform = $("#ui #editform").hide();

		// the about box
		$about = $("#ui #instr");
		$about.find("input").click(function(){
			$about.hide();
		});

		// a box to put our incoming messages
		var $messages = $("<div style='height:130px; overflow: auto;'></div>");

		/**
		 * set up the buttons to load data
		 */
		$console.append($("<input type='button' value='Clear Console'></input><br><br>").click(function(){
			$messages.empty();
		}));
		$console.append($messages);

		// the user wants to update the event
		// so validate the form, and then
		// edit the Note
		function submitEditForm(){
			var note_id = $editform.find("#noteId").val();
			var dom = doms.get(parseInt(note_id));
			var subj = $editform.find(".subject").val();
			var body = $editform.find(".body").val();
			if(subj.length == 0){
				alert("Please enter a subject for your note");
				return false;
			}
			dom.getNote().setSubject(subj);
			dom.getNote().setBody(body);
			dom.getNote().confirm();
			return false;
		}

		// set up events for the edit form
		$editform.submit(submitEditForm);
		$editform.find("#update").click(submitEditForm);
		$editform.find("#cancel").click( function(){ that.showAddForm() } );
		$editform.find("#delete").click(function(){
			var noteId = $editform.find("#noteId").val();
			that.notifyDeleteNote(noteId);
		});

		// the user wants to add a new Note
		// so validate the form, and then
		// add a new Note
		function submitAddForm(){
			var subj = $addform.find(".subject").val();
			var body = $addform.find(".body").val();
			if(subj.length == 0){
				alert("Please enter a subject for your note");
			}else{
				that.notifyNewNote(subj, body);
			}
			return false;
		}
		$addform.submit(submitAddForm);
		$addform.find("#add").click(submitAddForm);

		/**************************************
		 *  The view is now set up,          *
		 *  so let's flesh out functionality *
		 *************************************/

		// show the edit form
		// pre-populated w/ the given note
		this.showEditForm = function(note){
			$addform.hide();
			$editform.show();
			$editform.find("#noteId").val(note.getId());
			$editform.find(".subject").val(note.getSubject());
			$editform.find(".body").val(note.getBody());
			$editform.find(".subject").focus();
		}

		// hide the edit form
		// and show the add form
		this.showAddForm = function(){
			$editform.hide();
			$addform.show();
			$addform.find(".subject").focus();
		}

		/**
		 * enable or disable all inputs in a form
		 */
		function enabledForm($form, en){
			if(!en){
				$form.find(".input").attr("DISABLED","1");
			}else{
				$form.find(".input").removeAttr("DISABLED");
			}
		}

		/**
		 * set the add form's enabled state
		 */
		this.setAddFormEnabled = function(en){
			enabledForm($addform, en);
		}

		/**
		 * set the edit form's enabled state
		 */
		this.setEditFormEnabled = function(en){
			enabledForm($editform, en);
		}

		/**
		 * clear the inputs of the add form
		 */
		this.clearAddForm = function(){
			$addform.find(".input").val("");
			$addform.find(".subject").focus();
		}

		/**
		 * set the edit form's enabled state
		 */
		this.setEditFormEnabled = function(en){
			if(!en){
				$editform.find(".input").attr("DISABLED","1");
			}else{
				$editform.find(".input").removeAttr("DISABLED");
			}
		}

		/**
		 * a note was loaded/updated from the
		 * cache, so let's build / update
		 * the DOM
		 */
		this.loadNote = function(note){
			var dom = doms.get(note.getId());
			if(dom){
				dom.refresh();
			}else{
				// build a new note item
				// and put it in the list
				dom = new $.NoteLI(note, that.showEditForm);
				doms.put(note.getId(), dom);
				$notes.append(dom.getDOM());
			}
		}

		/**
		 * remove the note from view, but
		 * don't remove from cache
		 */
		this.showNote = function(note_id, show){
			var dom = doms.get(note_id);
			if(dom){
				if(show){
					$(dom.getDOM()).show();
				}else{
					$(dom.getDOM()).hide();
				}
			}
		}

		/**
		 * remove the note completely from
		 * the view, including the cache
		 */
		this.flushNote = function(note_id){
			var dom = doms.get(note_id);
			if(dom){
				$(dom.getDOM()).remove();
			}
			doms.clear(note_id);
		}

		/**
		 * show a simple text-only message in the console
		 */
		this.log = function(str){
			$messages.append(str + "<br>");
		}

		/**
		 * add a listener to this view
		 */
		this.addListener = function(list){
			listeners.push(list);
		}

		/**
		 * notify that we're trying to add a new note
		 */
		this.notifyNewNote = function(subj, body){
			$.each(listeners, function(i){
				listeners[i].newNoteClicked(subj, body);
			});
		}

		/**
		 * notify that we're trying to delete a note
		 */
		this.notifyDeleteNote = function(note_id){
			$.each(listeners, function(i){
				listeners[i].deleteNoteClicked(note_id);
			});
		}

	},

	/**
	 * let people create listeners easily
	 */
	ViewListener: function(list) {
		if(!list) list = {};
		return $.extend({
			newNoteClicked : function() { },
			deleteNoteClicked : function() { }
		}, list);
	}

});
Close
jQuery.extend({

	Controller: function(model, view){
		/**
		 * listen to the view
		 */
		var vlist = $.ViewListener({
			deleteNoteClicked : function(note_id){
				model.deleteNote(note_id);
			},
			newNoteClicked : function(subj, body){
				model.addNote(subj, body);
			}
		});
		view.addListener(vlist);

		/**
		 * listen to the model
		 */
		var mlist = $.ModelListener({
			loadBegin : function() {
				view.log("Fetching Data...");
			},
			loadFail : function() {
				view.log("ajax error");
			},
			loadFinish : function(notes) {
				var ids = "";
				$.each(notes, function(i){
					ids += (ids.length ? ", " : "") + notes[i].getId();
				});
				view.log("just loaded via ajax: " + ids);
				view.log("done.");
			},
			loadNote : function(note){
				view.log("loading single: " + note.getId());
				view.loadNote(note);
			},
			addingNote : function() {
				view.log("adding new note...");
				view.setAddFormEnabled(false);
			},
			addingFailed : function() {
				view.log("adding new note failed");
				alert("failed adding note");
				view.setAddFormEnabled(true);
			},
			addingFinished : function(newNotes) {
				$.each(newNotes, function(i){
					view.log("just added via ajax: " + newNotes[i].getId());
				});
				view.setAddFormEnabled(true);
				view.clearAddForm();
			},
			deletingNote : function(note_id) {
				view.log("deleting note " + note_id + "...");
				view.showNote(note_id, false);
				view.setEditFormEnabled(false);
			},
			deletingFailed : function(note_id) {
				view.log("deleting note " + note_id + " failed");
				alert("failed deleting note");
				view.showNote(note_id, true);
				view.setEditFormEnabled(true);
			},
			deletingFinished : function(note_id) {
				view.flushNote(note_id);
				view.setEditFormEnabled(true);
				view.showAddForm();
				view.log("note " + note_id + " deleted.");
			},
			savingNote : function(note){
				view.log("saving note " + note.getId() );
				view.setEditFormEnabled(false);
				view.loadNote(note);
			},
			savingFailed : function(note){
				view.log("saving note " + note.getId() + " failed.");
				alert("failed saving note");
				note.revert();
				view.loadNote(note);
				view.setEditFormEnabled(true);
			},
			savingFinished : function(note){
				view.log("saving note " + note.getId() + " complete.");
				view.setEditFormEnabled(true);
			}
		});
		model.addListener(mlist);

		// let's get the data
		model.getAll();
	}
});
Close
jQuery.extend({

	HashTable: function(){
		/**
		 * our local cache of $.Note objects
		 */
		var cache = new Array();
		/**
		 * a reference to ourselves
		 */
		var that = this;

		/**
		 * get contents of cache into an array
		 */
		this.toArray = function(){
			var a = new Array();
			for (var i in cache){
				a.push(cache[i]);
			}
			return a;
		}

		/**
		 * put a new item into the HashTable
		 */
		this.put = function(key, obj){
			cache[key] = obj;
		}

		/**
		 * clear out the item with
		 * the input key
		 */
		this.clear = function(key){
			delete cache[key];
		}

		/**
		 * return the item associated
		 * with key
		 */
		this.get = function(key){
			return cache[key];
		}
	}
});
Close
<html>
<head>
<link rel="stylesheet" href="demo.css" type="text/css" />
<script src="jquery.js" type="text/javascript"></script>
<script src="util.js" type="text/javascript"></script>
<script src="model.js" type="text/javascript"></script>
<script src="view.js" type="text/javascript"></script>
<script src="controller.js" type="text/javascript"></script>
<script type="text/javascript">
	$(function(){
		var model = new $.Model();
		var view = new $.View();
		var controller = new $.Controller(model, view);
	});
</script>
</head>
<body>
	<div id="ui" class="flora">
		<div id="instr" class='contain'>
			<h3>About This Demo</h3>
			<p>
			This is a demo note application for the
			<a href="http://welcome.totheinter.net/tutorials/model-view-controller-in-jquery/">jQuery
			Model-View-Controller Tutorial</a> (Phase 2)
			by <a href="http://welcome.totheinter.net/">Adam Wulf</a>.
			</p><p>
			With this application, you can add, edit, and delete simple text notes. There is
			no login, so anyone can see anything you post (and you can see what they post)
			</p><p>
			The server is set up to fail AJAX requests 10% of the time to demonstrate how the
			UI can recover from such errors.
			</p><p>
			Try it out and have fun!
			</p>
			<p>
			<input value="Close About Box" type="button"/></p>
		</div>
		<div id="notes" class='contain'>
			<h3>List o' Notes</h3>
			<ul>
			</ul>
		</div>
		<form id="addform" class='contain'>
			<h3>Add New Note</h3>
			<label for="subject">Subject:</label>
			<input name="subject" class="subject input" />
			<br/>
			<label for="subject">Body:</label>
			<textarea name="body" class="body input" ></textarea>
			<br/>
			<input type="button" id="add" value="Add Note"/>
		</form>
		<form id="editform" class='contain'>
			<h3>Edit Note</h3>
			<label for="subject">Subject:</label>
			<input type="hidden" id="noteId" />
			<input name="subject" class="subject input" />
			<br/>
			<label for="subject">Body:</label>
			<textarea name="body" class="body input" ></textarea>
			<br/>
			<input type="button" id="update" value="Update"/>
			<input type="button" id="delete" value="Delete"/>
			<input type="button" id="cancel" value="Cancel"/>
		</form>
		<div id="console" class='contain'>
			<h3>Console</h3>
		</div>
	</div>
</body>
</html>
Close
<?
include "config.php";

$mysql = mysql_connect(DB_HOST, DB_USER , DB_PASSWORD);
mysql_select_db(DB_NAME, $mysql);

// run a query on mysql,
// and throw an exception if there's
// a problem
function query($sql){
	global $mysql;
	$result = mysql_query($sql, $mysql);
	if(mysql_error($mysql)){
		throw new Exception("mysql error");
	}
	return $result;
}

try{
	/**
	 * randomly fail to show
	 * how the UI recovers when the
	 * server can't process a request
	 */
	if(!isset($_REQUEST["load"]) && rand(1, 100) < 10){
		throw new Exception("a fake error to show how the UI"
			." does error correction when the server dies.");
	}

	// get one note from the DB
	function sql_getNote($id){
		if(!is_int($id)) throw new Exception("argument to " .
			__METHOD__ . " must be an int");
		return "SELECT * FROM `notes` WHERE `note_id`='" . $id . "'";
	}

	// add a note to the DB
	function sql_addNote($subj, $body, $dt){
		if(!is_string($subj)) throw new Exception("argument to " . __METHOD__ . " must be a string");
		if(!is_string($body)) throw new Exception("argument to " . __METHOD__ . " must be a string");
		if(!is_string($dt)) throw new Exception("argument to " . __METHOD__ . " must be a string");
		return "INSERT INTO `notes` (`subject`, `body`,`dt_added`,`dt_modified`) "
			. "VALUES ('" . addslashes($subj) . "','" . addslashes($body) . "','"
			. addslashes($dt) . "','" . addslashes($dt) . "')";
	}

	// get all notes from the DB
	function sql_getAllNotes(){
		return "SELECT * FROM `notes` ORDER BY dt_added ASC";
	}

	// delete a note from the DB
	function sql_deleteNote($id){
		if(!is_int($id)) throw new Exception("argument to " . __METHOD__ . " must be an int");
		return "DELETE FROM `notes` WHERE `note_id`='" . $id . "'";
	}

	// save a note to the DB
	function sql_editNote($id, $subj, $body, $dt){
		if(!is_int($id)) throw new Exception("argument to " . __METHOD__ . " must be an int");
		if(!is_string($subj)) throw new Exception("argument to " . __METHOD__ . " must be a string");
		if(!is_string($body)) throw new Exception("argument to " . __METHOD__ . " must be a string");
		if(!is_string($dt)) throw new Exception("argument to " . __METHOD__ . " must be a string");
		return "UPDATE `notes` SET `subject` = '" . addslashes($subj) . "', `body` = '"
			. addslashes($body) . "', `dt_modified` = '" . addslashes($dt)
			. "' WHERE `note_id`='" . $id . "'";
	}

	if(isset($_REQUEST["delete"])){
		//request to delete a note
		$note_id = (int) $_REQUEST["note_id"];
		$result = query(sql_deleteNote($note_id));
		$ret = array();
		$ret["error"] = false;
		echo json_encode($ret);
	}else if(isset($_REQUEST["edit"])){
		// request to modify subj/body of a note
		$note_id = (int) $_REQUEST["note_id"];
		$subject = $_REQUEST["subject"];
		$body = $_REQUEST["body"];
		$dt = gmdate("Y-m-d H:i:s");
		$result = query(sql_editNote($note_id, $subject, $body, $dt));
		$ret = array();
		$ret["error"] = false;
		$ret["dt_modified"] = $dt;
		echo json_encode($ret);
	}else if(isset($_REQUEST["add"])){
		// request to add a new note
		$dt = gmdate("Y-m-d H:i:s");
		$subject = $_REQUEST["subject"];
		$body = $_REQUEST["body"];
		$result = query(sql_addNote($subject, $body, $dt));
		$note = array();
		$note["note_id"] = mysql_insert_id($mysql);
		$note["dt_added"] = $dt;
		$note["dt_modified"] = $dt;
		$note["subject"] = $subject;
		$note["body"] = $body;
		$ret = array();
		$ret["error"] = false;
		$ret["notes"] = array($note);
		echo json_encode($ret);
	}else if(isset($_REQUEST["load"])){
		// request to load all notes
		$ret = array();
		$ret["error"] = false;
		$ret["dt"] = gmdate("Y-m-d H:i:s");
		$ret["notes"] = array();
		$result = query(sql_getAllNotes());
		while($row = mysql_fetch_array($result)){
			$ret["notes"][] = $row;
		}
		echo json_encode($ret);
	}else{
		// the client asked for something we don't support
		throw new Exception("not supported operation");
	}

}catch(Exception $e){
	// something bad happened
	$ret = array();
	$ret["error"] = true;
	$ret["message"] = $e->getMessage();
	echo json_encode($ret);
}

// close DB connection to clean up
mysql_close($mysql);

?>
Close
<?

// ** MySQL settings ** //
define('DB_NAME', 'yourDB');    // The name of the database
define('DB_USER', 'yourUser');     // Your MySQL username
define('DB_PASSWORD', 'yourPassword'); // ...and password
define('DB_HOST', 'yourHost');    // 99% chance you won't need to change this value

?>
Close
CREATE TABLE `notes` (
  `note_id` bigint(20) NOT NULL auto_increment,
  `dt_added` datetime NOT NULL,
  `dt_modified` datetime NOT NULL,
  `subject` varchar(255) NOT NULL,
  `body` longtext NOT NULL,
  PRIMARY KEY  (`note_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

Email This Page Email This Page

1 Comment

1 response so far ↓

  • 1 ajlozierNo Gravatar // Dec 28, 2008 at 1:05 pm

    this is very interesting. i am wondering how you might go about extending this into more of a framework, where you create more specific classes that extend base model, view and controller classes.

Leave a Comment