I am using jquery .html() to append some tags dynamically by calling a REST url, but it doesn't work.
<div style="display: none;" id="tables">
<form:select id="table" name="table" path="table">
<form:option value="">Choose</form:option>
<div id="tables-select">
<!-- The available tables for update will be added here -->
</div>
</form:select>
<script type="text/javascript">
function getTables(type) {
$.getJSON('/web/tables/db/' + type,
{
ajax : 'true'
},function(data) {
html ='';
var len = data.length;
for ( var i=0; i<len; i++) {
html += '<option value="'+data[i]+'" >'+data[i]+'</option>';
}
$('#tables-select').html(html);
});
}
</script>
</div>
I see the REST call is going through, but nothing is happening.
After debugging and placing break points, I see that the java script jumps from line 10 directly to end of java script function (line 20).
Any idea what is happening here?
I have bunch of same kind of functions in my page and all those work expect for this one.
EDIT:
This is how I am calling the function
<script type="text/javascript">
$(document).ready(function(){
$("#type").live('change', function(){
var type = $(this).val();
getSites(type);
getTabless(type);
});
});
</script>
As it stands, this code is wrong: there's a missing close brace for getTables(). Also, I assume you have some code somewhere that actually calls getTables(), otherwise this code does nothing except declare a function.
When debugging, the $.getJSON call will indeed execute quickly. The whole purpose of AJAX is that it is asynchronous. The debugger will thus step over the $.getJSON call without entering the callback, because the callback is invoked at a later time. If you put a breakpoint inside the callback then it should be triggered.
This whole <DIV> has a style of display:none. Unless you are somewhere calling $('#tables').show() or otherwise doing something to make it visible, then the result won't ever be visible, except in the DOM, or via a tool like firebug.
Also, you cannot put a <DIV> tag inside a <SELECT> tag. Either use an <OPTGROUP> tag for the tables-select element, or replace the whole contents of the <SELECT> element, including the initial "Choose" option.
Related
I have a report authoring tool that lets me add descriptive text in the report header, prior to a table containing the data. The examples included with the tool show how include Javascript in the description for various special effects. I would like to change certain cells in the table into links to other reports. Here's the HTML produced by the reporting tool.
<div class="element-info">
<div class="description">My Description</div>
<div class="properties">
<table>...</table>
</div>
</div>
I have tried replacing "My Description" with the following, but (perhaps unsurprisingly) it's changing something other than the table.
<div>My Description
<script type="text/javascript">
// currentScript is supported in my version of Firefox.
var me = document.currentScript;
// go up two levels to get the enclosing div
var element_info = me.parentElement.parentElement;
// from there we want the properties div, then the table
var mytable = element_info.lastChild.firstChild;
mytable.style.color = "red";
</script>
</div>
I expect that the problem is that when the script runs, the HTML in the following div has not yet been parsed. Mozilla says that the defer attribute will be ignored in scripts without a src= attribute, and I've verified that it does nothing.
Although my example code is using plain Javascript, the authoring tool is based on jQuery, so it's full repertoire is available if needed.
If the problem involves the fact that the html hasn't yet been parsed, you can immediately gain a reference to the script, but only later utilize it, once the document is loaded. It would look like this:
<div>My Description
<script type="text/javascript">
// Get the reference immediately...
var script_of_interest = document.currentScript;
// And only use it once everything is loaded:
window.onload = function() {
var element_info = script_of_interest.parentElement.parentElement;
var mytable = element_info.lastChild.firstChild;
mytable.style.color = "red";
};
</script>
</div>
Make sure your the node your script operates on is loaded before the execution, otherwise your the node may be undefined or just nothing. You may try wrap your code with
$(document).ready(function(){
//your code
}).
Yet another "dynamically change select options based on parent option selected" question.
I have the select values changing dynamically - but after my rails render of the child select - I lose the Chosen styling (the jQuery Chosen plugin) and I cannot operate on this newly injected element.
Here is where the code is right now - it's gone through dozens of iterations -
$('#vendor_block').on('change', '#vendor_name', function(){
overlay.show();
var v = $(this).val();
vndr_json = {};
vndr_json["v"] = v;
$.ajax({
type : "GET",
url : "/purchaseorders/upd_vndr_locs",
data : vndr_json,
success: function(res) {
overlay.hide();
// console.log(typeof(res),res);
jQuery("#vndrAddrOpts").html(res);
}
});
$("#vendor_addresses").chosen(); // WHY DON'T YOU RENDER CHOSEN BOX?!
});
I get this new select box on my page - and I want to fire an event when it changes, but the DOM has already loaded, so it doesn't "see" this element I'm guessing.
Also - the Chosen plugin doesn't render on the element. Not sure why - probably the same reason.
I'm using jQuery's .on() like every post on SO says I should. But it doesn't "reload" the elements inside this parent (and 'vendor_block' is the parent div of 'vendor_name' and 'vendor_addresses').
You can see the difference in the select boxes here:
Any help would be great?
UPDATE:
Adding before and after HTML :
<div id="vndrAddrOpts">
<select class="chzn-select vndrLocs span12" id="vendor_addresses" name="vendor_addresses"><option value="">Select Location</option></select>
</div>
That is the raw HTML - but Chosen does the following when the DOM loads:
<div id="vendor_addresses_chzn" class="chzn-container chzn-container-single chzn-with-drop chzn-container-active" style="width: 100%; margin-bottom: 10px;" title=""><span>Select Location</span><div><b></b></div><div class="chzn-drop"><div class="chzn-search"><input type="text" autocomplete="off"></div><ul class="chzn-results"><li id="vendor_addresses_chzn_o_0" class="active-result result-selected highlighted" style="">Select Location</li></ul></div></div>
This is all fine and well - this is what's supposed to happen.
This is the raw HTML after the select box has been injected:
<div id="vndrAddrOpts">
<select class="chzn-select vndrLocs span12" id="vendor_addresses" name="vendor_addresses"><option value="">Select Location</option></select>
</div>
And here is the rendered box - sans Chosen stuff.
<select class="chzn-select vndrLocs span12" id="vendor_addresses" name="vendor_addresses"><option value="">Select Location</option><option value="532757b4963e6505bc000003">Honolulu</option>
<option value="532768d0963e6505bc000004">Waipahu</option></select>
I found the answer here :
Is there a way to dynamically ajax add elements through jquery chosen plugin?
I actually was approaching this problem in an overly complex way - trying to inject and element instead of just starting with the element and adding options to it.
My AJAX looks like this now:
$.ajax({
type : "GET",
url : "/purchaseorders/upd_vndr_locs",
data : vndr_json,
success: function(res) {
overlay.hide();
var va = $('#vendor_addresses');
// console.log(typeof(res),res);
for (var i=0; i < res.length; i++) {
va.append(
$('<option></option>')
.val(res[i].id)
.html(res[i].name)
);
}
va.trigger("liszt:updated");
// jQuery("#vndrAddrOpts").html(res);
}
});
So instead of even worrying about rebuilding the chosen element from an injected element - we just use the built-in "updated" trigger and it works great.
You are inserting the result of your ajax call into the DOM it's success callback, which is executed whenever it finishes (independent of the script's execution). In this case, your ajax request is being made, the code after it begins executing, and then the callback. The odds of the success callback being called before the next line of code are slim, as the ajax call is an http request which takes much longer than a line of JavaScript executing.
You want to put the code in the success call back, such as:
$.ajax({
type : "GET",
url : "/purchaseorders/upd_vndr_locs",
data : vndr_json,
success: function(res) {
overlay.hide();
$("#vndrAddrOpts").html(res);
$("#vendor_addresses").chosen();
}
});
I think the chosen method is firing before the element has actually been rendered on the page, and jQuery can't find it. Try putting $("#vendor_addresses").chosen(); as part of the AJAX success callback. Failing that, try commenting out the chosen() method, running the AJAX script, then manually running the chosen() method. If it works that way, you have to delay it a little bit.
EDIT:
Actually, looking more closely at your code, it appears you're using an ID tag instead of a class. Do multiple HTML elements have the #vendor_address id? If so, use a class instead, and use $('.vendor_addresses').last().chosen();. If you use an ID, and use an ID selector, jQuery will pick the first element if finds with that ID, and stop there.
Lesson to be learned? Use an ID for UNIQUE elements, and classes for multiple elements of the same 'class'.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How may I reference the script tag that loaded the currently-executing script?
I am trying to make a javascript function that includes a html doc on a page via AJAX, as a way of making a PHP-esque include() with no serverside interaction. I want the script to include the file at the location on the page the function is called from. Here's my function (assuming ajax is a valid xmlhttp object):
function include(src, elem){
ajax.open('GET', src, false);
ajax.send(null);
elem.innerHTML = ajax.responseText;
}
So this would print the contents of "src.html" in the div when it is clicked:
<div onclick="include('src.html', this);"> </div>
But I want it to load when the page does. Considering there is no onload event for divs I have to include the script in the div, which is fine:
<div id=write>
<script>include('src.html', this);</script>
</div>
But then the script has no reference to the div it is called from. Sure I could put an id on the div and pass that to the function, but I don't want to. I want to be able to call this from any unidentified element. Any ideas?
You could change your div (or other element(s)) to use a data- attribute to specify what script to run:
<div data-include="src.html"></div>
And then run a script onload of the page (or in a script block just before the closing </body> tag) that finds all elements with that attribute.
var elements = document.querySelectorAll("[data-include]");
for (var i = 0; i < elements.length; i++)
include(elements[i].getAttribute("data-include"), elements[i]);
Here's a demo of the above (with a dummy include() function that just puts the required source url string in the element rather than doing Ajax, but it shows the elements are selected correctly): http://jsfiddle.net/nnnnnn/gm2LN/
For simplicity I've used querySelectorAll() to select the elements, but note that it isn't supported in IE7 and older. But obviously you can substitute whatever other element selection method you like if you want or need to support older browsers.
Here:
<div id=write>
<script>include('src.html', this);</script>
</div>
"this" points to the window object.
I think of putting an id to the script element and doing something like this:
<div id=write>
<script id='test'>include('src.html', document.getElementById('test').parentNode);</script>
</div>
Now elem in "include" function will point to the div containing the script element. In this case you are still relying on id but not on the div's side
When the page is loaded, all scripts will be executed sequencially, as soon as they are parsed. Therefore, you just need to get the last script that is apparent in the DOM to get the currently executed script:
var script = document.scripts[document.scripts.length-1];
ajax(url, function successCallback(html) {
script.insertAdjacentHTML("afterend", html);
});
(Demo to test - notice that document.scripts needs FF 9+)
However, I see no reason not to use serverside include().
nnnnnn was on the money, but I modified it ever so softly. I ended up making an include tag with a src attribute. On pageload I loop through all the "include" tags and fill them with the data from their src attribute:
function include(src, elem){
ajax.open('GET', src, false);
ajax.send(null);
elem.innerHTML = ajax.responseText;
}
window.onload = function(){
var includes = document.getElementsByTagName('include');
for(var i = 0; i <= includes.length; i++){
var elem = includes[i];
var src = elem.getAttribute('src');
include(src, elem);
}
}
Then anywhere I want to include a html file I just include my custom element:
<include src='includeme.html'> </include>
In practice this produces a bit of popup but for my application that's fine.
Thanks for the help!
I've a javascript function
function $m(theVar){
return document.getElementById(theVar)
}
The problem with the above code is, the element I want to pass is generated by ajax so I need something like the .live() in jquery, unless it throws an error
How do I rewrite the above function in jQuery so that any DOM element generated later can also be detected.
Update:
When my page first load, it loads
1) ajaxupload.js with codes
function ajaxUpload(form,url_action,msg){
var id_element= "pop-con";
function $m(theVar){
return document.getElementById(theVar)
}
if($m(id_element)==null){
erro += "The element of 3rd parameter does not exists.\n";
}
}
2) index.php with codes
<div id="popupMargin">
<div class="close">x</div>
<div id="pop-con"></div>
</div>
<div id="ajaxGenerateMarkUp"></div>
3) now on the click of a button, the following markUp is added to the #ajaxGeneratedmarkUp div (mark-up generated through ajax)
<form onSubmit="return disableForm(this);" action="crop/wizecho_upload.php" method="post" name="f" id="wizecho" enctype="multipart/form-data">
<input id="file" type="file" name="file" onChange="return disableForm(this), ajaxUpload(this.form,'crop/wizecho_upload.php', '<br>Uploading image please wait.....<br>'); return false;"/>
</form>
Now on change of this input type file, made the call on in the javascript. Now it shows the error.
[Note: I only posted sections of code I think might affect my question]
Like this:
return $('#' + theVar)[0];
jQuery's selector can detected newly generated items:
$('#id');
So in your case:
var theVar = 'something';
$('#' + theVar); //returns a jQuery object of the select item
$('#' + theVar)[0]; //returns the first DOM object that jQuery finds with that id
I think you need to add a live call somewhere to detect the new AJAX-loaded button. This way, the button will be automatically bound to a handler that works OK as in other answers. From your comment I guess you are doing one of these:
In the AJAX-loaded button you already include some JS logic, that is not working (something like onclick="do_something").
You are binding the second button to a handler withoug the live method.
Here's a working example. Although it doesn't load contents via AJAX, it does load a dynamic button.
http://jsfiddle.net/marcosfromero/VKfKL/
Update: Another example that does load contents via AJAX and binds the newly created button with live:
http://jsfiddle.net/marcosfromero/h9RSC/
I have a html component that includes some javascript.
The component is a file in a template engine, so it can be used
in the initial rendering of the whole html page
as stand-alone html rendered through an ajax request
The javascript should be applied to an object in the template, i.e. :
<div class="grid" >
<div class="item" id="item_13">
This is item 13
</div>
<div class="item" id="item_14">
This is item 14
</div>
</div>
<script type="text/javascript">
$(document).ready(function(){
$(HOW_DO_I_GET_PREVIOUS_ELEMENT???).someEffect(params)
})
</script>
I've checked this similar question but the best answers seem to rely on the current script being the last one in the 'scripts' variable as the next ones are not loaded yet. If I append the html and js with an ajax request, it will not be the case.
To be 100% clear : the question is about getting the previous object WITHOUT reference to any specific attribute : no unique id for the tag, no random id as there is theoretically always a chance it will show up twice, no unique class attribute,as exactly the same component could be displayed in another part of the HTML document.
Simple solution involving a two step process:
1) find out which element your script tag is
2) find the previous sibling of that element
in code:
<div id="grid">
<!-- ... -->
</div>
<script type="text/javascript">
var scripts = document.getElementsByTagName("script");
var current = scripts[scripts.length-1];
var previousElement = current.previousSibling;
// there may be whitespace text nodes that should be ignored
while(previousElement!==null && previousElement.nodeType===3) {
previousElement = previousElement.previousSibling; }
if(previousElement!==null) {
// previousElement is <div id="grid"> in this case
$(document).ready(function(){
$(previousElement).someEffect(params);
});
}
</script>
Is this good web programming? No. You should know which elements should have effects applied to them based on what you're generating. If you have a div with an id, that id is unique, and your generator can tell that if it generates that div, it will also have to generate the js that sets up the jQuery effect for it.
But let's ignore that; does it work? Like a charm.
If you can give your <script/> block an Id you could easily call prev() to get the previous element.
<script type="text/javascript" id="s2">
$(document).ready(function(){
$("#s2").prev().append("<h1>Prev Element</h2>");
})
</script>
Example on jsfiddle.
You will need to get a way to reference the script tag immediately after the "grid" div. As #Mark stated, the easiest way to do this is by giving the script tag a unique id. If this is beyond your control, but you do have control of the script contents (implicit by the fact that you are creating it) you can do something like this:
var UniqueVariableName;
var scripts = document.getElementsByTagName('script');
var thisScript = null;
for(var i = 0; i < scripts.length; i++){
var script = $(scripts[i]);
if(script.text().indexOf('UniqueVariableName') >= 0){
thisScript = script;
break;
}
}
if(thisScript){
thisScript.prev().append("<h1>Prev Element</h2>");
}
Hack? Yes. Does it Work? Also, yes.
Here's something that works in FF, Chrome and IE 8, untried anywhere else. It looks at the element before the last element on the page (which is the script being parsed), stores it locally (with a self calling function) so the load handler can use it.
http://jsfiddle.net/MtQ5R/2/
<div class="grid" >
<div class="item" id="item_13">
This is item 13
</div>
<div class="item" id="item_14">
This is item 14
</div>
</div><script>(function(){
var nodes = document.body.childNodes;
var prevSibling = nodes[nodes.length - 2];
$(document).ready(function(){
console.log( prevSibling );
})
})();</script>
Having said that. I still have to mention that you're tightly coupling the behavior (JS) and HTML, by putting them into the same file which kind of goes against the web flow of separating them. Also, I don't know how you'd expect this to work with an AJAX request since you're not just adding it to the HTML as it's being rendered. In that case, it would be very easy to get a reference to the html you just inserted though.