Multiple Javascript calls on an Orchard field - javascript

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.

Related

Storing a variable from an html document to display it in another

On the first page, the user is asked to select a name from a list (select/option tags) and click the "edit" button. User's choice is stored using the "option" variable and we redirect him/her to the next page.
When the body of the next page loads, it triggers the second function, which displays the option made previously as the main header of the page.
The problem is that, although onEdit() runs, displayOption() displays the variable as the empty string (as declared above the functions).
Why doesn't the second function "see" the alteration?
var option = "";
//"edit" button (onclick)
function onEdit() {
var selector = document.getElementById("selector");
option = selector.options[selector.selectedIndex].value;
window.location.href = "nextPage.html";
return false;
}
//"nextPage.html" body (onload)
function displayOption() {
var header = document.getElementById("header-main");
header.innerHTML = option;
}
Use local storage for that, it is easy to use and in this case highly appropriate.
See mdn docs
Example
on first page simply declare
localStorage.setItem('option', 'selectedOption');
on the second page get the var
var option = localStorage.getItem('option');
EDIT
as wendelin commented it is even more appropriate to use session storage, because it remove itself automatically.
The reason this doesn't work is that when nextPage.html loads, the entire script is re-evaluated, and option is now back to its default value of "".
You'll need another solution to persist the user's choice across refreshes. One of the more common approaches to something like this is to set the value as a query string parameter that can be read from within displayOption.

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.

Refresh to repeat control not working normal after deleting 1 row

I have a field named "selectedTime" in a document, this fields stores the selected timings added by user.Adding times is working perfect.This is back-end.
Now I will explain this issue of selecting date from front end.I have given a button add to add times.The custom control of date-time gets added to repeat control on click of Add button.Even if I check in document it shows the list of selected times.Even this works fine.
Now if I want to delete a selected time from repeat control randomly, it deleted that particular record from document, but on the page the last record of the repeat gets disappears,
I was assuming that this is the issue with partial refresh of repeat control,I have even tried that but no result.Full refresh breaks the page.
java script code for the delete button
`var doc:NotesDocument = database.getDocumentByUNID(context.getUrlParameter("refId"))
var selectedTimes:java.util.Vector = doc.getItemValue("selectedTimes");
if(selectedTimes != null){
var sdtString = getComponent("inputHidden1").getValue();
if(selectedTimes.contains(sdtString))
selectedTimes.remove(sdtString);
doc.replaceItemValue("selectedTimes",selectedTimes);
doc.save();
};
var url:XSPUrl = context.getUrl();
view.postScript("window.refresh('"+url+"')");`
I know it is difficult to understand what i want to explain but any suggestion on this will be appreciated.
Even if anybody have any idea to delete the a field values of a documents,In my case field name is "selectedTimes" and the values are added times in repeat control, Please share.
Edit 1:
//Repeat Control
var doc:NotesDocument = database.getDocumentByUNID(context.getUrlParameter("refId"))
var selectedTimes:java.util.Vector = doc.getItemValue("selectedTimes");
return selectedTimes;
Another try could be link the repeat with a viewScope instead of the document:
1) In the event beforeLoadPage/afterLoadPage: Get the value from the document, and put it in a viewScope variable:
// beforeLoadPage event:
// ... get the doc
viewScope.selectedTimes = doc.getItemValue("selectedTimes");
2) In the repeat control, use the viewScope:
<xp:repeat value="#{viewScope.selectedTimes}"...
3) When an update is done, update both the viewScope and the document:
//...update the View Scope variable and get the document:
doc.replaceItemValue("selectedTimes", viewScope.selectedTimes);
This could be a hint if the document would be added as DataSource:
Do you have the document included in the XPage as a DataSource? In that case, try to get and update the NotesXspDocument instead of the Document from the DB:
XPage:
<xp:this.data>
<xp:dominoDocument var="xspDocument"
action="editDocument"
documentId="#{param.unid}">
</xp:dominoDocument>
</xp:this.data>
SSJS code: work directly with the XspDocument
var selectedTimes:java.util.Vector = xspDocument.getItemValue("selectedTimes");
...
xspDocument.replaceItemValue("selectedTimes", selectedTimes);
This could be a hint if the value would not be removed from the document:
In sdtString you are getting a String value:
var sdtString = getComponent("inputHidden1").getValue();
If you have the time values stored as NotesDateTimes, you will get this type of value inside the Vector and the remove method won't find the String and nothing will be removed.
// In a Vector<NotesDateTime> the String cannot be found:
selectedTimes.remove(sdtString);
Be sure you remove the same type of value you get in the Vector

Get input value and insert into table on different page

How would I do the question asked above. I have tried .append() in javascript but can you get data from one html file and insert it into another?? Some please help.
If the page you are receiving the data was created by your js then do it like this.
var childPage = window.open("somepage.html");
The child page would need a global function to receive data, then just call it.
childPage.passData(dataToPass);
If the page to receive the data is the parent, and the input is on the child do like this.
window.parent.someFunction(dataToPass);
Your respective functions would then have to take said data and do the work fro there.
the functions do have to be on the global scope of each page.
Your should wrap the inputs in a<form> whose action attribute is set to the url of the page in which you want to display the values, as shown below:
<form action='url to second page' method='get'>
<input name='name' value='something' />
<button>Submit</button>
</form>
In the second html page, You can retrieve the request parameters by calling the js function given in this answer when it is loaded:
For example,
<html>
<head>
<title>b.html</title>
<script>
function load() {
var params = getRequests();
console.log(params['name']);
}
function getRequests() {
var s1 = location.search.substring(1, location.search.length).split('&'),
r = {}, s2, i;
for (i = 0; i < s1.length; i += 1) {
s2 = s1[i].split('=');
r[decodeURIComponent(s2[0]).toLowerCase()] = decodeURIComponent(s2[1]);
}
return r;
};
</script>
</head>
<body onload='load();'></body>
</html>
The function getRequests() returns an object containing all request parameters with the name of input element as key value. So if your first html page contains an input with name='test', the following code :
var params= getRequests();
var value =params['name'];
will give you the value of test input in second html page. Then you can use DOM API methods such as document.getElementById() to target the table elements in which you want to display the value, and set it's innerText.
can you get data from one html file and insert it into another?
Try .load()
$("#mydivid").load("/myotherpage.html");
To get a specific part of that page
$("#mydivid").load("/myotherpage.html #dividonotherpage");
We can also do something after it has loaded
$("#mydivid").load("/myotherpage.html", function() {
$("#mydivid").show();
/* like grab the values of attributes .. */
});
https://api.jquery.com/load/
edit: / reading #QBM5, I see you might be referring to 'data' as local client side user input from another window. Disregard this answer if so, as this will not pick up changes that are not set as part of the original delivered markup.

Variable not updating in script string, yet it updates

Very confused here.
I have a search box which reads a list of school names from my database. When I select a school, the id (from the db) gets put in a hidden textbox.
I also have a search box which reads a list of courses from my database. However, I made the query so that it only reads the courses from the selected school.
It does that, in theory.
I was planning to pass the school id, which I grab from the hidden box, to the search script which in turn passes it to my database query. However, the variable I put my school id in doesn't seem to be updating.. yet it does. Let me explain.
I come on the page. The school for my test account has id 1. The id number in my hidden box is indeed 1. I search for a school which I know has some courses assigned to it: the id number in the box changes to 3.
I have a JS variable called school_id which I declared outside of my $(document).ready. I assume that means it's global (that's what I got taught even though SO told me once it isn't really the correct way to do this. Still have to look into that). I wrote a function which updates this variable when the school search box loses focus:
$("#school").blur(function() {
school_id = $("#school_id").val();
});
A quick javascript:alert(school_id); in my browser bar also shows the updated variable: it is now 3 instead of 1.
Onto the search script part of my page (excerpt of the script):
script:"/profiel/search_richting?json=true&limit=6&id=" + school_id + "&"
As you can see, I pass the school_id variable to the script here. However, what seems to be happening is that it always passes '1', the default variable when the page loads. It simply ignores the updated variable. Does this string get parsed when the page loads? In other words, as soon as the page loads, does it actually say &id=1? That's the only idea I can come up with why it would always pass '1'.
Is there a way to make this variable update in my script string? Or what would be the best way to solve this? I'm probably missing out on something very simple here again, as usual. Thanks a lot.
EDIT
Updated per request. I added a function getTheString as was suggest and I use the value of this function to get the URL. Still doesn't work though, it still seems to be concatenating before I get a chance to update the var. HOWEVER, with this code, my ajax log says id:[object HTMLInputElement], instead of id:1. Not sure what that means.
<script type="text/javascript">
var school_id;
$(document).ready(function() {
$("#school").blur(function() {
school_id = $("#school_id").val();
});
// zoekfunctie
var scholen = {
script:"/profiel/search_school?json=true&limit=6&",
varname:"input",
json:true,
shownoresults:false,
maxresults:6,
callback: function (obj) { document.getElementById('school_id').value = obj.id; }
};
var as_json = new bsn.AutoSuggest('school', scholen);
var richtingen = {
script: getTheString(),
varname:"input",
json:true,
shownoresults:true,
maxresults:6
};
var as_json2 = new bsn.AutoSuggest('studierichting', richtingen);
});
function getTheString() {
return "/profiel/search_richting?json=true&limit=6&id=" + school_id + "&";
}
</script>
This is because the URL is static, it is not updated as the ID changes.
You should update the URL as part of the code you wrote to get the ID:
$("#school").blur(function() {
school_id = $("#school_id").val();
// update URL here ...
});
Aren't you concatenating script:"/profiel/search_richting?json=true&limit=6&id=" + school_id + "&" before the event is fired and the var updated?
Okay. So the problem was my third party plug-in instead of the code I wrote. I fixed this by editing the code of the autoSuggest plugin so it now includes my id field in the AJAX request.
var url = this.oP.script+this.oP.varname+"="+encodeURIComponent(this.sInp)+"&id="+ $("#school_id").val();
Thanks to everyone who tried to help me out!

Categories