How pass 4 string values from HTML page to a javascript file? - javascript

Wish to pass 4 string values (not user inputted) from a HTML page to a javascript function in a separate file.
Have some javascript code which does an image flip. I've used this on many HTML pages and it worked.
Now I wish to put this code in a separate file, called "image-flip-comment.js" and each webpage will pass it 4 string values. The script will execute the function which will be displayed in the HTML page.
This is PART of the working code which was from a script on my HTML page.
<script language="JavaScript" type="text/javascript">
<!-- hide from non-JavaScript Browsers
Image_top1= new Image(100,100)
Image_top1.src = "../buttons/Rm_btn_fwa.gif"
//----more stuff ----
function SwapOutTop() {
document.imagebacktop.src = Image_top1.src; return true;
}
// - stop hiding -->
</script>
// here is PART of my code from the file "image-flip-comment.js"
// Imageflip Javascript routine, version w passed values shown as comments
// <!-- hide from non-JavaScript Browsers I'm going to assume this is
obsolete?
Image_top1= new Image(100,100)
Image_top1.src = "../buttons/${button_forw_a}!"
// Rm_btn_fwa.gif this went on above line
// more stuff for the other 3 parameters
function FwSwapBackTop() {
document.imagefliptop.src = Image_top1.src; return true;
}

Well you can have a parameterized function like
function imageflip(var your_parameter_name) {
...
...<!-- access the string here -->
...
}
And depending upon the event you want your image to flip call the function by onclick with parameter passed
For example:
<a onclick="imageflip('some_string_value')" >click</a>

Related

How to have JavaScript functions work across different HTML pages?

I am building a website with several HTML pages, and going to fill up info on different pages through an API. I have added onclick listeners to HTML elements like this:
// ASSIGNING ELEMENTS AS VARIABLES
const EPL = document.getElementById('epl');
const bundesliga = document.getElementById('bundesliga');
const laliga = document.getElementById('laliga');
// ONCLICKS
EPL.onclick = function() {
getStandings('2021');
location.replace('standings.html');
}
bundesliga.onclick = function() {
getStandings('2088');
location.replace('standings.html');
}
laliga.onclick = function() {
getStandings('2224');
location.replace('standings.html');
}
When one of these is clicked, I call a function (getStandings) with its unique argument to fetch some data from the API. I also want to move to another HTML page, for which I used location.replace.
I'm caught in a dilemma: if I use the same JS file for every HTML page, when I get to the new HTML page, I get errors as the new HTML page does not have every element:
main.js:41 Uncaught TypeError: Cannot set property 'onclick' of null
But if I use different JS files, maybe one JS file for each HTML file, I cannot carry forward the bits of information I need. How can I get to the new HTML page, with its own JS file, without stopping and losing everything in the function I'm in currently, under the JS file of the old page? For example, the argument '2021' or '2088' are to be passed into the getStandings() function which will populate the new HTML page with data from an API. If I jump to a new HTML page with a new JS file, this is lost.
Is there a better way to organise my files? 😐😐😐😐😐
You can set your event listeners on the condition that the elements are not null e.g.
const EPL = document.getElementById('epl');
const bundesliga = document.getElementById('bundesliga');
const laliga = document.getElementById('laliga');
if(EPL){
EPL.onclick = function() {
getStandings('2021');
location.replace('standings.html');
}
}
etc...
Solved! As amn said, I can add URL parameters to the end of the URL of the new HTML page, then get the variables from its own URL once I'm on the new HTML page.
I think I would rather use classes instead of IDs to define the listener, and maybe IDs for dedicated action.

jQuery trigger function from code loaded by append

Is there anyway to call a function or trigger an event from html loaded from an append() call? I have a tag It is filled when a user licks on a list of things like this. in my index.html I have something like this:
function doThis(someData) {
$.get("/url/"+someData, function(htmlFromServer) {
$("#something").append(htmlFromServer);
});
}
function doSomething(moreData) {
alert(moreData);
}
I want to be able to do something like this in the returned html
<div>
<p>This is an important message</p>
<script>
doSomething("this message is different for each page");
</script>
</div>
I want to be able to call one function, but depending on what is returned, I alert a different message. I want the front end to call one endpoint, but what happens next is dynamic. I don't want to do a huge if block in my doThis(), or worse, a function for each possibility that "someData" may have.
You could pass a function to doThis. You also probably meant to concatenate the someData.
function doThis(someData, cb) {
$.get("/url/" + someData, function(htmlFromServer) {
$("#something").append(htmlFromServer);
cb()
});
}
doThis('somepath', () => console.log('append successful'));
I got this to work by defining all my functions in a javascript file and import like usual.
I then make a decision on the back end that all of the possible html that is returned by the jQuery get() call, has a hidden form field with the id of "x" and the value being the function name I want to call after the .append(htmlFromServer) is done.
So i have this function in a .js file defined int the head as usual. I then do this:
$.get("/url/"+someData, function(htmlFromServer) {
$("#myDiv").append(htmlFromServer).append(function() {
var functionToCall = $("#x").val(); // x is the id of the element
window[functionToCall]();
});
}
And I now have a generic way of handling different data depending on the server response without a big if block.

Inject/execute JS code to IPython notebook and forbid its further execution on page reload

I'm writing the library which has to embed javascript code to IPython notebook and execute it. The HTML/JS code looks like:
<div id="unique_id"></div>
<script>
var div = document.getElementById("unique_id");
// Do the job and get "output"
div.textContent = output; // display output after the cell
</script>
And the python code:
from IPython import display
display.display(display.HTML(code))
The side-effect is that the javascript code is stored in the output of the cell in notebook, and every time when the page is reloaded or the notebook is opened it will run again.
Are there any way of forbidding the code to be executed on reload? Or is it possible to run the javascript code without saving it within the output?
I've figured out the hack.
The trick is to use update=True argument of the IPython.display.display() which will replace the output with a new one (see here for an example).
So what is needed to be done: first output javascript that does the job, and then waits until the div with a certain ID is created, to fill it with the output. Once this display() is called, we could call display a second time updating the first one with the actual HTML with the div. So the javascript code once finished will fill it with the results, but the code itself will not be saved.
Here's the test code:
First, define the callback function (it looks like, it is important here to display it as HTML("<script> ... </script>") rather than Javascript(...)):
from IPython.display import display, HTML, Javascript
js_getResults = """<script>
function getResults(data, div_id) {
var checkExist = setInterval(function() {
if ($('#' + div_id).length) {
document.getElementById(div_id).textContent = data;
clearInterval(checkExist);
}
}, 100);
};
</script>"""
display(HTML(js_getResults))
And then execute the update trick in one cell:
js_request = '$.get("http://slow.server/", function(data){getResults(data, "unique_id");});'
html_div = '<div id="unique_id">Waiting for response...</div>'
display(Javascript(js_request), display_id='unique_disp_id')
display(HTML(html_div), display_id='unique_disp_id', update=True)
After the callback of get() is executed, the content Waiting for response... will be replaced with the output from the server.
After running into the same issue of Javascript executing on every notebook open, I adapted #Vladimir's solution to a more general form:
Use fresh unique IDs on every render (since old ID is saved with the HTML output of the notebook).
No polling to determine when HTML element is rendered.
Of course, when the notebook is closed, no HTML modifications done by JS are saved.
Key Insight: Replace Cell Output
from IPython.display import clear_output, display, HTML, Javascript
# JavaScript code here will execute once and will not be saved into the notebook.
display(Javascript('...'))
# `clear_output` replaces the need for `display_id` + `update`
clear_output()
# JavaScript code here *will* be saved into the notebook and executed on every open.
display(HTML('...'))
Making it Work
The challenge here is that the HTML and Javascript blocks can be rendered out of order, and the code which manipulates the HTML element needs to only execute once.
import random
from IPython.display import display, Javascript, HTML, clear_output
unique_id = str(random.randint(100000, 999999))
display(Javascript(
'''
var id = '%(unique_id)s';
// Make a new global function with a unique name, to prevent collisions with past
// executions of this cell (since JS state is reused).
window['render_' + id] = function() {
// Put data fetching function here.
$('#' + id).text('Hello at ' + new Date());
}
// See if the `HTML` block executed first, and if so trigger the render.
if ($('#' + id).length) {
window['render_' + id]();
}
''' % dict(unique_id=unique_id)
# Use % instead of .format since the latter requires {{ and }} escaping.
))
clear_output()
display(HTML(
'''
<div id="%(unique_id)s"></div>
<!-- When this script block executes, the <div> is ready for data. -->
<script type="text/javascript">
var id = '%(unique_id)s';
// See if the `Javascript` block executed first, and if so trigger the render.
if (window['render_' + id]) {
window['render_' + id]();
}
</script>
''' % {'unique_id': unique_id}
))
To keep the notebook clean, I would put this plumbing code into a separate .py file and import it from Jupyter.

Multiple Javascript calls on an Orchard field

I'm creating a module that allows users to see the status of a set of IP addresses by creating a custom field that holds the address (and validates it when it's first entered). On the Field view there's a glyphicon that changes based on the result of a ping attempt.
How it should look
However, I'm having difficulty in getting the Javascript for pinging the address and each individual field to pass arguments correctly. For some reason, only the address from the first field is passed to the Javascript, instead of using the addresses from each individual field.
How it looks when only one address gets passed
I've checked the page with Firebug and found that the onload arguments are collected and sent correctly, but the Javascript is only receiving the first field's contents. Since the Javascript uses the arguments to determine which DOM to change, only the first DOM is ever altered.
I've also confirmed that the values are passed incorrectly by making the spanIDHolder and addressHolder spans visible and having the Javascript alert with the contents of those two spans. The HTML displays the correct value, but the alert only shows the first.
Here's the code for the view:
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet">
#{
string ipaddress = Model.ContentField.Value;
string spanID = ipaddress + "span";
bool showPingResult = Model.ContentField.ShowPing;
}
<body>
#{
if (!string.IsNullOrEmpty(ipaddress)) {
if (showPingResult) {
<span id="addressHolder" style="display:none">#ipaddress</span>
<span id="spanIDHolder" style="display:none">#spanID</span>
<span id="#spanID">
<span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span>
</span>
}
<span class="text-field">#ipaddress</span>
}
}
<script src="http://code.jquery.com/jquery.min.js"></script>
<script>
var address = document.getElementById("addressHolder").innerText;
var id = document.getElementById("spanIDHolder").innerText;
function setPingResult() {
var elem = document.getElementById(id);
elem.innerHTML = '<div class="glyphicon glyphicon-ok-sign" aria-hidden="true"></div>';
}
$(document).ready(function () {
setPingResult();
});
</script>
</body>
The Javascript is temporarily simplified until I can get the parameters passing correctly, so 'address' is unused.
Things I've tried so far:
Other methods of including the Javascript code such as inlining or including it in the HTML as discussed here
Doing the ping through a C# function and using if statements on the view to display the correct symbol
This works, but means that it runs the ping script before the page loads. If there's a way to call the C# function in the onload block (or equivalent), that would be a solution
Running the code through an onload call on the body and storing the Javascript in a separate file
Moving things around randomly hoping it decides to work
Let me know if I need to provide code from elsewhere in the project.
Edit: Some things I've found so far...
The block at the beginning which designates the variables is only executed once, no matter how many individual fields are on the page. I found this by replacing spanID with the output of a random number generator. All four fields received the same random number.
I've tried encasing the field in a part, but can't figure out how to get the variables to the part view instead of the field view. A viewmodel may be the key?
The variables can be passed to the Javascript section just by using # in front of the needed variable name. This results in the last field's data being passed.
Solution:
For some reason, the pass works correctly if I collect the variable in the document.ready block instead of directly in the JS function. Therefore, instead of
function setPingResult() {
var elem = document.getElementById('#spanID');
elem.innerHTML = '<div class="glyphicon glyphicon-ok-sign" aria-hidden="true"></div>';
}
$(document).ready(function () {
setPingResult();
});
I use
function setPingResult(spanID) {
var elem = document.getElementById(spanID);
elem.innerHTML = '<div class="glyphicon glyphicon-ok-sign" aria-hidden="true"></div>';
}
$(document).ready(function () {
setPingResult('#spanID');
});
If someone could explain why this works, that would be lovely.

(epson tm-t20ii) print multiple html files with qz-print

I tried to print multiple html files in folder with qz-print and EPSON - TM-T20II, but seem no work.
This is an example of script that i used:
function printPages() {
if (notReady()) {
return;
}
qz.appendHTMLFile(getPath() + "misc/out-may-21.html");
qz.appendHTMLFile(getPath() + "misc/out-may-22.html");
while (!qz.isDoneAppending()) {
qz.printHTML();
}
but it will only print "out-may-22.html" file.
- And one more problem, when printing html file, it print html file, then print one more text file with tag "".
So confused,
thanks.
Update: Since QZ Tray 2.0, the new API supports a data block which supports multiple HTML files without confusing callbacks.
For those still using QZ Print/QZ Tray 1.9, the function qz.appendHTMLFile("..."); is not synchronous and cannot currently be called in succession.
Instead, you'll have to wait until qzDoneAppending() is called, then call printHTML(), then call qz.appendHTMLFile("..."); again, etc.
<script>
// Called automatically when the software has loaded
function qzReady() {
qz.findPrinter("epson");
}
// Called automatically when the software has finished searching for the printer
function qzDoneFinding() {
// append first file
qz.appendHTMLFile("first.html");
}
var secondHasAppended= false;
// Called automatically when a file is done appending
function qzDoneAppending() {
qz.print();
}
// Called automatically when document has been sent to the printer
function qzDonePrinting() {
if (!secondHasAppended) {
qz.appendHTMLFile("second.html");
secondHasAppended = true;
// qzDoneAppending and qzDonePrinting will take care of the rest
} else {
alert("Done!");
}
}
</script>
If you require more than two documents, replace the boolean with a counter.
I use QZTray 2.0.2 and I could not make it prints multi pages.
It only prints first page. In other words it only prints what it can render for only 1 page.
I have 3 pages HTML.
When I set "scaleContent" to false it only prints the one portion of first page. When I set it true it prints all pages into 1 page with scaling.
All I need is to print all pages one by one with scaling.
Best

Categories