Creating element in place - javascript

I want to create an element in place where javascript function run.
<script>
var uniqid='an unique Id';
document.write('<iframe id='+uniqid+'></iframe>');
someAsyncFunction(callback)
</script>
in other part of code I set additional parameters for this element
<script>
callback=function(paramfromcallback){
getElementById(uniqid).url=paramfromcallback;
}
</script>
but this is not work in IE. I can't find this element.
My problem is:
There are many elements on page, for each element must be set only this element parameters
I do not know which element is parent, I do not know the script element ID. I need insert an element in place where are first script called
First part of code executed before any call back, and I want to keep it asynchronous

Depending on the order your script blocks are hit, you could have a number of issues here. document.write() creates interesting problems with inline script. More often than not, any script that comes after it won't be able to use the results of the doc.write until after the page finishes loading -- or from within another document.write() block. Waiting for the window to be fully loaded could solve your issue. How about something like this -
Defined Once:
function callback(id) {
var el = document.getElementById(id);
if (el !== null) {
el.url = 'http://google.com';
}
}
Then anywhere you want to write out an iframe:
(function(){
var id = 'an_unique_Id';
document.write('<iframe id='+id+'></iframe>');
var l = window.onload;
var n = function() { someAsyncFunction(function() { callback(id); }); };
window.onload = (typeof l == 'function') ? function() { l(); n(); } : n;
})();

First, use:
document.getElementById(uniqid).url = 'http://google.com';
The method is part of the document object, so you can only use it by prepending document.
Second, use:
var callback = function() {
Will not break your code probably, but variables should be declared with var

Related

Why must I access a global variable through window?

I have some JS in a file, and some JS on a page.
If I try to access my function via NucleusPreview, it can't be found
If I access it via window.NucleusPreview, it is found
Why is that? Am I doing something wrong, or do I need to be explicit when accessing objects in window scope when in another function?
Update: I was creating NucleusPreview inside the onReady, but moved it so I think the window scope was a red herring. The problem is that when calling it in onReady, gave it time to load the file, but when I moved it out I started calling it too early.
The JS in the the file is basically:
var NucleusPreview;
(function ($) {
NucleusPreview = function NucleusPreview(source) {
//ctor stuff
};
NucleusPreview.prototype.AdjustCaption = function AddCaption() {
//caption stuff
};
})(jQuery);
My JS on the page:
$('.nucleus-preview').each(function eachNucleusPreview(index, element) {
var jElement = $(element),
vidId = jElement.data('video-id'),
np = new NucleusPreview($(element)); //Uncaught RefError: NucleusPreview is not defined
_wq.push({
id: vidId,
onReady: function (video) {
np.AdjustCaption();
}
});
});
As long as the first bit of code you provided is executed first and none of the code is executed prior to the DOM being loaded (you can put all of this code in a document.ready() callback to ensure that is the case), you should be able to. Run this code snippet and wait a moment, you will see that it works without qualifying window.
In the example below, I've placed all the code in a document.ready() callback (although that is not required for the code to run) to ensure that you don't try to access $('.nucleus-preview') before the DOM is ready.
Additionally, doing this will keep NucleusPreview out of the global scope in the first place, which is always a good idea.
// Always make sure the DOM is fully loaded prior to scanning for DOM elements.
// This can be done by placing all of your code in a "document.ready()` callback
// function as I'm doing here or by placing the code at the end of the HTML document,
// just before the close of the body (</body>).
$(function(){
// Now NucleusPreview is scoped to this function, which keeps it out of the
// global scope and that's always good, so you don't pollute the window.
var NucleusPreview;
(function ($) {
NucleusPreview = function NucleusPreview(source) {
//ctor stuff
};
NucleusPreview.prototype.AdjustCaption = function AddCaption() {
//caption stuff
};
})(jQuery);
var _wq = []; // Added to allow code to execute
$('.nucleus-preview').each(function eachNucleusPreview(index, element) {
var jElement = $(element),
vidId = jElement.data('video-id'),
np = new NucleusPreview($(element)); // <-- Works just fine!
_wq.push({
id: vidId,
onReady: function (video) {
np.AdjustCaption();
}
});
});
});
console.log($('.nucleus-preview'));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="nucleus-preview"></div>
<div class="nucleus-preview"></div>
<div class="nucleus-preview"></div>

If element is not present on page why is JavaScript throwing an error?

My scenario is that I have one JS file which is being used on two HTML pages. One has a button with id="a" and the other doesn't have it. I have attached an event on id="a" by doing this.
document.getElementbyId("a").onclick = function () { .. }
My problem is when I run second file which doesn't have the button with id="a" and it throws the error
TypeError: document.getElementbyId(...) is null
which causes some unexpected behaviour! Is there any way to keep using just one JS file or should I separate the JS file for every html page?
I read a question on StackOverflow here which is about why jQuery doesn't throw an error if the selector is invalid. I need same or similar functionality with vanilla JavaScript.
The simple fix is to add a check:
if (document.getElementById("a") !== null) {
document.getElementById("a").onclick = function () /* .. */ };
}
jQuery will never break on missing elements, it just silently fails. You can argue about whether that is good or not.
The trick jQuery uses is that it will always return something. $("#id") will return a jQuery wrapper. That wrapper has functions like .on and .load and .html. A selector can match one, more or no elements. For the wrapper it doesn't matter how many elements are matched.
It works like this:
var elem = get_element("a");
elem.onclick(callback);
function get_element(id) {
var elem = document.getElementById(id);
return { // return a wrapper
onclick: function (callback) {
if (elem !== null) {
elem.onclick = callback;
} else {
// silently fail
}
}
};
}
Consider testing existance
var elm = document.getElementById("a");
if (elm) elm.onclick = function () { .. };
Or falling back in the case of a falsy
(document.getElementById("a") || {}).onclick = function () { .. };
In this second method, the function still gets set but will be quickly GC'd as the reference to {} dies by the next line.
All of the above solutions are correct. However, you should definitely move away from writing whatever.onclick = function as that is no longer the best way to write your code. Using this method, you only get one click event. Using a more modern approach allows you to attach as many events as you want.
Also, you mention jQuery but there is no jQuery in the supplied code only vanilla JavaScript. Do you need a jQuery solution or JavaScript?
JavaScript
document.addEventListener('DOMContentLoaded', function(){
var elm = document.getElementById('a');
if ( elm ) { //if the element exists add the click event
elm.addEventListener('click', function(){
//Your "onclick" code here
});
}
});
jQuery
$(function(){
$('#a').on('click', function(){
//Your "onclick" code here
});
});

Injecting Javascript to Iframe

I am making a live editor for my website. I have the CSS and HTML parts down, only issue is the JS part now. Here is a snippet of the code
var frame = $('#preview_content'),
contents = frame.contents(),
body = contents.find('body');
csstag = contents.find('head').append('<style></style>').children('style');
java = contents.find('head').append('<script><\/script>').children('script');//Issues here
$('.area_content_box').focus(function() {
var $this = $(this);
var check = $this.attr('id');
$this.keyup(function() {
if (check === "html_process"){
body.html($this.val());
} else if(check === "css_process") {
csstag.text($this.val());
} else if (check === "java_process"){
java.text( $this.val() );
}
});
});
Problem is it is not injecting script tags in the iframes body nor the head when ever I try this. I've read up on injecting and some issues containing the ending script tag. I need to figure out how to inject script tags, really want them in the head but if it is easier in the body that is fine.
jfriend00 - I will be focusing on making this vanilla, if you think I should honestly.
So any words of advice on how to go about making my editor work correctly with the injecting JS?
These two lines of code look like they could have problems:
csstag = contents.find('head').append('<style></style>').children('style');
java = contents.find('head').append('<script><\/script>').children('script');//Issues here
It seems like it would be much better to create the style tag and remember that DOM element.
var iframe = document.getElementById("preview_content");
var iframewindow = iframe.contentWindow || iframe.contentDocument.defaultView;
var doc = iframewindow.document;
var csstag = doc.createElement("style");
var scripttag = doc.createElement("script");
var head = doc.getElementsByTagName("head")[0];
head.appendChild.cssTag;
head.appendChild.scriptTag;
$('.area_content_box').focus(function() {
var $this = $(this);
var check = this.id;
$this.keyup(function() {
if (check === "html_process") {\
// I would expect this to work
doc.body.html($this.val());
} else if(check === "css_process") {
// I don't know if you can just replace CSS text like this
// or if you have to physically remove the previous style tag
// and then insert a new one
csstag.text($this.val());
} else if (check === "java_process"){
// this is unlikely to work
// you probably have to create and insert a new script tag each time
java.text( $this.val() );
}
});
});
This should work for the body HTML and it may work for the CSS text into the style tag.
I do not believe it will work for the javascript as you can't change a script by assigning text to the tag the way you are. Once a script has been parsed, it's in the javascript namespace.
There is no public API I'm aware of for removing previously defined and interpreted scripts. You can redefine global symbols with subsequent scripts, but not remove previous scripts or their effects.
If this were my code, I'd remove the previous style tag, create a new one, set the text on it before it was inserted in the DOM and then insert it in the DOM.
If you're not going to do it that way, then you'll have to test to see if this concept of setting .text() on an already inserted (and parsed) style tag works or not in all relevant browsers.
For the script tag, I'm pretty sure you'll have to create a new script tag and reinsert it, but there's no way to get rid of older code that has already been parsed other than redefining global symbols. If you really wanted to start fresh on the code, you'd have to create a new iframe object from scratch.
There are other issues with this too. You're installing a .keyup() event handler every time the .area_content_box gets focus which could easily end up with many of the event handlers installed, all getting called and all trying to do the same work.

How to make my function to be page specific or div id specific?

I am writing javascript to my web pages, but there is a number of functions and loops, that i think are running in all pages, so the first one is running and failing on the second page. Because of this, the javascript function on the second page is not running.
Can anyone give me an idea of how to create page-specific functions or check the availability of an id? I don't use any frameworks.
thanks in advance.
my javascript code is :
window.onload = function(){
var yellows = document.getElementById('magazine-brief').getElementsByTagName('h2');
var signUp = document.getElementById('signup-link');
function animeYellowBar(num){
setTimeout(function(){
yellows[num].style.left = "0";
if(num == yellows.length-1){
setTimeout(function(){
signUp.style.webkitTransform = "scale(1)";
},num * 250);
}
}, num * 500);
}
for (var i = 0; i < yellows.length; i++){
animeYellowBar(i);
}
alert("alert second page");
}
in this code, the alert message not working on second page. any idea?
If I understand you correctly, you have a javascript function, that you want to attach to an event from a specific div element in your page.
a) Include an event directly to you HTML page, something like this:
<div id="element" onclick="some_function();">Text is here</div>
b) Use a javascript function (add this code between <script> tag):
window.onload = function() {
document.getElementById("element").setAttribute("onclick", "some_function()")
}
The best way would be to only include those scripts on the pages which need them. Why waste time loading and parsing scripts you don't need?
If you must keep them on every page, put your functions in an if statement and check for something unique to the page that needs them (such as a form element or field ID).
Update
In response to your comment:
You have to code more defensively. You are attempting to make use of the magazine-brief and signup-link elements before you have made certain that they exist. Never trust that the proper element was returned - always check that it was before attempting to use that element.
I suggest checking your vars like so:
var yellows = document.getElementById('magazine-brief').getElementsByTagName('h2');
var signUp = document.getElementById('signup-link');
if (yellows != 'undefined' && signUp != undefined)
{
function animeYellowBar(num)
{
//...
}
}

Identifying the anchor tag when href is called

How can you identify in a function whether it has been invoked by an anchor tag href?
The event is null in this case, so event.target and event.srcElement won't work.
Code
HTML
Href works here
JavaScript
function SomeFunction ()
{
// I need to get the anchor element that invoked this function
}
What about
Href works here
function SomeFunction(context) {
var callingElement = context;
}
Following what #alex suggested, can you add a script to run in the page load to change the hrefs to be what you want (adding the 'this' reference)?
Take the following script for example, this will change the href value for anchor tags with id set to SomeID or class set to SomeClass:
function changeLinks() {
var all_links = document.getElementsByTagName("a");
for (var i=0; i<all_links.length; i++){
if (all_links[i].id == 'SomeID' || all_links[i].className == 'SomeClass') {
all_links[i].href = 'SomeFunction(this);';
}
}
}
Hope this helps...
Edit:
Following your comment, you can try this:
var clickedAnchor = null;
function setClickedAnchor(obj) {
clickedAnchor = obj;
}
function changeLinks() {
var all_links = document.getElementsByTagName("a");
for (var i=0; i<all_links.length; i++){
if (all_links[i].id == 'SomeID' || all_links[i].className == 'SomeClass') {
all_links[i].href = 'setClickedAnchor(this);' + all_links[i].href;
}
}
}
As far as I know there are only two ways to accomplish this using standard Javascript. The first way has already been outlined -- pass the node as a parameter to the function. The other way would be to handle the onclick event of the anchor. This is very similar to the previous approach in that is requires that you modify the markup to pass a parameter to a function. To do this you'll need to change the markup to the following:
Href works here
function SomeFunction(event) {
var node = event.srcElement;
}
The above code would pass the event object along to the function which would give you all sorts of interesting information about the event.
If you're unable to change the markup that is sent to the browser, you might want to consider using something like JQuery or another AJAX library to search for and modify the event handlers of the nodes at runtime. Modifying the markup before it gets to the browser is obviously preferred, but sometimes you don't have a choice.
Lastly, if you cannot change the markup and don't want to modify the DOM at runtime, you can always see what Javascript engine specific features are available. For example, you might be able to make use of arguments.caller in those engines that support it. I'm not saying that it will work, but you might want to see what's available.

Categories