Introduction

Referring to Heroes' example here, this example is totally created by Angular 2 and typescript. Some people may ask, if it is possible to do the same, using pure JavaScript instead. I decided to make a one, using JavaScript, pure JavaScript, and of course AJAX to call the Server-side functionality. At the Server-side, I coded PHP Web Service that accepts different kinds of requests (GET-POST-PUT-DELETE).
Let’s code first the Server-side
We add this piece of code to accept CORS and establish the database connection.
  1. <?php
  2. //ALLOW CROSS-ORIGIN RESOURCE SHARING CORS
  3. header('Access-Control-Allow-Origin: *');
  4. header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept');
  5. header('Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE,PUT');
  6. //-----------------------------
  7. //ESTABLISH DB CONNECTION
  8. $db_host = "hostname";
  9. $db_username = "username";
  10. $db_password="password";
  11. $db_name="DBName";
  12. $db_connection=new MySQLi($db_host,$db_username,$db_password,$db_name);
  13. if (!$db_connection)
  14. {
  15. die("Connection Error" . mysqli_connect_err());
  16. }
  17. ?>
Instead of using the virtual Server used in Angular 2, I wrote some PHP code to handle the different kinds of requests to avoid SQL injection, a prepared statement may come in handy, and more secure to handle the requests coming to the Server...
In the very first, check the kind of request and then handle each request, using if statements
  1. $verb=$_SERVER['REQUEST_METHOD'];
To get the associated row names from the result set, get the result and return get_result() into $result variable that has fetch_assoc() method.
  1. $result= $STMNT_SELECT->get_result();
The full code is given below.
  1. <?php
  2. //heroesOnline.php file
  3. //CONNECTO TO DB
  4. include_once('config.php');
  5. //PREPARED STATEMENTS
  6. //SELECT QUERY
  7. $querySelect="select id,name from heroes";
  8. $STMNT_SELECT=$db_connection->prepare($querySelect);
  9. $STMNT_SELECTBYID=$db_connection->prepare("SELECT id,name from heroes WHERE id=?");
  10. //INSERT QUERY
  11. $STMNT_INSERT = $db_connection->prepare("INSERT INTO heroes (Name) VALUES (?)");
  12. //UPDATE QUERY
  13. $STMNT_UPDATE=$db_connection->prepare("UPDATE heroes SET Name=? WHERE id=?");
  14. //DELETE QUERY
  15. $STMNT_DELETE=$db_connection->prepare("DELETE FROM heroes WHERE id=?");
  16. //CHECK VERB 'REQUEST TYPE'
  17. $verb=$_SERVER['REQUEST_METHOD'];
  18. //ARRAY TO RETURN THE RESULT SET INTO
  19. $result_set=array();
  20. //CHECK verb type
  21. if ($verb=='GET'){
  22. //Check if ID has been passed to the page
  23. if (isset($_GET['id']))
  24. {
  25. //Check if it is queryable
  26. $STMNT_SELECTBYID->bind_param("i",$_GET['id']);
  27. if ($STMNT_SELECTBYID->execute()){
  28. $STMNT_SELECTBYID->bind_result($id,$name);
  29. //CONVERT RESULT COMING FORM PREPARED STATEMENT INTO 'mysqli_result'
  30. //TO BE ABLE TO USE THE METHOD 'fetch_assoc'
  31. $result= $STMNT_SELECTBYID->get_result();
  32. $row=$result->fetch_assoc();
  33. echo json_encode($row);
  34. } else {
  35. echo 'ERROR RETURNING DATA WITH THIS ID';
  36. }
  37. } else{
  38. //if $STMNT has data
  39. if ($STMNT_SELECT){
  40. $STMNT_SELECT->execute();
  41. $STMNT_SELECT->bind_result($id,$name);
  42. //CONVERT RESULT COMING FORM PREPARED STATEMENT INTO 'mysqli_result'
  43. //TO BE ABLE TO USE THE METHOD 'fetch_assoc'
  44. $result= $STMNT_SELECT->get_result();
  45. while ($row=$result->fetch_assoc()){
  46. //printf ("%d %s <br>", $row["id"], $row["name"]);
  47. //ADD EACH ROW TO THE ARRAY
  48. $result_set[]=$row;
  49. }
  50. //RETURN JOSN OBJECT OF THE WHOLE ARRAY
  51. echo json_encode($result_set);
  52. } //IF
  53. }
  54. $STMNT_SELECTBYID->close();
  55. $STMNT_SELECT->close();
  56. } elseif ($verb=='POST'){
  57. echo 'POST method was called';
  58. $STMNT_INSERT->bind_param("s",$_POST['name']);
  59. if ($STMNT_INSERT->execute()){
  60. echo 'INSERTED';
  61. } else { echo 'INSERT_ERROR'; }
  62. $STMNT_INSERT->close();
  63. } elseif ($verb=='DELETE'){
  64. echo 'DELETE method was called';
  65. parse_str(file_get_contents('php://input'),$_DELETE);
  66. $STMNT_DELETE->bind_param("i",$_DELETE['id']);
  67. if ($STMNT_DELETE->execute() ){
  68. echo 'DELETED' . $_DELETE['id'];
  69. } else { echo 'DELETE_ERROR'; }
  70. $STMNT_DELETE->close();
  71. } elseif ($verb=='PUT'){
  72. echo 'PUT method was called';
  73. parse_str(file_get_contents('php://input'),$_PUT);
  74. $STMNT_UPDATE->bind_param("si",$_PUT['name'],$_PUT['id']);
  75. if ($STMNT_UPDATE->execute()){
  76. echo 'UPDATED';
  77. } else { echo 'UPDATE_ERROR'; }
  78. $STMNT_UPDATE->close();
  79. }
  80. //close connection
  81. $db_connection->close();
  82. ?>
Now, let’s move to the client-side.
Once the page opens, it sends a GET request to the Server to get all the heroes.
  1. //Call this on page load
  2. window.onload=function()
  3. {
  4. selectAllHeroes();
  5. }
  6. //Get all heroes form the server
  7. var selectAllHeroes=function(){
  8. xmlhttp4GET.open("GET","http://localhost:8000/HeroesWebservice/heroesOnline.php",true);
  9. xmlhttp4GET.send();
  10. }
  11. //Array to hold all heroes and filtered ones
  12. var heroes=[];
  13. var matchedHeroes=[];
  14. var hero;
Text is coming from the Server is parsed as JSON, as the Server-side function returns json_encode() of the resulting result set.
  1. //Initiate XMLHttpRequest object for GET method
  2. xmlhttp4GET=new XMLHttpRequest();
  3. //return data from the server
  4. xmlhttp4GET.onreadystatechange=function()
  5. {
  6. if (this.readyState==4 && this.status==200) {
  7. heroes=JSON.parse( this.responseText );
  8. //Draw panels and fill them with heroes data
  9. drawPanels(heroes);
  10. }
  11. }
Now, comes an important part, it combines the resulting data coming from the Server into the interactive user interface elements, using Bootstrap panels, that invokes the function drawPanls() passing heroes as an argument.
  1. //Draw panels according to the hero list
  2. var drawPanels=function(listHeroes){
  3. //collapse panel for the rows
  4. tableHeroes='<div class="panel-group" id="accordion">';
  5. //List items in the 'heroes' Array
  6. listHeroes.forEach(function(item) {
  7. tableHeroes+='<div class="panel panel-default"><div class="panel-heading">' +
  8. '<h4 class="panel-title"><a data-toggle="collapse" data-parent="#accordion" href="#panel' + item.id + '"' +
  9. ' onclick=' + '"' + 'selectOne(' + item.id + ',' + "'" + item.name + "'" + ')">' + item.name + '</a>' +
  10. '</h4></div><div id="panel' + item.id + '" class="panel-collapse collapse">' +
  11. '<div class="panel-body">' + '<h4>ID: ' + item.id + '</h4>' +
  12. '<h4>Name: ' + item.name + '</h4><br />' + '<input type="button" value="Delete" class="btn btn-danger"' +
  13. 'onclick="remove(' + item.id + ')"' + '/>'
  14. + '</div></div></div>';
  15. });
  16. tableHeroes+='</div>';
  17. document.getElementById('div_heroeList').innerHTML=tableHeroes;
  18. }
Note
There are two XML HTTP objects for GET requests, as we have two different kinds of data received from the Server, using GET request, all heroes data, and the second is one record for a hero related to the given ID.
And here is the full code.
  1. //Call this on page load
  2. window.onload=function()
  3. {
  4. selectAllHeroes();
  5. }
  6. //Get all heroes form the server
  7. var selectAllHeroes=function(){
  8. xmlhttp4GET.open("GET","http://localhost:8000/HeroesWebservice/heroesOnline.php",true);
  9. xmlhttp4GET.send();
  10. }
  11. //Array to hold all heroes and filtered ones
  12. var heroes=[];
  13. var matchedHeroes=[];
  14. var hero;
  15. //variable holding table contents
  16. var tableHeroes;
  17. //Initiate XMLHttpRequest object for POST, PUT and DELETE methods
  18. xmlhttp=new XMLHttpRequest();
  19. // Return data from the server
  20. xmlhttp.onreadystatechange=function()
  21. {
  22. if (this.readyState==4 && this.status==200) {
  23. console.log(this.responseText);
  24. }
  25. //
  26. }
  27. //Initiate XMLHttpRequest object for GET method
  28. xmlhttp4GET=new XMLHttpRequest();
  29. //return data from the server
  30. xmlhttp4GET.onreadystatechange=function()
  31. {
  32. if (this.readyState==4 && this.status==200) {
  33. heroes=JSON.parse( this.responseText );
  34. //Draw panels and fill them with heroes data
  35. drawPanels(heroes);
  36. }
  37. }
  38. //Initialize object to get data of one hero from the server
  39. xmlhttpGetById=new XMLHttpRequest();
  40. //return hero data
  41. xmlhttpGetById.onreadystatechange=function(){
  42. if (this.readyState==4 && this.status==200){
  43. hero=JSON.parse(this.responseText);
  44. document.getElementById('lbl_name').innerHTML=hero.name;
  45. }
  46. }
  47. //Draw panels according to the hero list
  48. var drawPanels=function(listHeroes){
  49. //collapse panel for the rows
  50. tableHeroes='<div class="panel-group" id="accordion">';
  51. //List items in the 'heroes' Array
  52. listHeroes.forEach(function(item) {
  53. tableHeroes+='<div class="panel panel-default"><div class="panel-heading">' +
  54. '<h4 class="panel-title"><a data-toggle="collapse" data-parent="#accordion" href="#panel' + item.id + '"' +
  55. ' onclick=' + '"' + 'selectOne(' + item.id + ',' + "'" + item.name + "'" + ')">' + item.name + '</a>' +
  56. '</h4></div><div id="panel' + item.id + '" class="panel-collapse collapse">' +
  57. '<div class="panel-body">' + '<h4>ID: ' + item.id + '</h4>' +
  58. '<h4>Name: ' + item.name + '</h4><br />' + '<input type="button" value="Delete" class="btn btn-danger"' +
  59. 'onclick="remove(' + item.id + ')"' + '/>'
  60. + '</div></div></div>';
  61. });
  62. tableHeroes+='</div>';
  63. document.getElementById('div_heroeList').innerHTML=tableHeroes;
  64. }
  65. //add() function when clicking button 'Add'
  66. var add=function(){
  67. //Get txtAdd value
  68. input=document.getElementById("txtAdd").value;
  69. //if txtAdd is not empty
  70. if (input==""){
  71. document.getElementById('spanAddError').style.display="inline";
  72. return;
  73. }
  74. //send POST requert to the server
  75. xmlhttp.open("POST","http://localhost:8000/HeroesWebservice/heroesOnline.php",true);
  76. xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  77. xmlhttp.send("name=" + input);
  78. document.getElementById("txtAdd").value="";
  79. selectAllHeroes();
  80. } //end function
  81. //Fire this on change txtAdd onkeyup
  82. var txtAdd_onChange=function(txt){
  83. if (txt.value==""){
  84. document.getElementById('spanAddError').style.display="inline";
  85. document.getElementById('btnAdd').disabled=true;
  86. }
  87. else{
  88. document.getElementById('spanAddError').style.display="none";
  89. document.getElementById('btnAdd').disabled=false;
  90. }
  91. } // end function
  92. //Fire this method on updating the entry
  93. var update=function() {
  94. input=document.getElementById("txtEdit").value;
  95. id=document.getElementById('hiddenID').value;
  96. //Send data to the server as a PUT request
  97. xmlhttp.open("PUT","http://localhost:8000/HeroesWebservice/heroesOnline.php",true);
  98. xmlhttp.send("id=" + id + "&name=" + input);
  99. //Select all heroes from the server after update.
  100. selectAllHeroes();
  101. }
  102. //Fire this on clicking a panel
  103. var selectOne=function(id,name){
  104. document.getElementById('hiddenID').value=id;
  105. document.getElementById('txtEdit').value=name;
  106. document.getElementById('lbl_id').innerHTML=id;
  107. xmlhttpGetById.open("GET","http://localhost:8000/HeroesWebservice/heroesOnline.php?id=" + id,true);
  108. xmlhttpGetById.send();
  109. }
  110. var remove=function(id){
  111. //Send data to the server as a POST request
  112. xmlhttp.open("DELETE","http://localhost:8000/HeroesWebservice/heroesOnline.php",true);
  113. xmlhttp.send("id=" + id);
  114. selectAllHeroes();
  115. }
  116. //Fire this onkeyup for txtSearch
  117. var search=function(filter){
  118. //Apply filter when txtSearch is not empty
  119. if (filter!=""){
  120. matchedHeroes=heroes.filter( n=>n.name.toLowerCase().search( filter )!=-1 );
  121. drawPanels(matchedHeroes);
  122. } else{
  123. drawPanels(heroes);
  124. }
  125. }
Note, the relative path to the Web service can be used too, but take care of the folder structure and hierarchy to get both the parts connected together.
I hope, this is useful and let me know if you still have any questions or need any clarifications
Enjoy coding.
Download the full code here.