I have a following Kohana setup:
All my files are placed under 'public_html/koh'
My js files are placed under 'public_html/koh/media/js/'
I use html::script helper to include those javascript files which generates me following html code:
<script type="text/javascript" src="/koh/media/js/site.js"></script>
In my js I access one of controllers like 'json/getsomething' (which is http://localhost/koh/json/getsomething).
It works OK as long as I'm staying in top of the controller:
http://localhost/koh/home
When I go to 'http://localhost/koh/home/index' it renders the same page of course but 'json/getsomething' is not accessible from Javascript anymore.
How can I solve this problem?
Include Javascript using absolute path?
Create a variable in js like var fullPath = 'http://localhost/koh/'?
What is the best practice to do it?
Leonti
That's how I did it.
I made a function url_base which would correspond to kohana's url::base and so it would switch around when I moved from localhost and to production.
View template:
<script type="text/javascript">
function url_base() { return "<?php echo url::base();?>"; }
</script>
And then in config.php:
if(IN_PRODUCTION) {
$config['site_domain'] = '/';
}
else {
//if in localhost redirect to localhost/mysite
//instead of just localhost
$config['site_domain'] = '/mysite/';
}
(A bit late but hope still useful) Here's another way I use to better organize my js-serverside vars.
I put somewhere in beginning some basic variables - eg. in "before()" function:
$this->template->appconf = array(
'url_base' => url::base(),
'l' => substr(I18n::$lang, 0, 2),
);
Now I can add whenever I need any extra variable:
$this->template->appconf['page_key'] = 'product_page';
And finally in template this cleaniness:
<script type="text/javascript">
var appconf = <?php echo json_encode($appconf); ?>;
</script>
Use like this:
<script type="text/javascript">
console.log(appconf.url_base); // "/mysite/"
</script>
Related
I am writing an app where some of the data to be used in the app is fixed and not going to change once the page is loaded. Other data is changing all the time and is brought into the app by ajax when the user clicks a button. This data needs to be combined with the fixed data for displaying to the user every time they click the button.
I want to use ES6 modules for this app. The solution I have attempted is shown below. In reality the variable, fixedData, would be quite a large data structure which is why I definitely do not want to get it by ajax every time the user clicks the button as that would be unnecessary and take time transferring data. Here I have used the value 6 for fixedData to keep the example simple.
The line, const fixedData = 6, would be made as PHP generates the page like this: `const fixedData = '<?php echo 6; ?>';
index.php:
<script type='module' src='./main.js'>
const fixedData = 6;
</script>
main.js:
const h2 = document.createElement('h2');
function displayFixedData(fixedData){
h2.innerText = data;
document.body.appendChild(h2);
}
displayFixedData(fixedData);
When I run this, I get 'Uncaught ReferenceError: fixedData is not defined'
Is there some way I can feed fixed data into my JavaScript code on page load and which would be available for using as an argument in functions inside ES6 modules in the app?
I feel like I need to export the data from the script tag and import it into main.js although I believe that is not possible. Is there some other way I can achieve that?
Edit:
In response to Barmar's comment I now have something which does work:
index.php
<script type="module">
import { displayFixedData } from './main.js'
const fixedData = 5;
displayFixedData(fixedData);
</script>
main.js:
const h2 = document.createElement('h2');
function displayFixedData(fixedData){
h2.innerText = fixedData;
document.body.appendChild(h2);
}
export { displayFixedData };
You can create a non-executable <script> element containing some text serialization of data, e.g. JSON:
<script id="fixed-data" type="application/json">
<?= json_encode($fixedData, JSON_HEX_TAG) ?>
</script>
<script type="module" src="main.js"></script>
(The JSON_HEX_TAG flag escapes <, preventing HTML injection (XSS) issues with data containing <!-- or </script>.)
Then select and deserialize in your script:
const fixedData = JSON.parse(document.getElementById('fixed-data').textContent);
I have some javascript code which requires few fields from server side. I would like to store this code in a separate .js file but, moustache will not be able to populate it with server side information. This is what I have:
<body>
<script type="text/javascript" src="/js/test.js"></script>
</body>
My .js file:
var testField = '{{someValue}}';
alert(testField); // is null
Thank you
You can try to use eval js function: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
var testTemplate = '{{someValue}}';
var testTemplateValue = Mustache.render(testTemplate, view);
var testField = eval(testTemplateValue);
alert(testField);
Eval function is not secure, so you must take care about input manually.
I have a javascript file that handles the scripting of several HTML files.
I started running into issues as everything is just written out, and nothing is called in functions (so all AJAX calls for instance are called at all pages, even though each call should only be called at one page one).
What is the best way to go about improving/fixing this? Here are the two ways that I thought of doing it:
Create a separate JS file for each HTML file
Put all JS code in functions and call each function respectively
I am leaning towards putting all my code in functions. However, when I did:
<script src="the_source">
call_function
</script>
That didn't seem to work. I put that right before where the responsible HTML was. I originally wrote it in Haml as follows:
%script{:src => "src"}
call_function
How can I get this HTML function calling working?
Or is separating them whereby each HTML file has a different JS file considered a better solution? The problem is that there is a lot of shared code between them. To solve this, I can create a different file with the shared code in objects which can be called from the other JS files as needed.
What is the cleaner approach/solution to this problem?
To call function use:
call_function();
Edited:
<script src="the_source"></script>
<script >
call_function();
</script>
where "the_source" is path to your js file
End edit
To separate the logic in every page i would just create some settings object and put there flag for cases you want to have separate:
//this code should be on every page you need your javascript file
<script src="the_source"></script>
<script>
var settings = {
mode:'doSomething1'
}
call_function(settings);
</script>
in your js file do things depending on the settings.mode value:
function call_function(settings)
{
switch(settings.mode){
case: 'doSomething1':
//code for case1
break;
case: 'doSomething2':
//code for case2
break;
default:
//code for default case
break;
}
}
This depends on your hosting plan:
If it's a dedicated or semi-dedicated server, I would prefer to have a shared JavaScript file (for performance).
If it is any other kind then separate file is faster as it distributes the load of requests in different JS files.
If you don't want to create separated files as it will be messy, I suggest to do the following:
<script src="somewhere">
var page = "<?PHP echo basename($_SERVER['PHP_SELF']); ?>";
Run_Function();
</script>
In somewhere:
function Run_function(){
switch(page){
case "1.php":
//Do Something
break;
case "2.php":
//Do Something else
break;
default:
alert("Unregistered webpage");
break;
}
Good Luck :D
EDIT:
Try up this function to get the file name from the URL:
function FileName(){
var url = window.location.pathname;
var filename = url.substring(url.lastIndexOf('/')+1);
return filename:
}
UPDATE:
Please check this improved function of the above:
function FileName(){
var url = window.location.pathname;
var filename = url.substring(url.lastIndexOf('/')+1);
if(filename == "" || filename == "Undefined"){
filename = "index.ruby";//or any other extension
}else{
var filename = filename.replace(/%C3%84/g, "Ä");
var filename = filename2.replace(/%C3%96/g, "Ö");
var filename = filename2.replace(/%C3%9C/g, "Ü");
var filename = filename2.replace(/%C3%A4/g, "ä");
var filename = filename2.replace(/%C3%B6/g, "ö");
var filename = filename2.replace(/%C3%BC/g, "ü");
}
return filename:
}
This function might help more people and it is more flexible to use.
I would put your JS code into several different files, one for each page.
This can help your site run quicker (admittedly not by much) because the browser isn't running through tons and tons of code to find the required function.
Also, (and this is just a personal opinion) , a JS file with just a long list of short functions is quite ugly and seems less efficient.
And yeah, include an extra file with the shared code on. Try to make sure nothing is repeated unnecessarily in the files!
Good luck! :)
wondering how I can pass a variable from load js like:
<script type="text/javascript" src="script.js?myVar=myValue"></script>
and use and pass to script.js itself?
I Know about declare variable before, but I'm looking for url way.
Thanks in advance.
The javascript wont have access to that value. The server would have to look for that and insert that value into the rendered javascript on your behalf.
Usually though, the pattern is more like this:
<script type="text/javascript" src="script.js"></script>
<script type="text/javascript">
ObjFromScript.myVar = 'myValue';
ObjFromScript.doStuff();
</script>
You'd have to locate the <script> tag in the document and extract the arguments. A prominent example of a site using this is facebook with the #xfbml=1 hashtag.
However, the proper/nice way is not putting any code but functions in script.js and then call someFunction(myValue);.
You could do it on the client or the server. On the client, get hold of the script element and parse the src attribute.
<script id="myScript" src="script.js?myVar=foo"></script>
<script>
var s = document.getElementById('myScript');
s.src; // parse it and extract myVar
</script>
On the server, setup routes so that script.js goes to some handler written in a server-side language like PHP. In that case you could be outputting script.js dynamically. Here's an example in PHP.
script.js => script.php
<?php
header('Content-Type: application/javascript');
$myVar = $_GET['myVar'];
?>
// optionally expose myVar inside JavaScript
var myVar = <?php json_encode($myVar) ?>;
// regular JavaScript
alert(myVar);
var x = 10;
You could use document.currentScript, but it isn't widely supported.
var matches = document.currentScript.src.match(/\?myVar=([^&]+)/),
myVarParam = matches && matches[1];
Alternatively, you could try getting the script element with the matching URL and parse out the GET param.
var scriptPath = 'path/to/this/script.js',
matches = $('script[src^="' + scriptPath + '"]').attr('src').match(/\?myVar=([^&]+)/),
myVarParam = matches && matches[1];
I want to include a script tag, while providing a parameter to it. This is what I came up with so far
Provide a parameter to script URL (cons: generate multiple JS files)
<script src="http://example.com/something.js?P=123" type="text/javascript"></script>
Hide parameter in script tag (cons: same as #1)
<script src="http://example.com/scripts/123/something.js" type="text/javascript"></script>
Google Analytics way (cons: ugly, complicated, global variables)
<script type="text/javascript" charset="utf-8">
var _something = _something || 123;
(function() {
var s = document.createElement('script');
s.type = 'text/javascript';
s.src = 'http://example.com/something.js';
var ss = document.getElementsByTagName('script')[0];
ss.parentNode.insertBefore(s, ss);
})();
</script>
The best thing is to define things (functions &c) in the external script but execute nothing. Then have an inline script that calls functions/methods defined in the external script.
<script src="http://example.com/something.js" type="text/javascript"></script>
<script type="text/javascript">
something(123);
</script>
If the way the script is executed, depends on how it's called, you can add params like your option 1.
Other ways are:
<script params='{"abc": 123}' src="script.js"></script><!-- params is a non standard, non official attr that the script will read -->
or
<script>var _abc = 123;</script>
<script src="script.js"></script>
or even
<script src="script.js#abc=123"></script>
I have to agree with #outis though: load the same thing for everybody, always, and execute it like you/the client want(s) afterwards.
I do this for a cross-sub-domain XHR handler that I have. I call it as:
<script type="text/javascript" src="xd.js#subdomain"></script>
and then in the script, parse it as such (using jQuery):
$('script').each(function(){
if((src = this.src).indexOf('xd.js') < 0){ return; }
xds = src.substr(src.indexOf('#') + 1).split(',');
// do stuff with xds
});
Your first example does not need to generate multiple files. It can be used by JavaScript alone, by detecting window.location.href and parsing it (you might find the likes of http://phpjs.org/functions/parse_url:485 and http://phpjs.org/functions/parse_str:484 helpful in doing this: var queryString = parse_str(parse_url(window.location.href).query); ).
However, if you use something like #P=123 instead of ?P=123, you won't cause another download of the file by your users, so I'd recommend that instead (in which case change "query" in the above code sample to "fragment").
Another possibility is using the HTML5-reserved data-* attributes, and detecting their values within your script:
<script src="http://example.com/something.js" data-myOwnAttribute="someValue" data-anotherCustomAttribute="anotherValue"></script>
The script would then detect along these lines:
(function () {
function getScriptParam (attr) {
var scripts = document.getElementsByTagName('script'),
currentScript = scripts[scripts.length-1];
return currentScript.getAttribute('data-' + attr); // in future, could just use the HTML5 standard dataset attribute instead: currentScript.dataset[attr]
}
var myOwnAttribute = getScriptParam('myOwnAttribute');
// ... do stuff here ...
}());
The real advantage of Google's ugly API is that it allows developers to drop in that code in the <head> of the document (considered proper form), while still acting asynchronously in a cross-browser way. I think they could indeed avoid the global had they combined their dynamic script-tag technique with either of the above approaches.