-1

I am trying to make a form where the user can fill in the last name of a customer, the program then needs to use the entered name to search the database for any customers with the same last name. Then the select form element needs to be populated with the results form the query allowing the user to select the correct customers info. After the correct customer is selected another query needs to be done to search a separate table to get all addresses associated with the customer ID of the selected customer.

Flow *User enters Customer last name *query to get all customers with same last name **select box populated with customer data *User selects correct customer *query to find all addresses with same Customer ID **separate select box populated with 2nd query results

I would like to accomplish this with ajax

primo4e
  • 1
  • 3
  • 1
    There are several issues to deal with, which I will address in an answer once we narrow down the exact cause. Could you edit your post to show the form tag – Tim Morton Jan 17 '21 at 01:56
  • Tim Morton--I have included the whole form now – primo4e Jan 17 '21 at 02:03
  • You have to consider using `ajax` to accomplish your desired result, and overthink how you check incoming data, because right now you are widely open to perform SQL injection. Also good start will be to check and play with getting ajax requests back from the server in form of JSON or HTML and play with this data to fulfill your option list. – Serghei Leonenco Jan 17 '21 at 02:10
  • Serghei Leonenco-- I would love to switch to AJAX just know next to nothing about it at the moment. I will work on improving security as I go. – primo4e Jan 17 '21 at 02:13
  • I have found a section in one of my books on AJAX so I will be learning up on it and will try somethings out. – primo4e Jan 17 '21 at 02:34
  • oh, I see the problem. You should be getting an error on `$search->fetch_assoc()`. Do you have error reporting set to show all errors? Let me write up an answer that deals with some more important issues... – Tim Morton Jan 17 '21 at 02:35
  • Tim I don't get any errors. – primo4e Jan 17 '21 at 02:52
  • I appreciate every bodies help Though I have been learning to code for a while now, this is my first real project. Or at least part of it. – primo4e Jan 17 '21 at 02:54
  • I’m writing an answer, but on my phone so it will be a while... the immediate answer to your question is that `$search` is not your db object; it should be `$result`. In fact, I can’t even tell how you’re connecting, whether pdo or mysqli... but you should be getting an error for calling a method on a non object. – Tim Morton Jan 17 '21 at 03:09
  • I'm connecting in a configuration file that I attach. It's mysqli – primo4e Jan 17 '21 at 03:23
  • ah, ok. I personally think pdo is more appropriate for new users. I recommend looking at this. https://phpdelusions.net/pdo – Tim Morton Jan 17 '21 at 03:29
  • I will thank you. I do have some parts of the program that are pdo but honestly didn't make them myself just modified – primo4e Jan 17 '21 at 03:33
  • please note that although my answer uses pdo, I don’t actually use it, so use the link and docs just in case I messed up ;) – Tim Morton Jan 17 '21 at 03:53
  • This is probably too advanced for a relatively new dev, but there is a lot of gold to mine from here: https://stackoverflow.com/a/36961571/2943403 Using this technique in your AJAX called php script will be very powerful in terms of accuracy and processing speed. – mickmackusa Jan 17 '21 at 05:53
  • Does this answer your question? [How to include a PHP variable inside a MySQL statement](https://stackoverflow.com/questions/7537377/how-to-include-a-php-variable-inside-a-mysql-statement) – Dharman Jan 17 '21 at 13:31
  • Dharman--Not quite what I am looking for. I am trying to change a select html elements options based on results from a query on a table – primo4e Jan 18 '21 at 00:18

2 Answers2

1

PRG Pattern

The first thing that caught my eye was not related to your actual issue, but does play a part in debugging. What caught my eye was

if (isset($_POST['search_button'])){

after HTML output was already started. Rule of thumb, POST variables should be worked with at the top, and always redirected (except ajax). Check out the Post-Redirect-Get pattern.

However, in this case you should be using GET because you aren’t changing data, just reading specific data.

Which leads me to the debugging step

Separate Logic and Presentation

Perform all your logic first, and then when that is all done, close out php and write your html (presentation), using php only for templating (loops, filling in variables, minor presentation conditionals)

This is extremely helpful when debugging, because you don’t have to dig through extraneous html code.

So your code could be reordered to be like this:

<?php

if (isset($_GET['search_button'])){
    require_once "/home/users/web/b1240/dom.heather93124/public_html/resources/config.php";
    
    $fName = $_GET['fName'];
    $lName = $_GET['lName'];
    
// more code here
}
// any other code here
?>
<html>
    <!— and so forth —>

Prepared Statements

The time to learn better security is now. This query is wide open to sql injection. Never, never, never put a raw variable into a query. You should be using prepared statements, where the user data is treated separately from the query. This example assumes you have a PDO connection $pdo.

$stmt = $pdo->prepare("SELECT * FROM Customers Where FirstName LIKE ? AND  LastName LIKE ?");
$stmt->execute(
    [
        $_GET['fName'],
        $_GET['lName']
    ]
);

// iterate through results with $stmt->fetch()

Incorporating this change will fix the error in your code. ($search->fetch... is an error)

Wrapping It Up

<?php

if (isset($_GET['search_button'])) {
    require_once "/home/users/web/b1240/dom.heather93124/public_html/resources/config.php";

    $stmt = $pdo->prepare("SELECT * FROM Customers WHERE FirstName = ? AND  LastName = ?");
    $stmt->execute(
        [
            $_GET['fName'],
            $_GET['lName']
        ]
    );
}
?>
<HTML>
... snip ...

     <div class="form-popup" id="newApp">
        <form  method="get" class="form-container">
            <h1>New Appointment</h1>
            <label for="emp_select"><b>Select Employee</b></label>
                <select id = "emp_select" name="emp_select0">
                    <?php
                        include "/home/users/web/b1240/dom.heather93124/public_html/resources/employee.php";
    
                    ?>
    
                </select><br>
            <input type="text" name="fName" id="fName" placeholder="First name">
            <input type="text" name="lName" id="lName" placeholder="Last name"><br>
            <input type="button" class = "btn" value="Search" name="search_button"></button><br>  
            <select id = "custSelect" name="custSelect0">
            <?php while($row = $stmt->fetchObject()): ?>
                <option value="<?= $row->CustId ?>"><?= $row->fName ?> <?= $row->lName ?></option>
            <?php endwhile; ?>

... snip ...

Note that this is not tested, you may have to adjust the pdo options to your taste.

Tim Morton
  • 2,614
  • 1
  • 15
  • 23
  • Review of your review: do not use `LIKE` unless you need to use wildcard symbols. Always use ALL-CAPS when writing sql keywords/functions. Use uniform spacing when declaring tag attributes. Read PSR-12 standards regarding spacing around control structures. Use css to style text as bold instead of introducing unnecessary tags into your html document. I prefer to not use verbose `endwhile` syntax for the loop because the curly brace syntax is more concise and there is no risk of the dev getting lost. – mickmackusa Jan 17 '21 at 04:13
  • 1
    @mickmackusa I don't agree with you about not using `verbose endwhile syntax for the loop because the curly brace syntax is more concise and there is no risk of the dev getting lost`, it helps create more clear outstanding point from programming logic and `html`, and that helps to understand where the loop ends. – Serghei Leonenco Jan 17 '21 at 04:23
  • 1
    That is certainly your prerogative @Serg I find proper indentation to be sufficient ...especially when the loop body only contains one line of code. – mickmackusa Jan 17 '21 at 04:29
  • @mickmackusa I agree, that's prerogative of each programmer. – Serghei Leonenco Jan 17 '21 at 04:31
  • 1
    Also, the iterated calls of `fetchObject()` van be avoided. Just feed the result set object into a `foreach()` and access each row's data as if it was an associative array. https://stackoverflow.com/a/41426713/2943403 – mickmackusa Jan 17 '21 at 04:46
  • @mickmackusa Ah, I got a bit sloppy typing on my phone. Yes, I agree on the `LIKE`, I had intended to demonstrate wildcards and then thought better of it mid-stream. Got tired of hunt-and-peck typing so I copied the html... But point taken, thank you. FWIW My preference is to name the end tag for clarity’s sake; but yeah, when there’s only one line the benefit is negligible. – Tim Morton Jan 17 '21 at 05:01
  • I am trying it out and it is throwing a fit over the : after fetchObject() – primo4e Jan 17 '21 at 05:09
  • I missed the closing parenthesis – Tim Morton Jan 17 '21 at 05:11
  • Also, consider what mickmackusa said about `foreach`. He knows pdo much better than I do. – Tim Morton Jan 17 '21 at 05:19
  • Where does the closing parenthesis go. I was looking at hte link He gave for the foreach. Just not entirly sure how to make it work for my situation – primo4e Jan 17 '21 at 05:26
  • The `:` replaces the `{`, which allows you to “name” the closing curly brace. If it messes you up, just use the curly brace. I just think the ending tag is more specific when in the context of html. But it’s preference. I edited my answer to include the missing parenthesis – Tim Morton Jan 17 '21 at 05:35
  • 1
    To clarify about the appropriate request type to use... `$_GET` is appropriate for receiving the fName and the lName because you are merely "reading" data from the database/server. `$_POST` is appropriate for the main form as it seems you will be "writing" data to your database/server. – mickmackusa Jan 17 '21 at 05:37
0

I was able to get it all figured out. Here it is.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<div class="form-popup" id="newApp">
    <form  method="post" class="form-container" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">
        <h1>New Appointment</h1>
        <label for="emp_select"><b>Select Employee</b></label>
            <select id = "emp_select" name="emp_select0">
                <?php
                    include "/home/users/web/b1240/dom.heather93124/public_html/resources/employee.php";

                ?>
            </select><br>

        <input type="text" name="lName" id="lName" placeholder="Last name" onkeyup="showCustomer(this.value)"><br>

        <select id = "custSelect" name="custSelect" onchange="adrSelect(this)">
            <option value="">-- Select Customer--</option>

        </select><br>
        <input type="text" id="cust_id" name="cust_id" placeholder="Customer ID" readonly>
        <input type="text" id="custName" name="custName" placeholder="Customer Name" readonly><br>

        <input stlye="backroundColor:#00000020" placeholder="000-000-00000" type="tel" id="newPhone" name="newPhone" pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}">
        <input stlye="backroundColor:#00000020" placeholder="000-000-00000" type="tel" id="newAltPhone" name="newPhone" pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}"><br>

        <select id="addrSelect" name="addrSelect" onchange="addrPicker(this)">
          <option value="">-- Select Customer address--</option>
        </select><br>

        <input type="text" placeholder="#### Street Name" name="newStreet" id="newStreet"  size="40"><br>
        <input type="text" PlaceHolder="City" name="newCity" id="newCity" size="10">
        <input type="text" placeholder="State" name="newState" id="newState" size="5">
        <input type="text" placeholder="Zip" name="newZip" id="newZip" size="5"><br>

        <label for="startDate"><b>Start Date</b></label>
        <input type="date"  name="startDate" id="newStartDate" required><br>

        <label for="startTime"><b>Time</b></label>
        <input type="time"  name="startTime" id="newStartTime" required><br>

        <label for="endDate"><b>End Date</b></label>
        <input type="date"  name="endDate" id="newEndDate"><br>

        <label for="endTime"><b>Time</b></label>
        <input type="time"  name="endTime" id="newEndTime" ><br>

        <label for="status_select"><b>Appointment Status</b></label>
            <select id = "status_select0"name="status_select0">
                <?php
                    include "/home/users/web/b1240/dom.heather93124/public_html/resources/aptStatusSel.php";

                ?>
            </select><br>

        <label for="newReason"><b>Description</b></label><br>
        <input type="text" name="newReason" id="newReason" size="55"><br>

        <button type="submit" class="btn" name="newAppSubmit">Submit</button>
        <input type="reset" class="btn cancel">
        <button type="submit" class="btn cancel" onclick="closeFormNewApp()">Cancel</button>
      </form>
    </div>


    <script>
    function showCustomer(str) {
          //alert("click");
          var LastName = str;
          //var ele = document.getElementById('custSelect');
       //alert (LastName);
       $.ajax({
            url:"getcustomer.php",
            type:"POST",
            data:{customer:LastName},
            dataType: "json",

            success:function(data){
                //alert("Data: " + data + "\nStatus: " + status);

                        $('#custSelect').empty();
                        $('#custSelect').append($('<option>').text("---Select Customer---"));
                        $.each(data, function(key, entry){
                          //alert (key + ":" + entry)
                           $('#custSelect').append($('<option></option>').attr('value', entry.custId).text(entry.fname + " " + entry.lname + " -- " + entry.phone));
                          });
                        }
                      });
                    }


        function adrSelect(ele) {
          // GET THE SELECTED VALUE FROM <select> ELEMENT AND populate form with values related to customer.

          let custID = ele.value;
          //alert(custID);
          $.ajax({
            url: "getPhone.php",
            type: "POST",
            data:{custID:custID},
            dataType: "json",

            success:function(data){
                  //alert("Data: " + data + "\nStatus: " + status);
                  $.each(data,function(key, entry){
                    $('#cust_id').val(entry.custId);
                    $('#custName').val(entry.fname + " " + entry.lname);
                    $('#newPhone').val(entry.phone);
                    $('#newAltPhone').val(entry.altPhone);
                    var custID = $('#cust_id').val();
                    //alert (custID);
                    $.ajax({
                         url:"custAddr.php",
                         type:"POST",
                         data:{custID:custID},
                         dataType: "json",

                         success:function(info){


                                     $('#addrSelect').empty();
                                     $('#addrSelect').append($('<option>').text("---Select Customer Address---"));
                                     $.each(info, function(key, entry){
                                       //alert (key + ":" + entry)
                                        $('#addrSelect').append($('<option></option>').attr('value', entry.propID).text(entry.street + ", " + entry.city + ", " + entry.state + " " + entry.zip));
                                       });
                                     }
                                   });
                                 });
                               }
                             });
                           }

        function addrPicker(ele){
          let propID = ele.value;
          //alert (propID);
          $.ajax({
            url: "addrPicker.php",
            type: "POST",
            data:{propID:propID},
            dataType: "json",

            success:function(data){
              //alert("Data: " + data + "\nStatus: " + status);
              $.each(data, function(key, entry){
                $('#newStreet').val(entry.street);
                $('#newCity').val(entry.city);
                $('#newState').val(entry.state);
                $('#newZip').val(entry.zip);
              });
            }
          });
        }


    </script>

And then the scripts that are called are all pretty similar to below just adapted to that part of the code where it is called. This one is the addrPicker.php

<?php
  //login to database
  require_once "/home/users/web/b1240/dom.heather93124/public_html/resources/configPDO.php";

  if (isset($_POST['propID'])){
    //Get value of custID variable
    $propID = $_POST['propID'];

    //Declare data variable as array
    $data = array();

    try{
      //SQL query PDO
      $sql = "SELECT * FROM `custAdr` WHERE `propID` = :propID";
      //Set cust ID variable as wildcard
      //$custID = "%$custID%";
      $stmt = $connect->prepare($sql);
      //bind wildcard to sql statements
      $stmt->bindValue(':propID', $propID);
      //Execute sql statements
      $stmt->execute();

      //create associative array with results from query
      while($row = $stmt->fetch(PDO::FETCH_ASSOC)){
        $data[] = array(
          'propID' => $row["propID"],
          'street' => $row["streetAdr"],
          'city' => $row["city"],
          'state' => $row["state"],
          'zip' => $row["zip"],

        );
        }

    //echo results back to ajax success function
    echo json_encode($data);
    //catch errors from try statement
    }catch(Exception $e){
      echo $e-getMessage();
    }
}

?>
primo4e
  • 1
  • 3