Hi guys,

I was hoping some one could help me with a problem im having with Ajax.
Im very new at Ajax and don't really understand it completely.

My current situation is as follows:

1: I have a main page which loads a flowchart.gif image.
2: Along side the flowchart image are small button images, they are also .gif. Each button relates to a procedure in the flowchart.
3: Each button image contains a hotspot link to another window using JavaScript.
4: All this is loaded using php and mysql which retrieves the buttons and flow chart from a database.

Now for the Ajax problem. When a user clicks a edit button a list of buttons appear on the page.
What I want to happen is when a user wants to add a button image to the current flow chart buttons he clicks on one of the buttons from the button list that appeared when the edit button was clicked and the button is added to the flowchart buttons.

Now at the moment I have managed to allow one button to be added to the flow chart buttons list using ajax, however, when I click on another button nothing happens.
I need the Ajax to keep adding the buttons the user clicks on to the flowchart buttons list. A sort of a recursive Ajax function!

Like I said im very new to ajax so I hope this is possible.
Below is my ajax.js functions:

function getXMLHttp()
{
  var xmlHttp

  try
  {
    //Firefox, Opera 8.0+, Safari
    xmlHttp = new XMLHttpRequest();
  }
  catch(e)
  {
    //Internet Explorer
    try
    {
      xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
    }
    catch(e)
    {
      try
      {
        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
      }
      catch(e)
      {
        alert("Your browser does not support AJAX!")
        return false;
      }
    }
  }
  return xmlHttp;
}

function MakeRequest()
{
  var xmlHttp = getXMLHttp();
 
  xmlHttp.onreadystatechange = function()
  {
    if(xmlHttp.readyState == 4)
    {
      HandleResponse(xmlHttp.responseText);
    }
  }
  xmlHttp.open("GET", "../ajax.php", true);
  xmlHttp.send(null);
}

function HandleResponse(response)
{
  document.getElementById('ResponseDiv').innerHTML = response;
}

I'm not sure I fully understand. Do you want a 2-level (or n-level) hierarchy of buttons (ie. buttons organised into groups)? If so then Ajax is overkill. You could download the whole button hierarchy as a set of nested javascript objects, together with a set of routines for displaying & navigating the hierarchy and for initiating flowchart building actions.

Ajax seems like a very reasonable approach to implementing the building of your flowchart itself, but not really necessary for showing/hiding the controls (buttons).

Or have I completely misunderstood?

Airshow

I'm not sure I fully understand. Do you want a 2-level (or n-level) hierarchy of buttons (ie. buttons organised into groups)? If so then Ajax is overkill. You could download the whole button hierarchy as a set of nested javascript objects, together with a set of routines for displaying & navigating the hierarchy and for initiating flowchart building actions.

Ajax seems like a very reasonable approach to implementing the building of your flowchart itself, but not really necessary for showing/hiding the controls (buttons).

Or have I completely misunderstood?

Airshow

Hi there,

haha, I think you misunderstood me

I'm not sure I fully understand. Do you want a 2-level (or n-level) hierarchy of buttons (ie. buttons organised into groups)? If so then Ajax is overkill. You could download the whole button hierarchy as a set of nested javascript objects, together with a set of routines for displaying & navigating the hierarchy and for initiating flowchart building actions.

Ajax seems like a very reasonable approach to implementing the building of your flowchart itself, but not really necessary for showing/hiding the controls (buttons).

Or have I completely misunderstood?

Airshow

Hi there,

haha, I think you misunderstood me!! sorry im horrible at explaining things.
Let me try again.

Basically at the moment I have to groups of buttons.
Group 1 of buttons are populated when the main page load via a database.
Group 2 of buttons are populated from the database but only when a user clicks a edit button.
Now what I have at the moment is when Group 2 of buttons is loaded the user clicks any of these buttons to add to the Group 1 of buttons. I used ajax so that the Group 1 of buttons is updated immediately. However, at the moment the ajax is only allowing for one button to be added to the Group 1 of buttons. When ever I click another button in Group 2 nothing happens.

Now each button in Group 2 has a javascript link to the ajax functions as shown below:

<a href='javascript:MakeRequest()'> <img border='0' src=$button_list_value width='35' height='28'></a>

Now the MakeRequest() function looks as follows:

function MakeRequest()
{
  var xmlHttp = getXMLHttp();
 
  xmlHttp.onreadystatechange = function()
  {
    if(xmlHttp.readyState == 4)
    {
      HandleResponse(xmlHttp.responseText);
    }
  }
  xmlHttp.open("GET", "../ajax.php", true);
  xmlHttp.send(null);
}

The HandleResponse() function looks as follows:

function HandleResponse(response)
{
  document.getElementById('ResponseDiv').innerHTML = response;
}

Now like I said before I don't really understand ajax at this stage but what I do know is that the MakeRequest() function only works once. When ever I call the MakeRequest() function more than once nothing happens.
Thats what I meant when I said I need a recursive ajax function that will add a button to Group 1 ever time a button in Group 2 is clicked.
Hope this explanation is clearer than the one I had before??
Do you think you can help?

haha, I think you misunderstood me!! sorry im horrible at explaining things.

The problem was all mine, but I think I have it now and I think I can see why your code appears not to be working. ../ajax.php is always called exactly like that with no variation, therefore (unless it does some tricky stuff) then its response will always be the same. Similarly, HandleResponse() always does exactly the same thing with no variation every time it is called. It accepts the same parameter and stuffs it into the same place - ResponseDiv .

If I'm right, the nett effect is that whatever button was added successfully to your Group 1 on the first occasion, is overwritten by a second, third, fourth etc. identical button on subsequent occasions. So the code appears not to be working but actually is - it's just doing the same thing over and over with no visible effect after the first shot.

As far as I can see, you need to adjust the code in two ways:

  1. Call ../ajax.php in such a way that it produces a different response (ie a different button) each time it is called. This would typically be done by requesting something like ../ajax.php?action=5&value=21 . The part after the ? is the query string, which will appear in the php script as $_GET and $_GET. I think you need something like this to instruct ../ajax.php exactly how to behave.
  2. Amend HandleResponse() such that it adds to, rather than replaces the innerHTML of ResponseDiv . Something like the following may work, though it's hard for me to know without seeing exactly how the AJAX response is composed and the screen layout you need to achieve:
    function HandleResponse(response) {
        //This appends to the innerHTML rather than replaces it
        document.getElementById('ResponseDiv').innerHTML += response;
    }
    
    or
    
    function HandleResponse(response) {
        //This wraps response in a new div, which is then added to 'ResponseDiv'.
        var d = document.createElement('div');
        d.innerHTML = response;
        document.getElementById('ResponseDiv').appendChild(d);
    }

Give these a try and let us know how you get on.

Airshow

WOW, thank you so much!!
Both your ideas work, but your second suggestion to change the HandleResponse() function was exactly what I was looking for!!

Thank you once again for your help, now I definitely understand ajax a lot better!!

Take care

Hello again.

I thought your solution worked until I tried to pass the id number of the button the user clicked to the MakeRequest() function and then to the ajax.php like you said with the $_Get.

However, when I do that and insert that $_Get into my SQL query the button image does not show!!

Below are the changes I made:
To get each buttons id number from the database to the MakeRequest() function I used the following code:

<a href='javascript:MakeRequest(\"$button_id_value\")'> <img border='0' src=$button_list_value width='35' height='28'></a> &nbsp

As you can see in the above code I send the id value to the ajax method MakeRequest function with the '$button_id_value' variable.

In the MakeRequest() function I made the following changes:

function MakeRequest(id)
{
  var xmlHttp = getXMLHttp();
  var button_id = id;
   
  xmlHttp.onreadystatechange = function()
  {
    if(xmlHttp.readyState == 4)
    {
      HandleResponse(xmlHttp.responseText);
    }
  }
  xmlHttp.open("GET", "../ajax.php?value=button_id", true);
  xmlHttp.send(null);
}

Now I have tested my changes and I found out that when I add the variable, '?value=button_id' to the 'xmlHttp.open("GET", "../ajax.php?value=button_id", true);' the button image does not show.

My ajax.php code looks as follows:

<?php

  include ("db_conn.php");
  
  $button_id = $_GET['value'];
     
  $button_query = "SELECT * FROM button_temps WHERE button_temps.id = $button_id";
     
  $button_results = mysql_query($button_query);
  
  $create_button = "";
     
  $button = "button_temp";
 
  $row = mysql_fetch_array($button_results);
             
  $button_value = $row[$button];
               
  $create_button = "<img border='0' src=$button_value width='35' height='28'></br>";
  
  echo $create_button;  
  
?>

Now I don't know if I'm adding the variable to the ajax.php request in the MakeRequest() function!!

What do you think??

Cheeki,

There's certainly a problem in MakeRequest where you build the query string for ajax.php . In javascript you must explicitly concatenate string fragments unlike in php, where you can "embed a $variable in a double-quoted string".

Therefore try the following:

replace :
  xmlHttp.open("GET", "../ajax.php?value=button_id", true);
with :
  xmlHttp.open('GET', '../ajax.php?action=getButton&value='+button_id, true);

( action=getButton is an extra feature - explained below)

Now I don't know whether or not that's the only problem. Try my suggested change, then you might like to consider the following in ajax.php :

<?php
include ("db_conn.php");
$action = isset($_GET['action']) ? htmlspecialchars($_GET['action']) : '';
switch ($action) {
	case 'getButton':
		$button_id = isset($_GET['value']) ? intval($_GET['value']) : null;
		if($button_id != null){
			$button_results = mysql_query("SELECT * FROM button_temps WHERE button_temps.id = $button_id");
			$row = mysql_fetch_array($button_results);
			echo sprintf('<img border="0" src="%s" width="35" height="28">', $row['button_temp']);
		}
		else echo '';
		break;
	case 'another_action':
		//action code goes here 
		break;
	case 'yet_another_action':
		//action code goes here
		break;
	default:
		echo '';
}
?>

NOTES:

  1. The variable $action together with the switch/case structure allows ajax.php to be a general purpose workhorse for all your ajax queries in this project. This avoids the need for a plethora of small php files as would otherwise happen as your use of AJAX grows.
  2. Empty string is returned in failure cases.
  3. For security, $action and $button_id are sanitised with htmlspecialchars() and intval() . They also acquire default values of '' and null if $_GET['action'] and $_GET['value'] are not present.
  4. The 'getButton' block is basically a simplified version of yours, avoiding the need for several intermediate variables. sprintf() is a convenient function for building strings (see php manual).
  5. I removed the <br /> from the end of the returned <img> string, for more flexibility client-side, where <br /> can be appended if required. (By wrapping the <img> in a <div>, we don't need a <br />).

The html for the clickable button looks ok but you might like to construct it like this :

$button = sprintf('<a href="" onclick="MakeRequest(\"%s\");return false;">%s</a>', $button_id_value, makeButton($button_list_value));

where makeButton is the function defined above. Javascript: urls are very 1990s, <a href="" onclick="...; return false;"> is preferred these days.

I've not tested any of this php so it may contain typos etc.

I'll be interested to know if any of it works.

Airshow

Hey there,
Everything you suggested worked brilliantly!! Haha, I keep finding things that I need!! Im so sorry!

1)
How would I remove a button from the list of buttons the Ajax’s created??
All that needs to happen is when a button “remove button” is clicked it must remove a button from the buttons just added to the Group 1 of buttons.

2)
When the user clicks a button from Group 2 that he wants to add to the Group 1 buttons the button needs to be saved into the database so that when the page is loaded again in the future the newly added buttons also show. Now obviously it will be dump or create too much overhead if every time you clicked the button that it writes to the database. Instead have something like when you click a button “Apply” it writes all the newly created buttons to the database in one go.

how would you go about creating these two functions??

I'm going to have to buy you a bottle of bubbly for all your help!! haha.

Kind Regards

Cheeki,

Does this project have a user login system?

If so then we'll use it to save current button config for each user, if not then we must either install one or use a cookie to save current button config on the user's computer.

Login system is preferred as it makes each user's config portable from computer to computer. Cookie approach means that config is not portable, and that another user at user-X's computer will see user_X's buttons (and will have the power to change them).

Button removal should be fairly trivial.

Must go do some <yuk>real work</yuk> now. At least I got an hour on my friend's boat this morning. Back again later.

Airshow

Hello there,

I have not explained the system completely or we miss understood each other :-)

The systems main use is to show the user flowcharts that have been created in visio and converted to .gif files to be shown on the website. Each flowchart has associated buttons and each button has associated popups. My database is set up in the same manner.

Now my previous question relates to storing newly created buttons into the database like a batch process and not storing the buttons into the database every time you add a new button because that will create to much overhead and the admin guy adding the new buttons to a certain flowchart might decide to remove a button that he just added by mistake or something like that.
Hope it makes more sense now.

There was no login in place but I'm in the process of creating one, however, the login is not very important because this will be used in a intranet.

hope you enjoyed ur real world work :-)
regards

Cheeki,

Aha, my login question seems to be a red herring then. I didn't realise we're talking about an admin function here. I thought that each user was to be allowed to maintain their own set of buttons. Doh!

I have been playing around with the code on The Terminator, my development machine, and think I have a better understanding of it now.

Must do a little more work to allow buttons to be successfully removed (adding is easy).

I think adding/removing can be done 100% client-side by downloading all the relevant button definitions as javascript objects, then manipulating the interface with DHTML. This would make editing interactions extremely fast - no server involvement necessary until the user hits "save". Our use of AJAX would change from one of button retreival from the db, to that of saving the current button configuration.

My current code contains some simple db-emulation (a mix of hard-coding and use of the $_Session) as I haven't set up a proper db. But with all db interactions factored into a couple of functions, you should have little trouble converting back to sql.

Leave it with me to play with, then I'll post my code.

Airshow

Hi,

Sounds like you have a brilliant idea at hand! Can't wait to see it!
I agree adding things are usually easier, its the removing which posses certain constraints!!

I have created a successful admin login just having some trouble with hiding certain functions but I'm sure i will be able to get it work before I pass out!!

take care

If my idea goes to plan Cheeki, then removal will be trivial because I'm going to cheat!!!! - :evil - but you'll like it.

Airshow

AAH, now I definitely can't wait to see what you have planned!!!

Hello there,

Any update on the removing of the ajax buttons and the batch storing of the buttons??

Kind regards

Hi Cheeki,

All sorts going on her over the last 2 days, so I'm running behind. The code is starting to look good though. Needs a bit more testing and some tidying up.

Will post soon, maybe tonight or some time tomorrow (Sunday).

Airshow

Cheeki,

Whoops later than predicted. Too many interruptions.

Not too sure I've hit the nail on the head, but think this is the sort of thing you described (just the buttons, no flowchart stuff). It's not complete yet but good enough to show you where I'm going.

The code is a good bit more involved than I expected but the good news is that in forcing myself to work without a database, I may have hit on a good scheme with advantages over a database. I unearthed a php "Cache" class from an old project and it does a great job of reading/writing little text files to store attributes.

It's a bit techie as it stands in that to change some aspects you need to edit the cache files manually. This is less than straightforward in that they contain serialized arrays - they ain't friendly! However, with a little more effort additional UI facets could be created to overcome this.

The schema allows you to define one or more categories (they are directories in the source) containing button graphics. This drives the content of user interface. Each category comprises "active buttons" and "available buttons", which can be made to align vertically or horizontally by changing settings in the main file index.htm (this is the file you browse).

In Normal mode the active buttons will (eventually) attach to handlers that do your flowchart building. In Edit mode buttons are moved between active and available. A save button in each category allows it to be saved; this is the only part that uses AJAX. Everything else is downloaded at launch and runs client-side.

The attached version contains two categories, Category 1 and Category 2. You can change these by changing the directory names, which propagate through to the user interface.

To install, unzip the attachment and upload to your web server. If it's *nix then you will most probably need to use CHMOD the buttons directory. 755 should do it; if not try 777. I developed under Windows so I didn't need to do this.

There's currently a flaw in the logic which makes it sensitive to button additions and deletions within categories. I will cure this asap. Meanwhile, adding and deleting categories is safe.

To create a new category, add a new directory to the buttons directory, name it, then copy some or all the five button gifs from Category 1 (in reality you would create new button graphics in photoshop). The other files in the category directory are created automatically, reflecting default values. To give the new category its own background color you can edit its cache.txt .

That's all I can think to tell you at the mo but I'm sure there will be more to say. Please feel free to ask questions and let me know where it fails to meed your spec.

Airshow

WOW!! when i looked at your example in the browser it was exactly what i have been looking for but then i looked at your code!!!! WOW!!
it will take me a few days to sort out where what has to go in my system and to make use of my database but im sure i will be able to!!

Just busy writing exams now so will only be able to get into it fully after the 25th of this month.
But thank you so so much for your help!! you definitely went all out!!
I will be in contact when i start reviewing your code!!

Take care
Thank you again!!!!

Cheeki,

That's great. I kept wondering if I might be going in the wrong direction.

The code has been written with integration in mind - ie. fitting in with your flowchart code. That said, and apart from the issues already mentioned, I still need to get the global namespaces cleaned up in both php and javascript. That will be important if the code is to coexist with the flowchart handlers.

And I'll add comments to highlight the candidates for conversion to sql/database working.

I'll definately be able to post another version by the 25th.

Good luck in your exams.

Airshow

Cheeki,

Your buttons have taken on a life of their own and have been quite absorbing, which has been good for me as I haven't done any interactive application building for some time.

The javascript is as tidy as I can make it. The php is tidy as far as it goes (much of it is organised into classes) but can't go further without assuming php5 (it was tested under php4 but should run under 5).

You will see that I've added a couple of interfaces for managing category properties (presentational aspects) and button properties within each category (tooltips and "handlers").

Handlers are text strings that determine the action each button performs (ie for building/amending flow-charts). When you click on a button, you will see an alert which tells you which file to edit to fully implement the handlers and thus integrate with your main application. You will eventually comment out my alert.

The behaviour of the code is detemined in part by a bunch of constants in the file "php_includes/config.php". Here you can set directory paths and various strings that appear in the user interface, and the like.

The unusual syntax used for defining constants in config.php is because I use a "$constants" class (written for another project), which allows all constants defined in this way to be inspected on the page "settings.php". Further constants can still be defined elsewhere with the straightforward php define() as required.

I've tried to make it easy for you to inetegrate with your login sytstem. An important constant in this regard is "USER_MODE" which is currently set to "admin". When you get your login system working, then you will need to ensure that for anyone with admin rights, you define('USER_MODE', 'admin') . For anyone else, then define('USER_MODE', 'normal') . You will do this in a file of your choosing (part of your login code), not config.php. You will comment out my line $constants->addConstant('USER_MODE', 'admin'); such that your own code determines the value of USER_MODE.

I suggest that your login script is contained in a single php include file and included in all pages by adding a line to the file "php_includs/common.php", which is key to making a number of classes available to all pages.

Finally, I looked at what would be necessary to convert to database storage and consider it unnecessary, and complex unless you are an sql whizz. If you really must, then each instance of the "Cache" class is a candidate for conversion but "Cache" is very robust (once you got CHMOD correct on your *nix server directories).

I will confuse us both if I try to describe in any greater detail. Some of the code is rather tricky to follow but hopefully you won't need to touch it. I have tested quite rigorously and in-code comments will help.

Oh yes, it's completly OTT in one particular regard but I will let you find that for yourself.

Airshow

Wow....wow....wow, I'm actually speechless!!! You have out done yourself! Thank you so much!!!!!
Im still writing exams, will finish my last one tomorrow and then its me and ur code :-) I will try implement it into my project and if any problems i know where to find you!!

Thank you once again, i love the category properties & the Button properties, very nice touch and that will come in handy!

Hope you well
Take care

Cheeki, when I find time I will create a sample "application page" to demonstrate how to integrate with your flow-chary builder.

It won't be immediately obvious how to style things with your own CSS and there's another aspect I'm not sure about myself. A sample application page may be worth all the rest put together.

Airshow

Hello there,

Has been a long time :-) had a great holiday but now its all back to work!!!
I had a look at your buttons and it all works perfectly, however, its kinda over my head and i have no clue where to change what to get the buttons to work with a database.
Another thing with the buttons functionality is how they work.
Group 1 Buttons are the buttons associated with the flow chart image.
Group 2 Buttons are template buttons that the admin can click on to add to the group 1 buttons however when the admin clicks on a button in group 2 it must appear in group 1 but it must not be taken away from group 2 because they are templates.
Now when the admin wants to remove a button from the group 1 of buttons he clicks on a button and the button must basically dissapear, it must not be added to group 2 of buttons!!

Hope this makes sense

Kind Regards
Cheeki

It's been a while Cheeki. Holiday sounds like fun, I must try it some time.

I'm afraid I forgot all about my promise to make a sample application. Other things have been going on.

I'll will take a wee while to digest your points above, then will post here again.

Airshow

I had a look at your buttons and it all works perfectly, however, its kinda over my head and i have no clue where to change what to get the buttons to work with a database.

I'm not too sure what level of database interaction you have in mind Cheeki, but here are my thoughts.

Flowchart Database
The buttons are designd to integrate with your main application (flowchart creation/manipulation) by each making a call to an admin-defined JavaScript function - a "button handler". I envisage interacton with the flowchart and its database as a bunch of AJAX calls from these button handlers.

Button Database
As written my code is effectively a freestanding application which allows buttons to be included/excluded from each of any number of admin-definable sets (you may only require one set but more than one is a built in feature). The "database" for the buttons is the server's filing system, with admin-created directories containing the button graphics (gifs) and settings files generated automatically by the php code. Interaction at this level is via an FTP client. All of this could, if you have time on your hands, be recreated in an sql database. There would in all probability be a performance advantage in doing this, but it would be measured in tens of milliseconds per user admin/user session - maybe a second at the outiside. With regard to server-load, this might be a consideration for a 100,000 page impressions per day internet web site but not for an intranet-served company facility.

Group 1 Buttons are the buttons associated with the flow chart image.
Group 2 Buttons are template buttons that the admin can click on to add to the group 1 buttons however when the admin clicks on a button in group 2 it must appear in group 1 but it must not be taken away from group 2 because they are templates.
Now when the admin wants to remove a button from the group 1 of buttons he clicks on a button and the button must basically dissapear, it must not be added to group 2 of buttons!!

This is not quite what I coded. I hadn't appreciated the "template" nature of the grp 2 buttons. Could you explain more please.

Airshow

This question has already been answered. Start a new discussion instead.