1. Advertising
    y u no do it?

    Advertising (learn more)

    Advertise virtually anything here, with CPM banner ads, CPM email ads and CPC contextual links. You can target relevant areas of the site and show ads based on geographical location of the user if you wish.

    Starts at just $1 per CPM or $0.10 per CPC.

PHP in JavaScript?

Discussion in 'PHP' started by Xerakon, Nov 23, 2015.

  1. #1
    Good evening everyone,

    I'm having a major headache trying to get this one to work out. I have an HTML form that I'm working on that will take input and push it to a mySQL. However, some of the select boxes are populated by other mySQLs. This has been working fine and dandy so far. The issue now comes when I want to add dynamic select boxes. I've found a nice JavaScript code that allows me to do this, but when I go to integrate the php to pull the data to populate from a mySQL, it returns nothing. Here's where I'm at:

    order-add.php
    <script src="/js/addProduct.js" language="Javascript" type="text/javascript"></script>
    
    <?php
        // connect to database
        include('../scripts/dbconnect.php');
        $conn = new mysqli($db_server, $db_user_name, $db_password, $db_name);
        if ($conn->connect_error) {
            die('Database Connection Error (' . $conn->connect_errno . ') ' . $conn->connection_error);
        }
    ?>
    
    <form action="/orders-add-script" method="post">
        <table borders="0">
            <tr>
                <td>Date</td>
                <td><input type="text" name="orders_date" size="100"></td>
            </tr>
            <tr>
                <td>LoB</td>
                <td><select name="orders_lob">
                        <option value="">Select One</option>
                        <?php
                            $orders_lob_query = $conn->prepare("SELECT lob_name FROM lob");
                            $orders_lob_query->execute();
                            $orders_lob_query->bind_result($orders_lob_result);
                            while ($orders_lob_query->fetch()) {
                                echo "<option value = '$orders_lob_result'>$orders_lob_result</option>";
                            }
                            $orders_lob_query->close();
                        ?>
                </select></td>
            </tr>
            <tr>
                <td>Vendor</td>
                <td><select name="orders_vendor">
                        <option value="">Select One</option>
                        <?php
                            $orders_vendor_query = $conn->prepare("SELECT vendor_name FROM vendor");
                            $orders_vendor_query->execute();
                            $orders_vendor_query->bind_result($orders_vendor_result);
                            while ($orders_vendor_query->fetch()) {
                                echo "<option value = '$orders_vendor_result'>$orders_vendor_result</option>";
                            }
                            $orders_vendor_query->close();
                        ?>
                </select></td>
            </tr>
            <tr>
                <td>Patient</td>
                <td><input type="text" name="orders_patient" size="100"></td>
            </tr>
            <tr>
                <td>Provider</td>
                <td><select name="orders_provider">
                        <option value="">Select One</option>
                        <?php
                            $orders_provider_query = $conn->prepare("SELECT provider_name FROM provider");
                            $orders_provider_query->execute();
                            $orders_provider_query->bind_result($orders_provider_result);
                            while ($orders_provider_query->fetch()) {
                                echo "<option value = '$orders_provider_result'>$orders_provider_result</option>";
                            }
                            $orders_provider_query->close();
                        ?>
                </select></td>
            </tr>
            <tr>
                <td>Product(s)</td>
                <td><div id="dynamicInput">
                    <select name="orders_product[]">
                        <option value="">Select One</option>
                        <?php
                                $orders_product_query = $conn->prepare("SELECT product_name FROM product");
                                $orders_product_query->execute();
                                $orders_product_query->bind_result($orders_product_result);
                                while ($orders_product_query->fetch()) {
                                    echo "<option value = '$orders_product_result'>$orders_product_result</option>";
                                }
                                $orders_product_query->close();
                        ?>
                    </select>
                    </div>
                    <input type="button" value="Add product" onClick="addInput('dynamicInput');">
                </td>
            </tr>
            <tr>
                <td>Status</td>
                <td><select name="orders_status">
                        <option value="">Select One</option>
                        <?php
                            $orders_status_query = $conn->prepare("SELECT status_name FROM status");
                            $orders_status_query->execute();
                            $orders_status_query->bind_result($orders_status_result);
                            while ($orders_status_query->fetch()) {
                                echo "<option value = '$orders_status_result'>$orders_status_result</option>";
                            }
                            $orders_status_query->close();
                        ?>
                </select></td>
            </tr>
            <tr>
                <td>Refills</td>
                <td><input type="text" name="orders_refills" size="10"></td>
            </tr>
            <tr>
                <td>Provider Fax Reference</td>
                <td><input type="text" name="orders_providerfax" size="20"></td>
            </tr>
            <tr>
                <td colspan="2"><input type="submit" value="Add"></td>
            </tr>
        </table>
    </form>
    PHP:
    addProduct.js
    var counter = 1;
    var limit = 10;
    function addInput(divName) {
        if (counter == limit) {
            alert("You have reached the limit of adding " + counter + " products.");
        } else {       
            var newdiv = document.createElement('div');
            newdiv.innerHTML = "
                <select name='orders_product[]'>
                <option value=''>Select One</option>
                <?php
                    $orders_product_query = $conn->prepare('SELECT product_name FROM product');
                    $orders_product_query->execute();
                    $orders_product_query->bind_result($orders_product_result);
                    while ($orders_product_query->fetch()) {
                        echo 'test';
                    }
                    $orders_product_query->close();
                ?>
                </select>";
            document.getElementById(divName).appendChild(newdiv);
            counter++;
        }
    }
    Code (JavaScript):
    Any help would be extremely appreciated. I'm not sure if it's a quotation issue in the
    newdiv.innerHTML =
    Code (markup):
    statement, or there's something going on with inserting PHP in there, but I'm having a heck of a time trying to figure this one. Also, if ya'll have any suggestions on optimization or ways to "do it right/better", or tips/tricks/advice, please let me know!

    Thanks,
    X
     
    Last edited: Nov 23, 2015
    Xerakon, Nov 23, 2015 IP
  2. deathshadow

    deathshadow Acclaimed Member

    Messages:
    9,732
    Likes Received:
    1,998
    Best Answers:
    253
    Trophy Points:
    515
    #2
    On top of the disastrously bad outdated markup with the accessibility flaws, your thinking on this is fundementally flawed. unless you are dynamically loading that .js as a php file you can't run PHP inside it - AND even if you did, the PHP would only run ONCE at the very first page load, not every time you call that function.

    Generally speaking if you have to use PHP inside your JS, you're doing something wrong... like really wrong.

    Simple fact is PHP runs server side, if you put it into a JS file it will NEVER be able to run as browsers and most users don't have PHP. It just flat out doesn't work that way.

    IF you want to pull that type of information from the server, every time they hit "add" you'd have to use AJAX or a similar technique of pulling the data.

    But since all you are doing is cloning the name="orders_product[]" select, I'd just track down the first one in the scripting and, well... clone it.

    Really you have a lot of just bad code there... again the tables for layout, no ID's on your form elements, no labels (you've got TD's doing their job), no fieldsets, if the value is the same as the contents you don't need to say value, elements in the markup that only work when scripting is on with no server-side fallbacks for scripting off -- and even if it were tabular data (which it clearly is not) you've got TD doing TH+SCOPE's job, and have the border attribute that has no business in any HTML written after 1997 -- and that's just the markup.

    The JS has the "multiple var for nothing", markup hooking the scripting instead of the other way around, using innerHTML which the ECMA has told us for a decade and a half to stop doing, etc, etc...

    Even the PHP -- you know how you've been told "use prepare/select, use prepare/select"? Well that's only for queries that have values passed to them from the user. You've got static queries, just ::query the buggers.

    See, there are tags OTHER than INPUT, SELECT, TEXTAREA and BUTTON that are supposed to go into forms if you give a **** about people actually using them -- not everyone has perfect vision or is even sighted online. FIELDSET and LABEL have their place, and you have neither... so the first order of business would be to drag the code kicking and screaming into being properly semantically built, and cleaning up the PHP.

    	<fieldset id="products" data-dynamicAdd="product">
    
    		<legend>Products:</legend>
    		<!-- if legend proves hard to style, you can use an appropriate h1..h6 -->
    		
    		<div id="products_first">
    			<label for="products_product"_>Select One:</label>
    			<select name="orders_product[]" id="products_product">
    				<option value="" selected>none</option>
    <?php
    	// above, just a reminder, <option> is NOT a <label>
    
    	// just use $result, it's not like you're going to re-use this result set
    	$result = $conn->query('SELECT product_name FROM product');
    	while ($order = $orderResult->fetch_assoc() echo '
    			<option>', $orders_product_result, '</option>';
    	$result->free();
    	
    ?>
    			</select>
    		<!-- #products_first --></div>
    		<noscript>
    			<p>
    				This page requires JavaScript to select more than one product
    			</p>
    		</noscript>
    	</fieldset>
    
    Code (markup):
    No table needed, you want the labels to "behave" just format them as inline-block, set the width, and then vertical-align:top on them. That's how a PROPERLY built form is done -- it's a fieldset as we have a bunch of related inputs we'll be copying, DIV with an ID on it as what we're going to make copies of, a LABEL for each INPUT/SELECT/TEXTAREA with a FOR attribute pointing at the ID on their related element, and a noscript warning for good measure where we'll add the button to make more of these in the script.

    The data-dynamicAdd attribute would be our trigger for if the fieldset should have the "add" button replicated, the value inside it would be what would be put inside the input value. So for example with data-dynamicAdd set to "product" the script will generate

    <input type="button" value="Add product">

    for us. Using that as the trigger would allow us to have multiple instances of this on the page! The ID on the fieldset would have to match the DIV or other element you want to replicate.

    Gimme a few, and I'll toss together a working script, a breakdown of how it works, and live demo (without the PHP) to show how it can handle multiple fieldsets from one script instead of customizing it for each and every one of them.
     
    deathshadow, Nov 24, 2015 IP
  3. deathshadow

    deathshadow Acclaimed Member

    Messages:
    9,732
    Likes Received:
    1,998
    Best Answers:
    253
    Trophy Points:
    515
    #3
    Ok, here's the live demo:
    http://www.cutcodedown.com/for_others/xerakon/template.html

    As with all my examples the directory:
    http://www.cutcodedown.com/for_others/xerakon/

    ... is unlocked/wide open for easy access to the gooey bits and pieces.

    Follow along with this explanation in this file:
    http://www.cutcodedown.com/for_others/xerakon/dynamicAdd.js

    I the script inside a self-initiating function so that it won't conflict with other scripts if present on the page. I also pass document as "d" just so I don't have to type "document" a dozen times. This script should be called right before </body> as it requires the DOM to have been built, and it just loads faster there. Some people would wait for "onload" but considering we're manipulating the DOM I prefer to get my foot in the door BEFORE rendering starts... that and cross-browser onload is a pain in the ass and a bunch of extra code we just don't need.

    I do violate one allegedly "good rule" -- not appending values to elements --- that I kind of chuckle at. The whole point of objects is extensibility and if one is REALLY worried about that, just use verbose names unlikely to cause a conflict -- like it's REALLY unlikely anyone else is going to use "dynamicAdd_count" or "dynamicAdd_limit" on the same inputs we are generating from this script...

    Besides if there were a conflict it's not like you can't search-replace.

    Scriptwise there's a handful of helper functions I'd use to simplify event handling, quick creation of a input[button], and to "walk" all child elements of an object as when we clone that DIV, we'll need to update the ID's and FOR attributes inside it since ID's have to be unique.

    eventadd(element, eventName, handler)

    Adds an "event" hander to the element, for example:

    eventAdd(ourNewInput, 'click', function(e) { console.log('do something!!!' });
    Code (markup):
    eventProcess(event, prevent)

    Quick cross browser handler for event handlers. Events don't pass a parameter in windows, and you can't rely on that parameter having a target attribute, so you pass it (event) and if it doesn't exist, it will plug it in, either way it fixes some missing things. The "prevent" option stops the event from cascading/propagating/bubbling.

    makeButton(parent, text, handler)

    makes our <input type="button" value="text" onclick="handler()"> and appends it to the end of the parent element.

    walkAll(parent, callback)

    Goes through all child elements walking the DOM instead of waiting for the painfully slow getElementsByTagName('*'), passing each of those elements to the callback function. REALLY deep nests of tags could blow out the stack due to this functions simplicity, solution? Don't nest tags 32,768 or more deep. (a situation SO unlikely...)

    After the helpers comes the actual meat. One of the first things we'll need is a way to update the ID's on the node we are copying... and form attributes on any LABEL. Since we're inside an anonymous we don't need to get too fancy... just make a suffix variable, a function to check for ID or FOR and append the suffix to it... then when we have our clone node we just walkAll(node, updateUniqueAttributes);

    Ok, I see that look on your face, what is, a "clone node". If you have an HTML element -- like say you did a "document.getElementById('something');" that variable is a direct reference to that element. Anything you change there changes there. The Element.cloneNode makes a copy of that element separate from the original not attached to the DOM. That's where our magic is gonna happen.

    What we're going to do is clone the target DIV we want to replicate, strip the ID off the div since we don't need it, then when we want to make a new one we'll clone it again, update the ID's by appending our count as a suffix to all the label/input/select/what have you, and then insert that new NODE into the DOM before our input[button].

    So... let's skip past addFromClone(e) for a moment and go straight to actually making these as that function won't make sense yet.

    The setList variable contains a list of all fieldsets. We iterate through it copying setList'i'to the f variable as array lookups are slower than a variable, so lets only do that once inside the loop. (used ' here on the forums as brackets around i trips bbcode). We then pull the data-dynamicAdd attribute (if any) off that form as our name. If there is in fact that attribute, we go ahead and process the fieldset.

    For processing first we make that scripting only input. A really good rule of thumb is that if you can't make a page work without scripting FIRST, you shouldn't be adding scripting to it. A close second best is to show a warning and NOT put any elements into the page that only work when scripting is on.

    To that end, we make the input[button] in the script using that handy little makebutton function. I then store on the buttton as attributes (that thing I said above some folks consider bad practice then throw ten times as much code at doing) a bunch of our data we'll need for it to work ahead of time.

    The reason I do it this way is that it's VERY hard to pass variables to event handlers -- more so if you want to use one event handler for multiple instances... but the event itself contains a reference to the element that launched it -- and that's our solution, store the data we want to process on that target element. That's why I have that processEvent function so that "e" as event and "e.target" as the originating element exist and resolves properly.

    For values stored we have:

    button.dynamicAdd_count - how many we've added

    button.dynamicAdd_limit - maximum allowed copies. I let you pass that either using the data-dynamic-limit attribute on the fieldset, or default to 9. That 9 default means there would be TOTAL limit of 10. (since you can only add 9 and you start with one)

    button.dynamicAdd_clone - we clone as our baseline a copy

    We then strip off the id from that clone since we don't need or want that on the children.

    *note, I mix underscore and camelCase, using camelCase for names and underscore as a delimiter between "what it's for" and "what it is".

    So lets go back up to addFromClone -- proper browsers will pass the event which I plug into e, and use the eventProcess to make sure e and e.target exist as well as to cancel any other events that might try to trigger for clicking on it.

    Since e.target is the button that launched this event handler, we can pull our dynamicAdd_ properties off it instead of having to root around or get too "slick" with our handlers. This also avoids the slow bloat of "get a copy of things every time" nonsense bloated halfwit garbage like jQuery actively encourages.

    The if + increment method I use simplifies the logic, as putting the ++ after means the if will compare the value BEFORE the addition takes place. So we end up with the check and the increment all in one.

    IF we can add one, we clone the clone -- since we want to preserve the original state for making later copies. I set the suffix to and underscore followed by the addition count, then go through the clone to make sure all ID's (and by extension any "for" attributes pointed at the ID's) remain unique. Once that's done, we insert the new clone before the input.

    ... and that's it. So long as you follow the overall formatting of the markup provided, you can do that with ALL of your sets of selects, not just the one, just by adding the data-dynamicAdd attribute... OR any other FIELDSET so long as there's a DIV inside it containing what you want to replicate.

    Some of my methodology choices might seem odd, but the way I implemented this the code provided should work all the way back to IE 5.5, possibly even IE 5.2 Mac. YES, even with the data-attributes. Laughably IE lets you just make up your own attributes willy-nilly so you can use the HTML 5 data- attributes so long as on the scripting side you use "Element.getAttribute" instead of the modern scripting hooks for it.

    I railed against the data- attributes at first, but there are legitimate usage scenarios... problem is when people start using it to pass massive amounts of data on every blasted tag.

    I could probably do this in half the scripting if we tossed IE9/earlier support in the trash.

    Hope this helps. Tried to take the time to explain it well enough.

    Basically, for what you were doing client side, there's no reason to even get PHP involved. Once you send it to the client, work from what's there instead of trying to grab it off the server again. If nothing else, it lightens the servers load.
     
    deathshadow, Nov 24, 2015 IP
  4. Xerakon

    Xerakon Greenhorn

    Messages:
    4
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    21
    #4
    I'm not sure why I read these posts as if Patton was writing them, but it just fit the scenario.

    First and foremost, I really appreciate all of this, Deathshadow. Above and beyond - completely.

    Secondly, I should have mentioned that I am rather new to all of this. You know, the type of guy that figures out what he needs to do, then goes and googles through hundreds of stack overflow examples to try to piece a Frankenstein together. So many of the concepts are flying over my head at this moment. But that's alright - I'll dig down and figure it out (if you're willing to work with me).

    Keeping this in mind, let me take your examples and work on updating/piecing together the form first. I'll rattle the brainpan and come back for some more.

    Cheers.
     
    Last edited: Nov 24, 2015
    Xerakon, Nov 24, 2015 IP
  5. Xerakon

    Xerakon Greenhorn

    Messages:
    4
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    21
    #5
    Okay. So, going in and working on the form, I've started converting to fieldsets and labels and such. Trying to populate the select boxes from their mySQL lists has become somewhat of a headache, however. I tried working with the code you had posted above but could not get it to return results, so I returned it to its original state with some tweaks. Would you mind looking at this for optimization?

                <label for="orders_lob">Line of Business:</label>
                <select name="orders_lob" id="orders_lob">
                    <option value="" selected>Select One</option>
                    <?php
    
                        // Still need some help optimizing this.
                        $orders_lob_query = $conn->prepare('SELECT lob_name FROM lob');
                        $orders_lob_query->execute();
                        $orders_lob_query->bind_result($orders_lob_result);
                        while ($orders_lob_query->fetch()) {
                            echo '<option>', $orders_lob_result, '</option>';
                        }
                        $orders_lob_query->close();
                    ?>
                </select>
    PHP:
     
    Last edited: Nov 24, 2015
    Xerakon, Nov 24, 2015 IP
  6. Xerakon

    Xerakon Greenhorn

    Messages:
    4
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    21
    #6
    Okay, here is what I currently have for the form itself. As always, feedback is appreciated. Going to work on the scripting side now.
    <html>
    <head>
        <title>Orders-Add-Form</title>
    
        <?php
            // connect to the database
            include('../scripts/dbconnect.php');
            $conn = new mysqli($db_server, $db_user_name, $db_password, $db_name);
            if ($conn->connect_error) {
                die('Database connection error (' . $conn->connect_errno . ') ' . $conn->connection_error);
            }
        ?>
    </head>
    <body>
    
        <form action="http://secure.medrepsrx.com/orders-add-script" method="post">
            <fieldset id="fsOrderInformation">
                <legend>Order Information:</legend>
    
                <label for="tfDate">Date:</label>
                <input type="text" name="orders_date" id="tfDate" size="10">
                <br>
    
                <label for="tfProviderFax">Provider Fax:</label>
                <input type="text" name="orders_providerfax" id="tfProviderFax" size="20">
                <br>
    
                <label for="selVendor">Vendor:</label>
                <select name="orders_vendor" id="selVendor">
                    <option value="" selected>Select One</option>
                    <?php
    
                    // Still need some help optimizing this.
                    $orders_vendor_query = $conn->prepare('SELECT vendor_name FROM vendor');
                    $orders_vendor_query->execute();
                    $orders_vendor_query->bind_result($orders_vendor_result);
                    while ($orders_vendor_query->fetch()) {
                        echo '<option>', $orders_vendor_result, '</option>';
                    }
                    $orders_vendor_query->close();
    
                    ?>
                </select>
                <br>
    
                <label for="selLOB">Line of Business:</label>
                <select name="orders_lob" id="selLOB">
                    <option value="" selected>Select One</option>
                    <?php
    
                        // Insert optimized select code here.
                    ?>
                </select>
            </fieldset>
    
            <fieldset id="fsPatientInformation">
                <legend>Patient Information:</legend>
    
                <label for="tfPatient">Patient:</label>
                <input type="text" name="orders_patient" id="tfPatient" size="50">
                <br>
    
                <label for="selProvider">Provider:</label>
                <select name="orders_provider" id="selProvider">
                    <option value="" selected>Select One</option>
                    <?php
    
                        // Insert optimized select code here.
                    ?>
                </select>
                <br>
    
                <label for="selStatus">Status:</label>
                <select name="orders_status" id="selStatus">
                    <option value="" selected>Select One</option>
                    <?php
    
                        // Insert optimized select code here.
                    ?>
                </select>
    
            </fieldset>       
    
            <fieldset id="fsProducts" data-dynamicAdd="products">
                <legend>Products:</legend>
    
                <div id="divProducts">
               
                <label for="selProduct">Product 1:</label>
                <select name="orders_product[]" id="selProduct">
                    <option value="" selected>Select One</option>
                    <?php
    
                        // Insert optimized select code here.
                    ?>
                </select>
                <br>
                   
                <label for="selRefills">Product 1 Refills:</label>
                <select name="orders_refills[]" id="selRefills">
                    <option value="" selected>Select One</option>
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                    <option value="4">4</option>
                    <option value="5">5</option>
                    <option value="6">6</option>
                    <option value="PRN">PRN</option>
                </select>
                </div>
    
                <!-- Warning for no JavaScript. -->
                <noscript>
                    <p>
                        This page requires JavaScript to select more than one Product and Refills.
                    </p>
                </noscript>
            </fieldset>
    
            <!-- Submit form button. -->
            <input type="Submit" value="Add Order">
        </form>
    </body>
    </html>
    PHP:
     
    Xerakon, Nov 24, 2015 IP