How do I accurately and elegantly reference JQuery libraries so that they're "seen" by included files?

I'm working on an app that has a tangled ball of wire going on as far as the number of "includes" that are represented. By that I mean, you'll have an index page that has a bank of "include('some_file.php') files in the header that will draw from directories that are three or four levels removed from the page you're looking at.

The problem is that on these included files, they're depending on JQuery libraries are not being seen because of the dynamic of the "include." For example...

index.php page - I'll have my JQuery library referenced in a "js" folder in the root directory.
           |_
                an included file on that index page that has some JQuery as part of the syntax. But because it's looking for a JQuery library that's referenced as a relative URL on the
                index.php page, the included file doesn't "see" it and it throws an error.

This is happening frequently and I've solved the problem by using a PHP script to retrieve the base URL and then build the correct web address so that I've got the equivalent to an absolute URL, but with the built in ability to move my app to a different server and not get in trouble.

My question is: Is there an more elegant way to do this? Does PHP have a function that establishes a dynamic where you don't wind up with broken links to various libraries once you start incorporating "includes" like what I've got described above?

What do you think?
brucegustPHP DeveloperAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Julian HansenCommented:
I am not sure I follow you - when you say include - are you talking about a PHP include?

PHP has no bearing on the interpretation of where jQuery is located - that is a rendered HTML issue - maybe I am not understanding the full story here?

In PHP an include becomes part of the script that includes it - so if you have index.php and include('some/path/to/nowhere/file.php'); - the physical location of that file is only relevant in that it points to something the compiler can load - after that it it becomes part of index.php as if it was coded into the file.

Maybe give a practical example to explain?
0
brucegustPHP DeveloperAuthor Commented:
Here is my directory tree...

root->primary_includes->account->reports_admin.php

On the reports_admin.php page, I've got several JQuery plugins being loaded and it's a ball of snot. I say that because I'm getting a lot of "...is not a function" that I've been able to remedy on test pages where I streamline what's being loaded and in what sequence.

To your point, as far as wanting an example:

On the reports_admin.php page I've got <script src="js/reports_admin.js">

It's referring to the reports_admin.js file that's in the "js" folder within the "account" directory.

Unless I give that "reports_admin.js" an absolute reference, I get an error that says it can't be found ("The requested URL js/reports_admin.js was not found on this server.").

As a quick aside, Julian, is there a quick and dirty way to see if a JQuery plugin library is loaded? This is related to the same question.

I'm using this plugin: <script src="select2-4.0.1/dist/js/select2.full.js"></script>. I've gotten an error on multiple occasions that says "select2 is not a function." Again, going back to the test page that I created, I don't get that error. But when I go back to my prod server, I'm dealing with the "include" dynamic once again and I'll get that same error. Is there an IF statement or something that I can use to see if that plugin library is being loaded?
0
Olaf DoschkeSoftware DeveloperCommented:
From all you say it seems a bit like you try to use JS functions from PHP or PHP functions from JS. You've got to realize, that JS only starts it's work, after PHP has fully finished and the page with JS is running client side, not server side. This is totally separated.

Any problem you have might be related to all the different browsers your code might run in.

Aside of that relative paths in script src attribute work in the same way as img src. If you do relative paths to the PHP script directory you misunderstand how this works. The base path is defined by thee request URL. Once you defined a controller on the PHP level, that's not the current php file or directory, it's typically within the web root. You can explicitly specify full URLs, but one level simpler is to make use of the base tag, see https://webdesign.tutsplus.com/articles/quick-tip-set-relative-urls-with-the-base-tag--cms-21399

Then if you load multiple JS and other things, you have a sure and configurable base URL

But all this is a pure HTML topic, has nothing to do with PHP.

Bye, Olaf.
0
Cloud Class® Course: MCSA MCSE Windows Server 2012

This course teaches how to install and configure Windows Server 2012 R2.  It is the first step on your path to becoming a Microsoft Certified Solutions Expert (MCSE).

Julian HansenCommented:
The location of script files is relative to the html page that is generated - not the PHP files that created that page.

What you need to do - is look at the resulting HTML (view source) and look at where it is referencing the scripts from. Then make sure the script are in those locations.
It's referring to the reports_admin.js file that's in the "js" folder within the "account" directory.
Then the script src must include the path to the account directory relative to where the page is located. If the page is in the root and you have an accounts folder under the root with a js folder in that then your script MUST read
<script src="accounts/js/reports_admin.js">

Open in new window


Always think of it relative to the generated page - not the PHP

EDIT
Lets follow this process to get more clarity
1. PHP generates HTML output from a bunch of PHP files - but only one HTML file is sent to the client
2. The client reads the HTML and starts to render the page
3. The client finds a reference to a script <script src="js/reports_admin.js"> - the browser issues a GET on this script relative to the page it is on - if page is in root on domain xyz.com then it will issue a get http://xyz.com/js/reports_admin.js
0
Olaf DoschkeSoftware DeveloperCommented:
Thanks Julian, for providing these details.

I just would point out, how this is related to URL rewrites. When a browser makes a request to say http:/www.domain.com/account and URL rewriting makes cause this to run http:/www.domain.com/php/controller.php?page=account, the browser still has http:/www.domain.com/account as the base URL, that's what I already said
The base path is defined by the request URL.

If your SEO friendly URL schema always goes to http:/www.domain.com/php/controller.php but can have - let's say - up to 3 parameters separated by slashes in the SEO friendly form, eg http:/www.domain.com/topic/id/action/ then the browser still takes these as real directories, it doesn't get aware of the redirections happening server side. The GET of a JS script src="js/some.js" will reflect that in requesting http:/www.domain.com/topic/id/action/js/some.js, that's why using src="/.." is an option making src relative URLs to the web root. And the base tag I also already pointed out is an option to redirect the src to some other base URL than the web root or the location the browser still knows from the original request for the current page. If you start the JS console while on some page and let it display document.baseURI you know what the browser thinks of as current location.

The easiest perhaps is to work with src URLs relative to the web root and thus starting src with /. That way you always only shorten the src URL by the http://www.domain.com/ part. If you want to provide shortest possible src values, you need to know what the browser will take as baseURI or you provide it by a base tag once, to shorten all src URLs by that base part.

You can FTP into your hosting space and look into the logs section. In the access.log you''ll find what URLs the browsers use for requesting the javascript files you know your pages request. And there you can deduct the baseURI that was valid at the time of that request and see how to fix these errors.

Bye, Olaf.
0
Julian HansenCommented:
Not sure were URL rewrites came in - are you suggesting this as a solution or something to take into account when building the site?
0
Olaf DoschkeSoftware DeveloperCommented:
There has to be a reason for failing to load JS resources, and URL rewriting could be one. No, it's not "the solution", how could it be? It could easily be the reason though, as it means a URL with many slashes is rewritten as a URL with less, typically, so when you make the wrong assumption about PHP script location to be the base, this easily lets you write out wrong relative src URLs.

URL rewriting is a thing you mostly will have and won't change, so most often src URLs starting from web root are the easiest solution as "defense" about the negative side effect of URL rewriting on the document.baseURI the browser sees in contrast to the PHP script location.

Besides that, of course also the URLs effectively resulting to make GET request of js files can cause URL rewriting, but most rewrites don't touch any URLs referring to actual files ending in extensions js, jpg, or whatever else files really existing. So what's typically wrong is the assumption about the base path only. URL rewriting just gives a very obvious example of how this affects base URL differing from the expectation of a developer not knowing this.

Bye, Olaf.
0
Julian HansenCommented:
Ok, I understood it to be a pathing issue.
He is including a script that refers to a JS script as js/reports_admin.js  - but this is in another folder account - so if the index.php (or root script) is based in the root folder then js/reports_admin.js must live off that folder - not off the accounts folder.

There is not really an elegant solution around this - the author has already admitted the code is a fruit salad - where I gather he is including modules that have their own resources but are relative to the included file not the host file - so the paths are failing. This speaks to a design problem in the original app (which happens - no fingers pointing at the author here).

How to fix
Create a configuration variable in your script that is accessible globally
define('gb_site_url','http://yourdomain.com');

Open in new window

(Define's are global so no need to inject them)
Then just prefix all script paths with this variable + the rest of the path that defines the script location

<script src="<?php echo gb_site_url;?>/accounts/js/reports_admin.js"></script>

Open in new window


That is probably the best way to approach this.
0
Julian HansenCommented:
Alternative, move your js scripts into folders that will be found according to their paths when the HTML file is generated.
0
Olaf DoschkeSoftware DeveloperCommented:
Why? If you simply start your src URLs with a slash these URLs are relative to the web root, that doesn't need a gb_site_url
.
There simply is a very big difference whether you do
<script src="/js/reports_admin.js"></script>

Open in new window

or
<script src="js/reports_admin.js"></script>

Open in new window


with or without the slash as start.

In the first case the URL first requested can be whatever, the script tag will always load "http://www.domain.com/js/reports_admin.js", in the second case what the browser knows as document.baseURI will modify that

You don't have that problem simply prefixing src URLs with /, this working independent from the domain, you might only have difficulties when your whole website scripts are installed to some subdirectory. The solution to that can be to provide a base tag, which enables you to easily switch between different sets of js scripts in several real subdirectories.

If you only have the one set of js files you want to reference, then simply go from root via a slash, that's free of any specific base domain name and still always the webroot directory. I don't see a hard problem with that. The problem only starts, if you really want to have dynamically moving and switching between different sets of js, eg different jQuery versions needed for core site, a blog, a wiki or a shop part with several subdomains.

Bye, Olaf.
0
Julian HansenCommented:
<script src="/js/reports_admin.js"></script>

Open in new window

Because as he stated in his second post the scripts are not relative to the root but relative to the folder that the included php script lives in.
So the above script actually lives in
account/js/reports_admin.js

Open in new window

Refer https://www.experts-exchange.com/questions/29086052/How-do-I-accurately-and-elegantly-reference-JQuery-libraries-so-that-they're-seen-by-included-files.html#a42481693
0
Olaf DoschkeSoftware DeveloperCommented:
Fine, then it's
<script src="/acccount/js/reports_admin.js"></script>

Open in new window


You still won't need to know the domain name, so this can be transferred and used on any website.

In fact if the browser requests GET /acccount/reports_admin.php then src="js/reports_admin.js" would load /acccount/js/reports_admin.js and if that throws an error, most likely a URL rewrite is causing the browser to work with another document.baseURI

As you said early, if reports_admin.php is just included from another php script, the location of that php is the baseURI, it's always based on what the browser initially requested. It has no idea what happens on the server side and where php scripts are located and included from subdirs. So once you know a php script you write is always included you knwo any HTML you output will need src values not relative to it's location, but to the location of php scripts initially requested by browsers via your frontend HTML. If that's even more hierarchies of includes you shot yourself into the foot, and if a php script sometimes is included and sometimes directly requested, you should perhaps get better ideas of modularizing code and class architecture.

It's a good reason to have a flat hierarchy of directories.

Bye, Olaf.
0
Julian HansenCommented:
You still won't need to know the domain name, so this can be transferred and used on any website.
I think the point here is that the author is stuck with some spaghetti code and is looking for a way to apply a temporary fix so that his scripts are imported.
With a properly designed script importing is not a problem but based on what he has told us it is a bit all over the place.

The solution using the define() is portable - you change the config for the domain you move to - but essentially it comes to the same thing.

Anyway, I don't think we can continue this discussion without seeing more of the code - most of what we have been recommending is based on guess work about how the code is laid out and how it is being used.

I think we have covered all the options based on information available.
1
Olaf DoschkeSoftware DeveloperCommented:
Maybe just one more thing already said but in more detail. If you're really having several subsections of your site, like /accounts/, all based on the same set of PHP scripts, your own kind of framework, now sitting in several folders aside of web root, what would bring all of these sections to their own URL base is subdomains, so when you have accounts.yourdomain.com redirecting to www.yourdomain.com/accounts/, then that would also work for script src="/js/some.js".

Because when the page containing the script tag is coming from a subdomain request, these relative URLs would also go to the same subdomain and so the script src="/js/some.js" would make browsers GET accounts.yourdomain.com/js/some.js, which redirects to www.yourdomain.com/accounts/js/some.js automatically without anything to do in PHP or with URL rewriting, this is happening on the level of subdomains and most hosters give you unlimited subdomains.

Bye, Olaf.
0
brucegustPHP DeveloperAuthor Commented:
I'm always encouraged when I see my questions inspire some quality debate among developers whose skill I both admire and respect.

I want to explain back to you what you two have been discussing and then I would like to share some additional dynamics that I have since been able to discover which I think may provide more clarity to both my problem and the solution.

First off, the ONLY thing I need to be worrying about when it comes to the referencing of libraries in the context of included files is the location of that library as it relates to the page in question. And to your point, Julian, yes - I am dealing with spaghetti code (and I don't want to come across like I'm being critical of another developer's work), but it is a tangled ball of wire.

The attached graphic illustrates that (I'm taking notes on all this, so that's why I'm going a little overboard perhaps in documenting all this).

Here's what I've got...

JQuery tree
Everything y'all have brought to the surface is intuitive and, you would like to hope, is a given, regardless of the app or what server / domain the website is sitting on. When I bring an included file into the DOM, it's a body of code that exists just as though I had hardcoded it into the page where its being "included." Hence, every library that is sitting on the index.php page will be recognized by the included page without any problem. If there's another library that is exclusive to the included file, I can refer to that library on the included file and it will just be recognized as an addition to the libraries that are on the index.php page.

Correct?

Since posting this question, a talented co-worker of mine saw something that I think represents a potential dealbreaker.

Here's the header on the main.php page. This is the main page the user gets after they've logged in:

<html>
	<head>
    	<meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>WorksWell Online</title>
        <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
        <link rel="stylesheet" href="jquery-ui-1.11.4/jquery-ui.min.css">
        <link rel="stylesheet" href="jquery-ui-1.11.4/jquery-ui.structure.css">
        <link rel="stylesheet" href="jquery-ui-1.11.4/jquery-ui.theme.css">
        <link rel="stylesheet" href="bootstrap/css/bootstrap.css">
        <link rel="stylesheet" href="bootstrap/css/bootstrap-theme.css">
        
        <link rel="stylesheet" href="font-awesome/css/font-awesome.min.css">
        <link rel="stylesheet" href="DataTables/datatables.min.css">
        <link rel="stylesheet" href="select2-4.0.1/dist/css/select2.min.css">
        <link rel="stylesheet" href="chosen/chosen.css">
        <link rel="stylesheet" href="chosen/docsupport/prism.css">
        <link rel="stylesheet" href="plugins/datepicker/datepicker3.css">
        <link rel="stylesheet" href="jquery-timepicker-master/jquery.timepicker.css">
        <link rel="stylesheet" href="sweetalert/dist/sweetalert.css">
        <link rel="stylesheet" href="signature-pad-gh-pages/assets/jquery.signaturepad.css">
        <link rel="stylesheet" href="fullcalendar/fullcalendar.css">
        <link rel="stylesheet" media="print" href="fullcalendar/fullcalendar.print.css">
        <link rel="stylesheet" href="AdminLTE/dist/css/AdminLTE.css">
        <link rel="stylesheet" href="//code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.css">
        <link rel="stylesheet" href="css/full_calendar_supplemental.css">
        <link rel="stylesheet" href="css/printing.css">
        <link rel="stylesheet" href="css/chart.css">
        <link rel="stylesheet" href="css/signin.css">
        <link rel="stylesheet" href="css/validate.css">
        
        <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
        <!--[if lt IE 9]>
        <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
        <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
        <![endif]-->
        
        <!-- Fav and touch icons -->
        <link rel="apple-touch-icon-precomposed" sizes="144x144" href="images/dm-144.png">
        <link rel="apple-touch-icon-precomposed" sizes="114x114" href="images/dm-114.png">
        <link rel="apple-touch-icon-precomposed" sizes="72x72" href="images/dm-72.png">
        <link rel="apple-touch-icon-precomposed" href="images/dm-57.png">
        <link rel="shortcut icon" href="images/dm-favicon.png">
    	<style>
			.modal {
				 overflow-y: auto;
			}
			
			.modal-open {
			 	overflow: auto;
			}
			
		</style>
		<script src="jquery-ui-1.11.4/external/jquery/jquery.js"></script>
		<script src="jquery-ui-1.11.4/jquery-ui.min.js"></script>
		<script src="jquery-timepicker-master/jquery.timepicker.min.js"></script>
		<script src="jquery.topzindex.1.2/jquery.topzindex.js"></script><!--unused at present-->
		<script src="jquery.form/jquery.form.js"></script>
		<script src="js/jquery_masked_input.js"></script>
		<script src="bootstrap/js/bootstrap.js"></script>
		<script src="chartjs/Chart.js"></script>
		<script src="chosen/chosen.jquery.js"></script>
		<script src="chosen/chosen.proto.js"></script>
		<script src="chosen/docsupport/prism.js"></script>
		<script src="DataTables/datatables.min.js"></script>
		<script src="signature-pad-gh-pages/jquery.signaturepad.js"></script>
		<script src="signature-pad-gh-pages/assets/json2.min.js"></script>
		<script src="jSignature/jSignature.min.js"></script>
		<script src="sweetalert/dist/sweetalert.min.js"></script>
		<script src="moment2.11.1/moment.js"></script>
		<script src="fullcalendar/fullcalendar.js"></script>
		<script src="js/numeric-1.2.6.min.js"></script>
		<script src="js/bezier.js"></script> 
		<script src="js/admin.js"></script>
		<script src="js/signin_timeout.js"></script>
		<script src="AdminLTE/dist/js/app.js"></script>
		<script src="AdminLTE/plugins/datepicker/bootstrap-datepicker.js"></script>
		<script src="select2-4.0.1/dist/js/select2.full.js"></script>
		<script src="jquery-validation-1.14.0/dist/jquery.validate.js"></script>
     </head>

Open in new window


Notice the "select2-4.0.1/dist/js/select2.full.js" library (second library up from the bottom). That's going to be relevant in a minute.

Now, here's the header of the included file - reports_admin.php:

<html>
	<head>
    	<link rel="stylesheet" href="../../jquery-ui-1.11.4/jquery-ui.min.css">
        <link rel="stylesheet" href="../../jquery-ui-1.11.4/jquery-ui.structure.css">
        <link rel="stylesheet" href="../../jquery-ui-1.11.4/jquery-ui.theme.css">
        <link rel="stylesheet" href="../../bootstrap/css/bootstrap.css">
        <link rel="stylesheet" href="../../bootstrap/css/bootstrap-theme.css">
        <link rel="stylesheet" href="../../chosen/chosen.css">
        <link rel="stylesheet" href="../../chosen/docsupport/prism.css">
        <link rel="stylesheet" href="../../select2-4.0.1/dist/css/select2.min.css">
        <link rel="stylesheet" href="../../css/validate.css">
        <link rel="stylesheet" href="../../font-awesome/css/font-awesome.min.css">
        <link rel="stylesheet" href="../../DataTables/datatables.min.css">
        <link rel="stylesheet" href="../../plugins/datepicker/datepicker3.css">
        <link rel="stylesheet" href="../../jquery-timepicker-master/jquery.timepicker.css">
        <link rel="stylesheet" href="../../sweetalert/dist/sweetalert.css">
        <link rel="stylesheet" href="../../AdminLTE/dist/css/AdminLTE.css">
        <link rel="stylesheet" href="//code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.css">
        <style>
			.ajax-loader-adminReports {
				position: absolute;
				top: 0;
				left: 0;
				right: 0;
				bottom: 0;
				margin: auto; /* presto! */
			}
		</style>

        <script src="../primary_includes/account/js/reports_admin.js"></script>
        
	</head>

Open in new window


This page is being called by clicking on the "wrench" on the main.php page...

wrench button
This is the code that's being triggered when you click on that button:

$('body #account_mgt-open').click(function() {
		$('body #user_support').fadeOut();
		$.get('../primary_includes/account_management.php', function(data) {
			$('body #account_management').html(data).fadeIn();
		});
	});

Open in new window


The screen looks like this after you click on that button:

account screen
When you click on the "reports" tab, you're activating this code below...

$("body #reports_btn").click(function(){
            $("body #reports").hide();
            $('body .ajax-loader-acctMgmt').show();
            $.get('../primary_includes/account/reports_admin.php', function(data) {
                  setTimeout(function(){
                        $('body .ajax-loader-acctMgmt').fadeOut('slow');
                        $("body #reports").html(data).fadeIn();
                  },delay);
            });
      });

And here's my problem. This is the page! This is the bugger, right there: reports_admin.php

When that page comes up, you get this:

reports_admin.php screenshot
The error is ...select2 is not a function

...which means that the select2 library is not being seen. Yet, I can go to the Google Dev tools and verify on the Network screen that the library is being called.

But...

If the page that I'm calling has a <head> tag, is it possible that any and all JS libraries are being ignored? In other words, is a nested <head> tag within the <body> of another page going to be a problem?

What do you think?
0
Julian HansenCommented:
I can refer to that library on the included file and it will just be recognized as an addition to the libraries that are on the index.php page.
Providing the path is correct.
If index.php includes primary_includes/accounts/reports_admin_page.php
Then any reference to a script within the reports_admin_page.php must have a path that is relative to the root - not the primary_includes/accounts folder.

I am not too clear on the includes part though - you show us two HTML file listings above - but you seem to indicate that one is included inside the other. I am guessing that reports_admin_page.php is a partial page that is included into index.php between a header and a footer section - is this correct?
If so - how is reports_admin_page.php including scripts - from the second listing it appears that they are in the head - which does not make sense

Can you clarify.
0
Olaf DoschkeSoftware DeveloperCommented:
Just having a glimpse look at this, but assumed
in index.php the <script src="jquery-ui-1.11.4/external/jquery/jquery.js"></script> is supposed to load the same library as the <link rel="stylesheet" href="../../jquery-ui-1.11.4/jquery-ui.min.css"> within reports_admin.php, then this is just not working, as you load the reports_admin.php from an ajax call. That doesn't change the browsers current baseURI, the src would still need NO ..\..\ going up two directory levels.

Even if index.php would include/require reports_admin.php on the PHP level and not via an Ajax client-side request.

Also, an ajax call typically doesn't request a whole new HTML page, it requests just the detail HMTL snippet you want to change in the currently loaded HTML page, eg in some <div> or another tag, you act on the DOM and don't start a new page. Then you also don't reload any JS script, they are already loaded.

Your error is, that reports_admin.php is creating the HTML for a whole new page. It's not meant to be used from a client-side Ajax framework maintaining a single page application.

Bye, Olaf.
0
Olaf DoschkeSoftware DeveloperCommented:
$.get('../primary_includes/account/reports_admin.php', function(data) {
                  setTimeout(function(){
                        $('body .ajax-loader-acctMgmt').fadeOut('slow');
                        $("body #reports").html(data).fadeIn();
                  },delay);

Open in new window


That part of the ajax, as far as I understand, would fade out one div and fade in another.The returned HTML of the /reports_admin.php should only be the part that's injected into the body into a div with id "reports", that's what $("body #reports").html(data) is setting, data is the return of get('../primary_includes/account/reports_admin.php, so that shouldn't be a full blown HTML page. reports_admin.php should only bring in the content of a <div id="report> tag, without that div tag, just the inner HTML of that.

Bye, Olaf.
0
Julian HansenCommented:
I am getting confused - we seem to have moved from an include(..../reports_admin/page.php) in the index.php to talking about AJAX.

Which one is it AJAX or server side include?
0
Olaf DoschkeSoftware DeveloperCommented:
$.get is an ajax HTTP GET, isn't it?

https://api.jquery.com/jquery.get/
Section Ajax -> Shorthand Methods.

Bye, Olaf.
0
brucegustPHP DeveloperAuthor Commented:
Julian, I can see why I may have seemingly taken a left turn, having mentioned "includes" only to now being talking about an AJAX call.

The "include" isn't so much an "included file," as much as it's the name of the directory where the page that's being called by the AJAX functionality that I've got referenced above is located (primary_includes/reports_admin.php).

I have been careless in the way I've used that word in the context of my question and content, but know that the reports_admin.php is not an "include." It's a separate page that's being called by an AJAX dynamic.

Sorry about that...

What's made this problem difficult to navigate is the way in which some of the JS libraries fail to be seen by the reports_admin.php page. This is what prompted to ask if there was a more elegant way in which to reference these libraries, assuming that the reason that the libraries in question weren't being identified by the reports_admin.php page was because of a potential error in the way in which they were being referenced.

Since posting this question, however, I think I've been able to determine that the reason why I'm getting the "selcect2 is not a function," is that, while I can look at the "Network" tab on Google Dev Tools and see that the library has been loaded, because the "reports_admin.php" has a <head> tag, once the user clicks on the button that brings that page to the surface, the system sees that as an entirely different page. Hence, any library that was loaded on the main page is ignored and that's why I'm getting the error.

Does that sound right?

I'm going to kick the tires on this thing and see if by adding the "select2" library to the "reports_admin.php" doesn't do the trick.
0
Olaf DoschkeSoftware DeveloperCommented:
The reports_admin.php doesn't see any JS code, that's loaded from the HTML client side and doesn't run and is referenced server side at all. You still don't seem to recognize that all the header part you return from reports_admin.php is wrong, it's not wanted from that AJAX call, the AJAX call only wants to populate one report div, all the JS includes it has are already done, they don't need to be redone at all.

You're trying to force a full page into a page. Either the call if reports_admin.php is wrong from the ajax side, as that should only make requests to server side PHP scripts returning the html for the <div id=report> section of the original page the index.php request already resulted in. Or the reports_admin.php was correctly doing just that, until you extended it to return a full HTML page. In any case, this doesn't work, not only because the relative paths don't match.

The aJAX call is doing a PHP request from an already ready and fully loaded HTML page,  It doesn't need a new full HTML response from it's request, it just needs partial HTML for a div that is there to be updated from AJAX requests. That's similar to iframes, with the difference that you don't load a full page into a div by AJAX, you would only do that with an iframe. And this whole webapp surely isn't meant to load page detail parts into iframes.

I don't know at which stage you got into the project, Bruce, but I'm sure reports_admin.php differed in some older version of this whole site code or the ajax called some different PHP script. If you can go back in the history of sources, if this whole thing is versioned in github, then find out, what this originally was meant to be.

Bye, Olaf.
0
brucegustPHP DeveloperAuthor Commented:
No, Olaf, you're right.

I'm coming on way after the fact. Why this is running in PROD, I have no idea because, in some instances at least, it's not built very well.

I think I've got what I need in order to fix this. Let me see what I can do.

Thanks!
0
Julian HansenCommented:
It's a separate page that's being called by an AJAX dynamic.
Ok I understand - I have put together the following sample to illustrate the problem
t3009.html - the host file
t3009a.html - the included file
t3009.js - a javascript file that contains a function that is called from t3009a.html
HTML for t3009.html
<html>
<body>
<div id="target"></div>
</body>
</html>

Open in new window

jQuery on t3009
<script>
$(function() {
	$('#target').load('t3009a.html');
});
</script>

Open in new window

HTML for t3009a.html page
<!doctype html>
<html>
<head>
<script src="t3009.js"></script>
</head>
<body>
<h1>Hello world</h1>
<script src="http://code.jquery.com/jquery.js"></script>
<script>
$(function() {
	ColourHeading();
});
</script>
</body>
</html>

Open in new window

t3009.js file
function ColourHeading()
{
	$('h1').css({color: 'red'});
}

Open in new window

Put all of those in the same folder and everything is fine.

Now create a folder t3009 and put the following into the folder
t3009a.html
t3009.js
Change the jQuery in the first file to
<script>
$(function() {
	$('#target').load('t3009/t3009a.html');
});
</script>

Open in new window

Reload host page and instead of the header going red - it stays black and the console reports an error trying to load a script.
Reason: when it loads t3009a.html the reference to t3009.js is local to the file but because it is being loaded into the host it uses the host as a reference point, looks for the t3009.js file in the root folder and does not find it.

How to fix
1. In the t3009a.html (accounts) file hard code the path to the .js file
2. In the t3009a.html add a base href tag
<!doctype html>
<html>
<head>
<base href="http://yourdomain.com/t3009/" />
<script src="t3009.js"></script>
</head>
<body>
<h1>Hello world</h1>
<script src="http://code.jquery.com/jquery.js"></script>
<script>
$(function() {
	ColourHeading();
});
</script>
</body>
</html>

Open in new window


For option 2 you can use a config variable as I described before
<base href="<?php echo gb_site_url;?>/t3009/" />

Open in new window


Either way - you need to put something in that script to tell it how to find the JS irrespective of what the target folder of the host page is.

Working sample of above here
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Olaf DoschkeSoftware DeveloperCommented:
No, this is a single page application in a sense. It replaces parts of an already loaded and running page, so you never reload any JS script already loaded.

All the libraries are loaded in the initial index.php request, and the ajax requests should only result in the partial html necessary. Then you never have a pathing problem at all. You don't load a header into a div; you don't load an <HTML> or <BODY> tag, only the inner html of a div.

The page remains loaded and JS libraries, too, functions are available. But because you DO load a full HTML page into the div, the browser reloads things and messes the situation up, What results from this is quirks mode DOM model with an HTML tag nested in the initial HMTL, that's what's happening and of course is a total misconception.

If you would like to create a new page, you wouldn't use ajax at all, ajax makes a server request to act on the already existing page. If you want to load another full page you may simply set window.location.href=newurl and don't need any ajax.

Bye, Olaf.
0
brucegustPHP DeveloperAuthor Commented:
Gentlemen!

First of all, my apologies for allowing this question to linger and secondly, thank you both very much for taking the time to explain in detail the solutions that you've recommended.

I was able to get it to work via a variety of dynamics. The bottom line is that I've been asked to refactor this app which will be a pleasure in light of what we've been wrestling with here.

First, the fact that the app has a page being forced into another (two <head> tags), lead me to going back and replacing some libraries that I had initially recognized as redundant - meaning that they were both on the parent page and the child page. Yes, they are redundant, but because you've got two <head> tags, you can't assume that the libraries referenced on the parent page are going to be seen by the child if the child has a <head> tag itself.

When I did that, the error "select2 is not a function" went away because the library was now being seen.

I also went back and reconfigured the order that the libraries were being loaded and that was also helpful.

So, bottom line: It's fixed. I've made notes so I can avoid this nonsense when I go back to rebuild it. Again, thanks for ALL your help. We got it done!
0
brucegustPHP DeveloperAuthor Commented:
Rather than going back and assigning points to every part of the thread that constitutes this dilemma, I just grabbed the two pieces of counsel that resonated with me the most. Thanks again, guys!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
PHP

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.