My page generates a jQuery string (the jqueryBlock below) that gets ajaxed up to a php file that writes it into a new html file, where it will execute. The code "A" below is what I have now to generate the final jQuery, "B" below in the new html file.
"A"
var targetName = "redbox";
target = $('div[filename=' + targetName + ']').hide()[0];
var jqueryBlock= '<script>$(function() {\n';
jqueryBlock += "$('#" + this.id + "').click(function() {\n";
jqueryBlock += "$('#" + target.id + "').show();\n";
jqueryBlock += "}).css('cursor', 'pointer');\n";
jqueryBlock += "$('#" + target.id + "').dblclick(function(){\n$(this).hide();\n});\n";
jqueryBlock += "})<\/script>";
"B"
<script>$(function() {
$('#T_1376594221987').click(function() {
$('#T_1376594237267').show();
})
.css('cursor', 'pointer');
$('#T_1376594237267').dblclick(function(){
$(this).hide();
});
})</script>
This all works, but it's a nightmare to write block A, trying to keep track of the multiple levels of quotes and all the parens and braces and not being able to break lines to make them more readable. I'm thinking that there must be a way to do this where I can write something that looks more like the finished jQuery for "A". Can anyone suggest a better method?
Thanks.
Ok, well... I came up with some ideas... you may like some, all, or none of it. But I figured I'd paste it here. Just a couple of techniques. You can view the JsFiddle as well.
The first, make a function for creating the jQuery selector. This way you can just pass the id, and get your selector, no quotes to worry about.
function makeJqIdSelector(id) {
return "$('#" + id + "')";
}
The same way of thinking, you could write functions to wrap something in <script> tags (or even a function.
function wrapScriptTags(scr) {
return "<script>\n" + scr + "\n<\/script>";
}
Finally, you can use an array to join the elements so you don't have to keep typing out \ns. ie:
var arr = [];
arr.push("a",
"b",
"c"
);
var str = arr.join("\n");
//output:
//a
//b
//c
This has the added effect of being more efficient as well. (probably not an issue for modern browsers, and especially not for this few strings)
Here it is all together:
var thisSelect = makeJqIdSelector(this.id);
var targetSelect = makeJqIdSelector(target.attr('id'));
var jblock = [];
jblock.push(
"$(function() {",
thisSelect + ".click(function() {",
targetSelect + ".show();",
"}).css('cursor', 'pointer');",
targetSelect + ".dblclick(function(){\n$(this).hide();",
"});",
"});"
);
var jqueryBlock = wrapScriptTags(jblock.join("\n"));
output
<script>
$(function() {
$('#T_1376594221987').click(function() {
$('#T_1376594237267').show();
}).css('cursor', 'pointer');
$('#T_1376594237267').dblclick(function(){
$(this).hide();
});
});
</script>
Note: Obviously, I did not spend a lot of time making sure the output was perfect. It was just for the technique - I have no real way of testing it.
If I understanded everything, you could ajax up only the dynamic variables to the PHP file, and change it to something like this:
<script>$(function() {
$('#<?php echo $_GET['id']; ?>').click(function() {
$('#<?php echo $_GET['id']; ?>').show();
})
.css('cursor', 'pointer');
$('#<?php echo $_GET['id']; ?>').dblclick(function(){
$(this).hide();
});
})</script>
In coffeescript you can use a text block that keeps track of the indention level for you. Maybe you can change to coffeescript just for this script.
http://coffeescript.org/#strings
Related
I am trying to pass arguments to onclick event of dynamically generated element. I have already seen the existing stackoveflow questions but it didn't answer my specific need.In this existing question , they are trying to access data using $(this).text(); but I can't use this in my example.
Click event doesn't work on dynamically generated elements
In below code snippet, I am trying to pass program and macroVal to onclick event but it doesn't work.
onClickTest = function(text, type) {
if(text != ""){
// The HTML that will be returned
var program = this.buffer.program;
var out = "<span class=\"";
out += type + " consolas-text";
if (type === "macro" && program) {
var macroVal = text.substring(1, text.length-1);
out += " macro1 program='" + program + "' macroVal='" + macroVal + "'";
}
out += "\">";
out += text;
out += "</span>";
console.log("out " + out);
$("p").on("click" , "span.macro1" , function(e)
{
BqlUtil.myFunction(program, macroVal);
});
}else{
var out = text;
}
return out;
};
console.log of out give me this
<span class="macro consolas-text macro1 program='test1' macroVal='test2'">{TEST}</span>
I have tried both this.program and program but it doesn't work.
Obtain values of span element attributes, since you include them in html:
$("p").on("click" , "span.macro" , function(e)
{
BqlUtil.myFunction(this.getAttribute("program"),
this.getAttribute("macroVal"));
});
There are, however, several things wrong in your code.
you specify class attribute twice in html assigned to out,
single quotes you use are not correct (use ', not ’),
quotes of attribute values are messed up: consistently use either single or double quotes for attribute values
var out = "<span class='";
...
out += "' class='macro' program='" + program + "' macroVal='" + macroVal + ;
...
out += "'>";
depending on how many times you plan to call onClickTest, you may end up with multiple click event handlers for p span.macro.
Here is my test javascript function
<script type="text/javascript">
function test() {
var sHTML = "<script type='text/javascript'> " +
"function showmsg() { " +
"alert('message'); " +
"} " +
"<\/script>" +
"<div>" +
"<a href='#' onclick='javascript:showmsg(); return false;'>click</a>" +
"</div>";
var divTemp = document.createElement("div");
divTemp.innerHTML = sHTML;
var d = document.getElementById("div1");
d.appendChild(divTemp);
}
</script>
When I run this function, the div along with a tag is added in the div1, but when I click on anchor tag, it says showmsg is not defined, which is indicating that browser is NOT parsing the script tag.
How to achieve this without any 3rd party library?
Update:
The possible usage is, I want to allow user to create HTML templates along with JavaScript code, then my JS library will use those HTML templates to render user defined markup, plus allowing user to implement his/her custom logics through JS.
You need to run eval on the script contents when using innerHTML. Try something like:
var scripts = divTemp.getElementsByTagName('script');
for(var i=0; i<scripts.length; i++) {
eval(scripts[i].textContent);
}
Obviously, you need to do this in end, after injecting the innerHTML into the DOM.
Browsers do not run JavaScript code when a <script> tag is dynamically inserted like that.
Instead of that, you can just define the function directly!
function test() {
window.showmsg = function() {
alert("message");
};
var sHTML = "<div>" +
"<a href='#' onclick='javascript:showmsg(); return false;'>click</a>" +
"</div>";
var divTemp = document.createElement("div");
divTemp.innerHTML = sHTML;
var d = document.getElementById("div1");
d.appendChild(divTemp);
}
Libraries like jQuery have code to strip <script> blocks out of text that's being stuffed into some element's innerHTML, and then evaluate it with eval(), so that's one thing to do if the code is somehow "stuck" in a block of content.
Using jquery, is this can help you :
$('<script>function test(){alert("message");};</' + 'script><div>click</div>').appendTo(document.body)
http://jsfiddle.net/TSWsF/
I have a JSON object that looks like this:
var content = '[{"title":"John Apple","lastname":"Apple"},
{"title":"Kumar Patel","lastname":"Patel"},
{"title":"Michaela Quinn","lastname":"Quinn"},
{"title":"Peyton Manning","lastname":"Manning"},
{"title":"John Doe","lastname":"Doe"},
{"title":"Jane Lee","lastname":"Lee"},
{"title":"Dan McMan","lastname":"McMan"},
{"title":"Yu Win","lastname":"Win"}]';
And I am trying to edit it with jQuery to display in my div tag with the id of content-view
here is my jquery:
$.each(content, function(t, l){
$('#view-content').appendTo('<div id = "' + l + '">' + t + '</div>');
});
For some reason on my jsFiddle, which is right here: http://jsfiddle.net/gAWTV/
It just comes up blank with the result. Does anyone have any ideas? I am stumped...
---EDIT---
What i would like to do is have everything output into its own div tags like this:
<div id="Apple">John Apple</div>
<div id="Patel">Kumar Patel</div>
<div id="Quinn">Michaela Quinn</div>
etc...
Your content is a string, not an array of objects.
You firstly need to store it as an array, so get rid of the single quotations marks.
var content = [{"title":"John Apple","lastname":"Apple"},
{"title":"Kumar Patel","lastname":"Patel"},
{"title":"Michaela Quinn","lastname":"Quinn"},
{"title":"Peyton Manning","lastname":"Manning"},
{"title":"John Doe","lastname":"Doe"},
{"title":"Jane Lee","lastname":"Lee"},
{"title":"Dan McMan","lastname":"McMan"},
{"title":"Yu Win","lastname":"Win"}];
Unless there is a reason you store it as a string? Then you need to parse it.
var content_object = JSON.parse(content);
Then you can run your code. However, I think you want to "stringify" your JSON. If that's the case you also need to swap t with l, because l is the object. Finally, you want to append, not appendTo. The latter appends the subject to the target you specify, not the other way round (so in your case appendTo appends #view-content to your div you've constructed, which doesn't work).
$.each(content, function(t, l){
$('#view-content').append('<div id = "' + t + '">' + JSON.stringify(l) + '</div>');
});
JSFiddle
Final comment, I would use document fragments to build your list instead of appending the new divs to an existing one in the each loop - that improves performance.
After OP edit:
Change the last snippet to:
$.each(content, function(t, l){
$('#view-content').append('<div id = "' + l.lastname + '">' + l.title + '</div>');
});
Updated JSFiddle
Try this:
var content = [{"title":"John Apple","lastname":"Apple"},
{"title":"Kumar Patel","lastname":"Patel"},
{"title":"Michaela Quinn","lastname":"Quinn"},
{"title":"Peyton Manning","lastname":"Manning"},
{"title":"John Doe","lastname":"Doe"},
{"title":"Jane Lee","lastname":"Lee"},
{"title":"Dan McMan","lastname":"McMan"},
{"title":"Yu Win","lastname":"Win"}];
$.each(content, function(t, l){
$('<div/>',{
id: l,
text:t }).appendTo('#view-content');
});
DEMO
I am wondering if there is a better way to write this JavaScript (Jquery) code.
This snippet dynamically created a H3 with a link.
My designer is going nuts trying to style this as its in JavaScript.
I am trying to re-write / refactor this into to smaller chunks to allow my designer to style without looking at all this code on one single line.
var dvClassContainer = $(document.createElement('div')).attr("id", 'dvclassconatiner_' + classVal).attr("classifname", classifname).attr("memclassnumber", memclassnumber).html('<h3>' + classifname + '<a id="ancclassremove_'+ classVal +'" classVal="' + classVal + '" onclick="RemoveClassificationUponConfirm(\'' + classVal + '\');" class="buttons delete btnSmall">Delete</a></h3><img style="display:none;" id="imgloadRemClass_' + classVal + '" alt="loading" src="../Images/application/smallUploading.gif" />');
I was thinking of creating more variables and combining them together.
Is there a 'cleaner' way of writing this?
If you utilize more of jQuery's features, the code becomes more readable and more easily maintained:
var dvClassContainer = $('<div>');
dvClassContainer.attr({
id: 'dvclasscontainer_'+classVal,
classifname: classifname,
memclassnumber: memclassnumber
});
var dvHeader = $('<h3>');
var dvHeaderLink = $('<a>Delete</a>');
dvHeaderLink.attr({
id: 'ancclassremove_'+classVal,
classVal: 'classVal',
class: 'buttons delete btnSmall'
}).on('click',function(){
RemoveClassificationUponConfirm(classVal);
});
var dvImg = $('<img>');
dvImg.attr({
id: 'imgloadRemClass_'+classVal,
alt: 'loading',
src: '../Images/application/smallUploading.gif'
});
dvClassContainer.append(dvHeader.append(dvHeaderLink.append(dvImg)));
Ideally, you would also want to move all those non-standard attributes (classifname, memclassnumber, classVal) to data- attributes, which would be accessible via jQuery's data() function.
var dvClassContainer = $(document.createElement('div'))
.attr("id", 'dvclassconatiner_' + classVal)
.attr("classifname", classifname)
.attr("memclassnumber", memclassnumber)
.html('<h3>' + classifname + '<a id="ancclassremove_'+ classVal +'" classVal="' + classVal + '" onclick="RemoveClassificationUponConfirm(\'' + classVal + '\');" class="buttons delete btnSmall">Delete</a></h3><img style="display:none;" id="imgloadRemClass_' + classVal + '" alt="loading" src="../Images/application/smallUploading.gif" />');
The last line still needs fixing. I would create elements and then set their attributes and then append them to the h3. You can do that using var h3 = $("<h3></h3>"); (as an example) and set attributes using .attr() and finally .append() to put it all together.
I'm going to go a different way with this, after acknowledging that this one line of code is nasty.
It's not the JavaScript that's giving your designer headaches. If they can't style this with CSS, they're not trying hard enough. Surely that h3 and anchor are inside other elements that they can grab for some styling:
.someContainer h3 { color: chartreuse; }
However, if they HAVE tried everything possible, you still just need to add a new class or two (to the h3 and the anchor). Where you have .html('<h3>'... you would change it to .html('<h3 class="someClass">'...
As much as we have fun optimizing and downright fixing bad JS in poor implementations, if we assume that this is "working", the problem is the designer's ability to style. This is therefore not really a JavaScript issue.
Use Douglas Crockford's Supplant method. It tokenizes a string so you can dynamically build strings out. Here is a fiddle example: http://jsfiddle.net/mmeah/F23rk/
// http://javascript.crockford.com/remedial.html
if (!String.prototype.supplant) {
String.prototype.supplant = function (o) {
return this.replace(/{([^{}]*)}/g,
function (a, b) {
var r = o[b];
return typeof r === 'string' || typeof r === 'number' ? r : a;
}
);
};
}
var classVal="x", classifname="y", memclassnumber="z"; //predefined
var dvClassHtml = $("#someDiv").html();
$("#someDiv").html("");
var params ={
"classVal":classVal,
"classifname":classifname,
"memclassnumber":memclassnumber
};
dvClassHtml=dvClassHtml.supplant(params);
var dvClassContainer =
$(document.createElement('div'))
.attr("id", 'dvclassconatiner_' + classVal)
.attr("classifname", classifname)
.attr("memclassnumber", memclassnumber)
.html(dvClassHtml);
var dvClassContainer = $('<div/>')
.attr({'id': 'dvclassconatiner_' + classVal,
'classifname': classifname,
'memclassnumber': memclassnumber
})
.html(
function() {
var $title = $('<h3>' + classifname + '</h3>');
var $link = $('<a>Delete</a>').attr({
'id': 'ancclassremove_' + classVal,
'classVal': classVal,
'class': 'buttons delete btnSmall'
})
.on('click', function() {
RemoveClassificationUponConfirm(classVal);
});
var $img = $('<img/>').attr({
'id': 'imgloadRemClass_' + classVal,
'alt': 'loading',
'src': '../Images/application/smallUploading.gif'
})
.css('display', 'none');
return $title.append($link).add($img);
});
Demo
I'm trying to generate a series of check boxes that will update a span to keep track of the number of check boxes that have been checked (shows something like "4 of 12 checked"). I've created the JavaScript function updateSelected that handles that, but it requires the ID of the span and the class of the check boxes to count, so I tried this code to generate each check box:
#Html.CheckBox(string.Format("contentprofilestate[{0}].selected", i),
new { onclick = "updateSelected('" + selectedSpanId + "', '" + checkboxClass + "')" })
This produces the following HTML:
<input id="contentprofilestate_6__selected" name="contentprofilestate[6].selected"
onclick="updateSelected('StMarySpan', 'StMaryCheck')"
type="checkbox" value="true" />
How can I get the onclick event handler to render without escaping the apostrophes? Alternatively, is there a better way to accomplish this task (if so, feel free to use jQuery in your suggestion)?
Note re: Lester
I created a new project and created this view and it still escaped the apostrophes:
#{
ViewBag.Title = "index";
}
<h2>index</h2>
#Html.CheckBox(string.Format("contentprofilestate[{0}].selected", 0), new { onclick = "updateSelected('" + "test" + "', '" + "test2" + "')" })
Alternate Solution
I was not able to figure out how to keep the apostrophes from being escaped, so I wrote some jQuery logic to do what I need without any inline JavaScript:
jQuery(document).ready(function () {
jQuery(':checkbox').click(function () {
var clientHeader = jQuery(this).closest('.client-header');
var clientCheckedSpan = clientHeader.find('.client-checked');
var inputChecked = clientHeader.find('input:checked');
clientCheckedSpan.text(inputChecked.length);
});
});
It's very odd that the apostrophes are being encoded. I didn't think they would be and after doing a quick test they aren't. There's probably something else going on in that view. If you place just that 1 line in an empty view I'm betting you won't get the same problem.
As for any other alternatives, you can easily get the number of selected checkboxes using jQuery:
var numChecked = $("input:checked[id^=contentprofilestate]").size();