I have the following
var id='123';
newDiv.innerHTML = "";
Which renders in my HTML.
The problem I have is that I wish to take the call to the method TestFunction, and use as a string parameter in my function StepTwo(string, boolean), which would ideally end up in live HTML as shown...
notice how the TestFunction is a string here (it is executed within StepTwo using eval).
I have tried to format my JS as by :
newDiv.innerHTML = "";
but while this appears to me correct in my IDE, in the rendered HTML, it as garbelled beyond belief.
Would appreciate if anyone could point me in the right direction. Thanks!
One of the biggest capital failures on the internet is creating html in javascript by gluing strings together.
var mya = document.createElement("a");
mya.href="#";
mya.onclick = function(){
StepTwo(function(){
TestFunction('123', false );
}, true );
};
newDiv.innerHTML = "";
newDiv.appendChild(mya);
This Eliminates the need for any fancy escaping stuff.
( I probably should do 'onclick' differently, but this should work, I'm trying hard not to just use jQuery code to do everything )
Heres how I would do it in jQuery:
jQuery(function($){
var container = $("#container");
var link = document.createElement("a"); /* faster than $("<a></a>"); */
$(link).attr("href", "Something ( or # )" );
$(link).click( function(){
var doStepTwo = function()
{
TestFunction('123', true );
};
StepTwo( doStepTwo, false ); /* StepTwo -> doStepTwo -> TestFunction() */
});
container.append(link);
});
There is no good excuse for gluing strings together in Javascript
All it does is ADD overhead of html parsing back into dom structures, and ADD potential for XSS based broken HTML. Even beloved google get this wrong in some of their advertising scripts and have caused epic failures in many cases I have seen ( and they don't want to know about it )
I don't understand Javascript is the only excuse, and it's NOT a good one.
Try using " instead of \"
newDiv.innerHTML = "<a href="#"...
You should be using " not " or \" inside an HTML string quoted with double-quotes.
NewDiv.innerHTML = "";
There's probably a better way to do this - any time you find yourself using eval() you should stand back and look for a different solution.
You claim that eval is the right thing to do here. I'm not so sure.
Have you considered this approach:
and in your StepTwo function
function StepTwo(func,args,flag){
//do what ever you do with the flag
//instead of eval use the function.apply to call the function.
func.apply(args);
}
You could create the a element and attach to the click event using DOM Methods.
A Javascript Framework (like the ubiquitous jQuery) would make this a lot easier.
Your biggest problem is using eval, it leads to so many potential problems that it's nearly always better to find an alternative solution.
Your immediate problem is that what you really have is
as the next " after the start of the onclick attribute, closes it. Use " as others have suggested. And don't use eval.
You need to alternate your " and '.
Maybe you don't need quotes around the 123, because of Javascripts flexible typing. Pass it without quotes but treat it as a string within TestFunction.
Hey guys, thanks for all the answers. I find that the quot; seems to work best.
I'll give you guys some votes up once I get more reputation!
In regards to eval(), what you see in the question is a very small snapshot of the application being developed. I understand the woes of eval, however, this is one of those one in a million situations where it's the correct choice for the situation at hand.
It would be understood better if you could see what these functions do (have given them very generic names for stackoverflow).
Thanks again!
The best way is to create the element with document.createElement, but if you're not willing to, I guess you could do or use ".
In your code:
newDiv.innerHTML = "";
If it doesn't work, try changing "\'" to "\\'".
Remember that the " character is used to open and close the attribute on HTML tags. If you use it in the attribute's value, the browser will understand it as the close char.
Example:
<input type="text" value="foo"bar"> will end up being <input type="text" value="foo">.
...
I know this is hella' old now, but if anyone has issues with escaped strings when using eval (and you absolutely have to use eval), I've got a way to avoid problems.
var html = '';
eval('(function(div, html){div.innerHTML = html;})')(newDiv, html);
So, what's going on here?
eval creates a function that contains two parameters, div and html and returns it.
The function is immediately run with the parameters to the right of the eval function. This is basically like an IIFE.
In this case
var myNewMethod = eval('(function(div, html){div.innerHTML = html;})');
is basically the same as:
var myNewMethod = function(div, html){div.innerHTML = html;}
and then we're just doing this:
myNewMethod(newDiv, html); //where html had the string containing markup
I would suggest not using eval. If it can't be avoided, or if you control all the inputs and there's no risk of injection then this will help in cases where string escapes are an issue.
I also tend to use Function, but it isn't any more secure.
Here's the snippet I use:
var feval = function(code) {
return (new Function(code))();
}
Related
I have the below javascript to get the UserID from a online form. This script will go through IE DOM Explorer to find the valued. But when I run the script, it is totally ignoring my "If" statement. It is just providing a value for "NewAuthUserID", without considering the "if".
(function () {
var NewAuthUserID = "";
var UserId = $('tr.background-highlight:contains("REQUESTER PROFILE") + tr').children('td:contains("User ID:")+td').text();
if ('tr.background-highlight:contains("NEW AUTHORIZED INDIVIDUAL PROFILE:"') {
var NewAuthUserID = $('td:contains("User ID:")+td:eq(2)').text();
};
alert(UserId);
alert(NewAuthUserID)
})();
Firstly, I'd suggest to check out how the if statement works: https://www.w3schools.com/js/js_if_else.asp
You need the if statement conditional to return true or false. Right now you're TRYING to use jquery to select things but even that has a syntax issues. Not only that but once the syntax is fixed it STILL won't do what you're attempting to do because you're putting something that will always evaluate to true as the conditional. That jquery selector just returns a function, not a boolean like it looks like you're intending to do. Try this:
(function(){
var NewAuthUserID = "";
var UserId=$('tr.background-highlight:contains("REQUESTER PROFILE") + tr').children('td:contains("User ID:")+td').text();
if($('tr.background-highlight').text() == "NEW AUTHORIZED INDIVIDUAL PROFILE:")){
var NewAuthUserID=$('td:contains("User ID:")+td:eq(2)').text();
}
alert(UserId);
alert(NewAuthUserID)
})();
Notice how I'm snagging the text that you're trying to test against with jquery and expressing it with a conditional instead? In this manner, it will return the boolean: true/false which is what you need to get the if statement to trigger.
Also if you check your syntax, you were missing the $() wrapper around your if statement, but you have a string that looked like it was trying to snag text via jquery.
I suggest formatting your code a bit, this always helps to debug.
The problem is you are trying to use a jQuery selector in your if statement, but you didn't include the $ to evaluate jQuery. It's just evaluating a string, wich results in TRUE (basically doing this: if(true)), so the code block is executed.
Try this instead:
javascript: (function() {
var NewAuthUserID = "";
var UserId = $('tr.background-highlight:contains("REQUESTER PROFILE") + tr').children('td:contains("User ID:")+td').text();
if ($('tr.background-highlight:contains("NEW AUTHORIZED INDIVIDUAL PROFILE:"').length > 0) {
var NewAuthUserID = $('td:contains("User ID:")+td:eq(2)').text();
};
alert(UserId);
alert(NewAuthUserID)
})();
EDIT: I added the length > 0 check on the returned object. It's possible to accomplish this with OP's code, he was just missing those two pieces. :contains is not the same as .text() ==.
Off topic response:
The way you manage/select your nodes may require a lot of maintanance in the future and is prone to errors.
For example: tr.background-highlight:contains("REQUESTER PROFILE") + tr
In words: Get me the table-row after a table-row with hilighted background, that contains "REQUESTER PROFILE".
What if you'll have to add a row in between them? what if you'll need to select the row, wether it is hilighted or not? what if further rows will be hilighted in the future, so that this selector ain't uniqu anymore? what if the label changes? maybe even the language? ...
In each of these cases you'll have to revisit (potentially all) your jquery selectors, just because some minor layout changed.
That's not very reliable.
Will you remember that when you'll get asked to do these changes? Maybe someone else will have to do these changes, will he/she know what to look for?
Tell me, do you remember the details/implications/quirks of the work you've done a week ago? not to speak about your work from a few months ago.
Better:
Use "unique" identifier to, well, identify your nodes by their role; and I'm not talking about IDs. Unique within their specific context.
The easiest way would be to use css-classes. Annotating the rows/cells so you can select the very same field as $('.ref-requester-provile .ref-user-id')
This is way more reliable and future-proof than your bulky $('tr.background-highlight:contains("REQUESTER PROFILE") + tr').children('td:contains("User ID:")+td') where your JS needs to know every little detail of your template/markup, and needs to be adapted with every little change.
Why did I prepend these classes with ref-? to distinct them from classes that are meant for styling
If you don't need to style these nodes and need these identifyer solely to reference them in your JS, I'd rather use a data-attribute. Why? Let's sum it up with:
performance: when you need to add/remove these marker; avoid unnecessary render-cycles
A cleaner seperation between style and code: classes are primarily for styling, but we don't style here.
Pretty simple question that I couldn't find an answer to, maybe because it's a non-issue, but I'm wondering if there is a difference between creating an HTML object using Javascript or using a string to build an element. Like, is it a better practice to declare any HTML elements in JS as JS objects or as strings and let the browser/library/etc parse them? For example:
jQuery('<div />', {'class': 'example'});
vs
jQuery('<div class="example></div>');
(Just using jQuery as an example, but same question applies for vanilla JS as well.)
It seems like a non-issue to me but I'm no JS expert, and I want to make sure I'm doing it right. Thanks in advance!
They're both "correct". And both are useful at different times for different purposes.
For instance, in terms of page-speed, these days it's faster to just do something like:
document.body.innerHTML = "<header>....big string o' html text</footer>";
The browser will spit it out in an instant.
As a matter of safety, when dealing with user-input, it's safer to build elements, attach them to a documentFragment and then append them to the DOM (or replace a DOM node with your new version, or whatever).
Consider:
var userPost = "My name is Bob.<script src=\"//bad-place.com/awful-things.js\"></script>",
paragraph = "<p>" + userPost + "</p>";
commentList.innerHTML += paragraph;
Versus:
var userPost = "My name is Bob.<script src=\"//bad-place.com/awful-things.js\"></script>",
paragraph = document.createElement("p");
paragraph.appendChild( document.createTextNode(userPost) );
commentList.appendChild(paragraph);
One does bad things and one doesn't.
Of course, you don't have to create textNodes, you could use innerText or textContent or whatever (the browser will create the text node on its own).
But it's always important to consider what you're sharing and how.
If it's coming from anywhere other than a place you trust (which should be approximately nowhere, unless you're serving static pages, in which case, why are you building html?), then you should keep injection in mind -- only the things you WANT to be injected should be.
Either can be preferable depending on your particular scenario—ie, if everything is hard-coded, option 2 is probably better, as #camus said.
One limitation with the first option though, is that this
$("<div data-foo='X' />", { 'class': 'example' });
will not work. That overload expects a naked tag as the first parameter with no attributes at all.
This was reported here
1/ is better if your attribubes depends on variables set before calling the $ function , dont have to concatenate strings and variables. Aside from that fact ,since you can do both , and it's just some js code somebody else wrote , not a C++ DOM API hardcoded in the browser...
I just wanted to know the differences between the methods of adding html in jquery.
both will do samething right?
$('body').append($("<div><img src='somesource' alt='something'></div>"));
and
var div = $("<div>");
var img = $("<img>").attr({"src" : "somesource", "alt" : "something"});
div.append(img);
$('body').append(div);
which is the best practice to follow?
The second is better. Because you often see people doing this:
var alt = 'This is " the title containing a double quote';
$('body').append($('<div><img src="somesource" alt="' + alt + '"></div>'));
and then wonder why something got eaten :-). Whereas when you use the second you have absolutely nothing to worry about:
var alt = 'This is " the title containing a double quote';
var div = $('<div>');
var img = $('<img>').attr({ src : 'somesource', alt : alt });
div.append(img);
$('body').append(div);
UPDATE:
I was too hasty in saying that you have nothing to worry about with the second approach. As others have already pointed out you have to worry about performance.
The second method looks better and there are lesser chances of error. But performance wise, the second method is slower. So if you're going to be doing a lot of appending, I would recommend going with the the first case - albeit, carefully.
Here's a small test case up on JS-Perf comparing the two methods
Normally I would say DOM-scripting is the better option (the second approach); it's more structured, and easier to catch issues than by inserting a mass of HTML prepared as a string.
That said, there are performance concerns. Inserting loads of elements via DOM-scripting, particularly in a loop, can cause significant slowdown and there are cases where inserting as a string is much quicker.
Also, the fewer inserts you do - by whatever means - the fewer repaints/refreshes you force the browser to make. Again, these all require browser attention, so the fewer the better.
I believe you are better off using template libraries for inserting objects. An example of one such library is here: http://api.jquery.com/category/plugins/templates/
Those libraries are build for performance and ease the burden on parsing HTML blobs.
Adding a string of HTML content is about 10 times faster
than using second method
Here is a reference
See also my answer on When do you use DOM-based Generation vs. using strings/innerHTML/JQuery to generate DOM content?
The difference is that you have two variables pointing to the jQuery instances. You might can need them for eventListener-adding or manipulating them lateron in the code.
Also, DOM-based element generation has the advantage of automatically escaping the strings, which is especially useful when designing functions with parameters and absolutely needed for user input.
Therefore, the second method is most often preferred. You can also nest the appending process to make the structure clear (OK, in this example the one-liner would be clear as well):
var div = $("<div>");
var img = $("<img>", {"src":"somesource", "alt":"something"});
$('body').append(
div.append(
img
)
);
I would prefer the second one as the first one could lead to very long lines and if you need to bind events to certain elements you already have a variable that is pointing to it.
var str = '<div part="1">
<div>
...
<p class="so">text</p>
...
</div>
</div><span></span>';
I got a long string stored in var str, I need to extract the the strings inside div part="1". Can you help me please?
you could create a DOM element and set its innerHTML to your string.
Then you can iterate through the childNodes and read the attributes you want ;)
example
var str = "<your><html>";
var node = document.createElement("div");
node.innerHTML = str;
for(var i = 0; i < node.childNodes.length; i++){
console.log(node.childNodes[i].getAttribute("part"));
}
If you're using a library like JQuery, this is trivially easy without having to go through the horrors of parsing HTML with regex.
Simply load the string into a JQuery object; then you'll be able to query it using selectors. It's as simple as this:
var so = $(str).find('.so');
to get the class='so' elememnt.
If you want to get all the text in part='1', then it would be this:
var part1 = $(str).find('[part=1]').text();
Similar results can be achieved with Prototype library, or others. Without any library, you can still do the same thing using the DOM, but it'll be much harder work.
Just to clarify why it's a bad idea to do this sort of thing in regex:
Yes, it can be done. It is possible to scan a block of HTML code with regex and find things within the string.
However, the issue is that HTML is too variable -- it is defined as a non-regular language (bear in mind that the 'reg' in 'regex' is for 'regular').
If you know that your HTML structure is always going to look the same, it's relatively easy. However if it's ever going to be possible that the incoming HTML might contain elements or attributes other than the exact ones you're expecting, suddenly writing the regex becomes extremely difficult, because regex is designed for searching in predictable strings. When you factor in the possibility of being given invalid HTML code to parse, the difficulty factor increases even more.
With a lot of effort and good understanding of the more esoteric parts of regex, it can be done, with a reasonable degree of reliability. But it's never going to be perfect -- there's always going to be the possibility of your regex not working if it's fed with something it doesn't expect.
By contrast, parsing it with the DOM is much much simpler -- as demonstrated, with the right libraries, it can be a single line of code (and very easy to read, unlike the horrific regex you'd need to write). It'll also be much more efficient to run, and gives you the ability to do other search operations on the same chunk of HTML, without having to re-parse it all again.
I try to copy an onClick function from an image to an span object.
But I don't get it.
I have tried it directly with onClick=img.onClick, onClick=new Function(img.onClick) and more.
if (img.onclick != undefined)
{
var imgClick = img.onclick;
strNewHTML = strNewHTML + " onMouseOver=\"this.style.background"
+ "= '#cecece'\" onMouseOut=\"this.style.background = ''\" onclick=\""+imgClick+"\">";
}
Can anyone help me?
Thanks!
span.onclick= img.onclick;
JavaScript is case-sensitive and DOM event handler properties are all lower-case.
edit:
if (img.onclick != undefined) {
strNewHTML = strNewHTML + " onMouseOver=\"this.style.background"
+ "= '#cecece'\" onMouseOut=\"this.style.background = ''\" onclick=\""+imgClick+"\">";
}
Well that's a completely different thing. You're creating an HTML string. But the onclick DOM property contains a function object. function objects can't be added into strings. (They would get converted to what you get if you call somefunction.toString(), which is not something that will work as an event handler.)
If you wanted to fetch the textual value of the onclick attribute to add into HTML, you'd have to do it with the span.getAttribute('onclick') method. But that won't work in IE due to bugs in its implementation of getAttribute, so you'd have to resort to span.getAttributeNode('onclick').value. And then when you added it into the HTML string, you'd have to HTML-escape it, so that any <, & and " characters in it came out as < etc., otherwise they'll break the markup.
However, this is really ugly; don't do it. In reality, HTML string-slinging invariably sucks. Especially when you've got JavaScript code inside HTML inside a JavaScript string. The escaping rules get insane and if you make a mistake escaping content that comes from user input, you've given yourself a cross-site-scripting security hole.
Instead, use DOM methods. This takes all the escaping out of the equation and it's generally more readable than hacked-together HTML markup strings. Then you can freely assign onclick to whatever function you like. eg.:
var span= document.createElement('span');
if (img.onclick)
span.onclick= img.onclick;
span.onmouseover= function() {
this.style.background= '#CECECE';
};
span.onmouseout= function() {
this.style.background= '';
};
someparentelement.appendChild(span);
Also consider replacing the mouseover/mouseout with a simple CSS :hover rule, for maintainability. The only browser that still needs help with :hover is IE6.