I'm building a small app with a few modal dialog windows. The windows require a tiny bit of HTML. I've hard coded the window HTML in the javascript library but am not thrilled with this solution. Is there a more elegant way to do this? It seems that JavaScript doesn't have multi line strings/heredoc syntax.
var html = "<div id='email_window'><h2>Email Share</h2><div>";
html = html + "<form action='javascript:emailDone();' method='post'>";
html = html + "<div><label for='to'>To</label><input id='to' type='text'></div>";
html = html + "<div><label for='from'>From</label><input id='from' type='text' value='" + email + "'></div>";
html = html + "<div><label for='subject'>Subject</label><input id='subject' type='text' disabled='disabled' value='" + subject + "'></div>";
html = html + "<div><label for='body'>Body</label><input id='body' type='text' disabled='disabled' value='" + body + "'></div>";
html = html + "<div><input type='submit' value='Send'><input type='button' value='Cancel' onClick='javascript:$.fancybox.close();'></div>";
html = html + "</form></div>";
$("#data").html(html);
Added to clarify the original message-
Any solution can't use Ajax/XHR to pull in the template file because the javascript library will be on a different domain that the html file it's included in
It's a little like ShareThis. The library will be included on a number of different sites and attached to the onClick event of any anchor tag inside divs with attribute sharetool="true".
For example:
http://www.bar.com - index.html
<html>
...
<script type="text/javascript" src="http://www.foo.com/sharetool.js"></script>
...
<body>
<div sharetool="true">
</div>
...
</html>
You can include the HTML as regular markup at the end of the page, inside an invisible div. Then you're able to reference it with jQuery.
You then need to programmatically set your variable fields (email, subject, body)
<div id='container' style='display: none;'>
<div id='your-dialog-box-contents'>
...
...
</div>
</div>
<script type='text/javascript'>
$("#from").val(from);
$("#subject").val(subject);
$("#body").val(body);
$("#data").html($("#your-dialog-box-contents"));
</script>
Templates. Pick your poison
EJS
jQuery templates (nb: development discontinued)
underscore templates
mustache
jResig micro templates
Either inline them as script blocks or load them using ajax as external resources.
I personally use EJS as external template files and just get EJS to load them and inject them into a container with json data bound to the template.
new EJS({
url: "url/to/view"
}).update('html_container_name', {
"foobar": "Suprise"
});
And then view files use generic view logic.
// url/to/view
<p> <%=foobar %></p>
For multiline strings (no frameworks, just javascript) there are several solutions. See my answer to this SO Question. You could combine that with some simple templating:
String.prototype.template = String.prototype.template ||
function (){
var args = Array.prototype.slice.call(arguments)
,str = this
,i=0
;
function replacer(a){
var aa = parseInt(a.substr(1),10)-1;
return args[aa];
}
return str.replace(/(\$\d+)/gm,replacer)
};
//basic usage:
'some #1'.template('string'); //=> some string
//your 'html' could look like:
var html =
[ '<form action="javascript:emailDone();" method="post">',
' <div><label for="to">To</label>',
' <input id="to" type="text"></div>',
' <div><label for="from">From</label>',
' <input id="from" type="text" ',
' value="$0"></div>',
' <div><label for="subject">Subject</label>',
' <input id="subject" type="text" disabled="disabled" ',
' value="$1"></div>',
' <div><label for="body">Body</label>',
' <input id="body" type="text" disabled="disabled" ',
' value="$2"></div>',
' <div><input type="submit" value="Send"><input type="button" ',
' value="Cancel" ',
' onClick="javascript:$.fancybox.close();"></div>',
'</form>'
] .join('').template(email, subject, body);
Personally I like building DOM trees like this:
$('#data').html(
$('<div/>', {
id: 'email_window',
html: $('<h2/>', {
html: 'Email Share'
})
}).after(
$('<form/>', {
action: 'javascript:emailDone();',
method: 'post',
html: $('<div/>', {
html: $('<label/>', {
for: 'to',
html: 'To'
}).after($('<input/>', {
id: 'to',
type: 'text'
}))
}).after(
... etc
)
})
)
);
There is 2 solutions tto your problem:
- An alternative to the heredoc Syntax in javascript is to escape the newline char with \ :
var tpl = "hello\
stackoverflow\
World !";
The char is escaped so ignored, and it wont take place in the resulting string.
You can also create a plain html file with your template, and in your js script you create a hidden iframe and load the crossdomain html template. You can now access the document object of the iframe and retreive body.innerHTML. In theory! I Didn't tested this solution yet....
You're right, JS doesn't have heredocs or multi-line strings. That said, the usual approach to this is to have the HTML in...the HTML, and show or hide it as appropriate. You're already using jQuery, so you're most of the way there:
<div style="display:none;">
<form method='post' class="email">
<input id='from' type='text'> <!-- other form fields omitted for brevity -->
</form>
<form method='post' class="facebook"></form> <!-- again, omitted for brevity -->
</div>
Then, you can populate the form and toss it in the right spot:
$('#data').html($('form.email').find('input#from').val(email).end().html());
Cook.js
div([
button({click:[firstEvent, secondEvent]},
'You can bind (attach) events on the fly.'),
p('Here are some popular search engines'),
ul([
li([
a('Google', {href:'http://www.google.com'})
]),
li([
a('Bing', {href:'http://www.bing.com'})
]),
li([
a('Yahoo', {href:'http://www.yahoo.com'})
])
])
]);
how it works
Objects = Attribute & Events
-> {href:'facebook.com', src:'static/cat.gif', ng-bind:'blah'}
String = Text or Html
-> 'hello world'
Array = Elements
-> [a('hello world', {href:'facebook.com'}), img({src:'static/cat.gif'})]
more on cook.js!
Related
Im using this to capture the HTML source for a single html page.
It works good except for one thing.
After entering values into my html page, when I do the capture it only captures the page without the edited values.
Any Ideas please.
var getDocTypeAsString = function () {
var node = document.doctype;
return node ? "<!DOCTYPE "
+ node.name
+ (node.publicId ? ' PUBLIC "' + node.publicId + '"' : '')
+ (!node.publicId && node.systemId ? ' SYSTEM' : '')
+ (node.systemId ? ' "' + node.systemId + '"' : '')
+ '>\n' : '';
};
function getPageHTML() {
// alert( "<html>" + $("html").html() + "</html>" );
console.log(getDocTypeAsString() + document.documentElement.outerHTML);
}
and the call from the button
<div class="no-print">
<div class="buttonBar">
<input type="button" class="button" value="Print" onClick="window.print()">
<input type="button" class="button" value="Save" onClick="getPageHTML()">
</div>
</div>
The editing values will come from similar fields like this
So I would like to capture the edited 'PastMedicalHistory' as-well
<div class='row'>
<div class='cell100'>
<div class='table'>
<div class='cell100 content'>
<textarea id='PMH' class='basicTextArea PMHText' name="PastMedicalHistory"></textarea>
</div>
</div>
</div>
</div>
What are you trying to achieve?
The statement document.documentElement.outerHTML will take the HTML itself as rendered.
The values of the input elements are filled in afterwards, so not visible via outerHTML.
You could run through the elements, inspect them and populate the DOM.
What would be for the best, though is to describe what are you trying to achieve and put the full code example on codepen or similar.
You can't do that, this easy way. You're getting the same as looking "source code" from your browser.
Use jQuery or JS to parse document input values.
Then reinject it in your getDocTypeAsString
Found something that seems to work fine, but Im not that great of an expert to judge this on possible limitations
keep a watch over items like this
$( document ).ready(function() {
var isDirty = false;
$("textarea").on("change", function() {
isDirty = (this.defaultValue !== this.value);
if (isDirty)
this.defaultValue = this.value;
});
$("input").on("change", function() {
isDirty = (this.defaultValue !== this.value);
if (isDirty)
this.defaultValue = this.value;
});
});
call for the source of the new html like this
function getPageHTML() {
console.log( "<html>" + $("html").html() + "</html>");
}
I can't 'echo' the ' ' closers in jQuery.
I tried this method:
$('#run').append("<pre><code class='prettyprint'>"+data+"</code></pre> <div data-ac-chart="+"'"+"bar"+"'"+" data-ac-data='data' data-ac-config='config' class='chart'></div>");
But this will show:
<div data-ac-chart="bar" data-ac-data="data" data-ac-config="config" class="chart"></div>
How to edit the jQUery code to the result will be this:
<div data-ac-chart="'bar'" data-ac-data="data" data-ac-config="config" class="chart"></div>
Not the neatest solution, but you could escape the double quotes.
<div data-ac-chart=\"'" + data + "'\"></div>
Example Here
$('#run').append("<pre><code class='prettyprint'>"+data+"</code></pre> <div data-ac-chart=\"'" + data + "'\" data-ac-data='data' data-ac-config='config' class='chart'></div>");
For a neater solution, I'd suggest checking out a JS templating engine.
Alternatively, you could also just change/add the value after you have appended the element:
Example Here
$('#run [data-ac-chart]').attr('data-ac-chart', "'" + data + "'");
Try this to add \ before the apostrophe, like this:
data-ac-chart="+"\'"+"bar"+"\'"
Josh was right with :
data-ac-chart="+\"'"+"bar"+"'\"
You can escape such characters using a backslash.
A) With single quotes around HTML attributes: (not recommended, here you have to escape the created attribute value)
var output = "<div data-ac-chart='\\\'bar\\\'' data-ac-data='data' data-ac-config='config' class='chart'></div>";
The multitude of backslashes is required here to mask the backslash and single quote inside the attribute from JavaScript. JS then outputs HTML with escaped attribute values:
"<div data-ac-chart='\'bar\'' data-ac-data='data' data-ac-config='config' class='chart'></div>"
B) With double quotes around HTML attributes: (recommended, write beautiful markup and everything will work out :-)
var output = '<div data-ac-chart="\'bar\'" data-ac-data="data" data-ac-config="config" class="chart"></div>';
C) A more readable approach using placeholders and string replacement:
var output = '<div data-ac-chart="{chart}" data-ac-data="{data}" data-ac-config="{config}" class="chart"></div>'
.replace( '{chart}', '\'bar\'' )
.replace( '{data}', 'data' )
.replace( '{config}', 'config' );
Concatenating strings is cumbersome and as you experience quite difficult to debug. That's why I recommend using a template approach as supported by underscorejs:
<!-- in your HTML -->
<script type="text/template" id="template">
<div>
<pre>
<code class='prettyprint'>
<%=data%>
</code>
</pre>
<div data-ac-chart='bar' data-ac-data='data' data-ac-config='config' class='chart'>
</div>
</div>
</script>
/* in your javascript */
$('#run').append(_.template($("#template").html())({
data : "var function(x) = { some code };"
}));
Make sure to load the underscorejs library. A working example is available in this jsfiddle
Please help me to solve this string formating . it shows error while running.
I need to call a java script function AddHotel() with some php variables from an input tag. while running the first parameter in function shows error. It should be like onClick='AddHotel('divid', 'some_id', 'id',ids,rate)'
but while running in comes as onClick='AddHotel(divid', 'some_id', 'id',ids,rate)'
$resort[] = "<div id='".$iiiddd."'><input id='hotel_day".$child_post->ID.$dyid."' name='hotel_day".$dyid."' type='radio' value='".$child_post->ID."' onclick='AddHotel(".$p.",'".$s."','".$psid."','".$dyid."','".$child_post->ID."',".$child_post->fields['price'].")' />
<input id='".$s."' name='expsel".$dyid."[]' type='hidden' value='' />".$child_post->post_title."<span>Rs:- ".$child_post->fields['price']."</span></div>";
You want to escape Quotes
$resort[] = "<div id='".$iiiddd."'><input id='hotel_day".$child_post->ID.$dyid."' name='hotel_day".$dyid."' type='radio' value='".$child_post->ID."' onclick='AddHotel(".$p.",\'".$s."\',\'".$psid."\',\'".$dyid."\',\'".$child_post->ID."\',".$child_post->fields['price'].")' />".$child_post->post_title."Rs:- ".$child_post->fields['price']."";
For all who face such issues:
You should always use Double quotes for HTML attributes value eg:
<div attribute="value"><div>
For passing variables in a Javascript functions, you must use quotes (single quote preferably) for string. eg:
somethingAwesome('work', 'life', 1);
While embedding HTML and Javascript in PHP, you must not get confused with Quotes.
PHP string + HTML element:
$string = '<div></div>';
PHP string + HTML element with attributes:
$string = '<div id="awesome"></div>';
PHP string + HTML element with attributes + Javascript Function:
$string = '<div id="awesome" onclick="somethingAwesome()"></div>';
PHP string + HTML element with attributes + Javascript Function with Parameters:
$string = '<div id="awesome" onclick="somethingAwesome(\''.$string.'\', \''.$string2.'\', '.$integer.');"></div>';
You are open to choose double or single quotes, but following one particular fashion will prevent you from getting confused.
Also remember to Indent your code even in case of HTML in strings
Solution for your issue:
$resort[] = '<div id="'.$iiiddd.'">
<input id="hotel_day'.$child_post->ID.$dyid.'" name="hotel_day'.$dyid.'" type="radio" value="'.$child_post->ID.'" onclick="AddHotel(\''.$p.'\', \''.$s.'\', '.$psid.', \''.$dyid.'\', '.$child_post->ID.', \''.$child_post->fields['price'].'\')" />
<input id="'.$s.'" name="expsel'.$dyid.'[]" type="hidden" value="" />
'.$child_post->post_title.'
<span>Rs:- '.$child_post->fields['price'].'</span>
</div>';
I am developing MVC application and using razor syntax.
I want to use HTML code in JavaScript in cshtml file, but I get confused about how to use double quotes in JavaScript in razor syntax. Is that matter?
This is line of code:
<span class="EmpName"> #Html.ActionLink(item.Owner.FullName, "Details", "EMployee", new { id = item.OwnerId }, new { #style = "color:#1A6690;" })</span>
#Html.DisplayFor(ModelItem => item.CommentDateTime)
<span class="EmpName"><button type="button" id = "#item.Id" class="deleteComment">Delete</button></span>
And I have written below code in JavaScript, is that right?
success: function (data) {
$("p.p12").append
("<div style=\"background-color:#FAFAFA\";>Recently Added... <br />" + data.OwnerName + ""
+ data.cmtDateTime + "<button type=\"button\" id = \" + data.Id + "\class=\"deleteComment\">Delete</button></span><br />" + data.msg + "</div>");
}
and I have written below code in JScript is that right ?
No, it doesn't seem right. The generated HTML is broken. You need to be more careful about the syntax, things liks spaces between the attributes and the quotes are important. Also you seem to be hardcoding urls instead of using url helpers. Try like this:
$('p.p12').append(
'<div style="background-color:#FAFAFA;">Recently Added... <br />' + data.OwnerName + '' + data.cmtDateTime + '<span><button type="button" id=' + data.Id + ' class="deleteComment">Delete</button></span><br />' + data.msg + '</div>'
);
or as I suggested you here which IMHO is more correct approach.
or since you are using an AJAX call, instead of returning JSON from your controller action, return a ParialView in which you will correctly build the markup using proper HTML helpers.
Like this:
[HttpPost]
public ActionResult SomeAction(SomeViewModel args)
{
MyViewModel model = ...
return PartislView("_SomePartial", model);
}
and then inside your strongly typed partial (_SomePartial.cshtml) build the markup without any string concatenations and spaghetti code mixing javascript and HTML:
#model MyViewModel
<div style="background-color:#FAFAFA;">
Recently Added...
<br />
#Html.ActionLink(Model.OwnerName, "Details", "Employee", new { id = Model.OwnerID }, null)
#HtmlDisplayFor(x => x.cmtDateTime)
<span>
<button type="button" id="#Model.Id" class="deleteComment">Delete</button>
</span>
<br />
#HtmlDisplayFor(x => x.msg)
</div>
Now all that's left in your AJAX success callback is to refresh the corresponding DOM section:
success: function(html) {
$('p.p12').append(html);
}
I have a lot of JavaScript code that creates HTML. For example:
function Reply(postId) {
if (!document.getElementById("reply" + postId)) {
$("#root" + postId).after("<div id='reply" + postId + "'><textarea cols='70' rows='8' style='margin-bottom: 10px'></textarea><br/><span style='margin-bottom: 30px'><input type='button' value='Submit' /><input type='button' value='Cancel' onclick='$(\"#reply" + postId + "\").remove();'/></span></div>");
}
}
How can I use jQuery to make this more readable? What's the best way to go about making new elements in JavaScript? Can I see an example?
The standard way is not to create html and then appending or prepending it but to create dom elements and adding them.
Please read this wonderful article on innerHTML vs DOM. by Tim Scarfe. It's very well written and and points and counter points.
You can read more on DOM here. and a Lot of information at the Gecko DOM Reference..
Sorry for only pasting links but it's a lot to go through.
If you want a quickstart. Look at this part of the Gecko DOM Reference. where they talk about createElement. Which is the magical method you're looking for.
First of all you need to know where you want to append the HTML, here you'll see the documentation: for "manipulation": here.
So lets say you want to create a paragraph inside a DIV with the ID "insideme".
$("#insideme").append("<p>I'm adding this</p>");
That is for creation, now lets say you want to insert an existent DIV:
$("#insideme").append($("div#existent"));
Check the documentation, there you'll find every function that is used to add before, after, inside, etc.
Hope it helped you.
If you want to fully use jquery functions, see if the following works (I have not tested it). Howerver, I would actually advise against this since I understand that direct HTML-string parsing/rendering is optimized a lot faster than a bunch of js function calls.
function Reply(postId) {
var rid = "reply"+postId;
if (!$('#'+rid)) {
$('#root'+postID)
.append("<div/>").attr('id',rid)
.append("<textarea/>").attr({'cols',70,'row',8,'style','margin-bottom: 10px'})
.after("<br/>")
.after("<span />").attr('style','margin-bottom: 30px');
.append("<input type='button' value='Submit' />")
.after("<input type='button' value='Cancel' />")
.onclick(function(){
$("#"+rid).remove();
});
}
}
Two ways:
Improve the formatting of that string
Install event handlers programatically
Eg:
function Reply(postId) {
if (!document.getElementById("reply" + postId)) {
// Generate HTML
var html = "<div id='reply" + postId + "'>";
html += "<textarea cols='70' rows='8' style='margin-bottom: 10px'></textarea><br/>";
html += "<span style='margin-bottom: 30px'>";
html += "<input type='button' value='Submit' />";
html += "<input class='cancelButton' type='button' value='Cancel' />";
html += "</span>";
html += "</div>";
// Insert into DOM
$("#root" + postId).after(html);
// Install event handlers
$("#root .cancelButton").bind("click", function() {
$("#reply" + postId).remove();
});
}
}
Using the DOM is methods directly is specifically discouraged by jQuery since it's so slow.
Update: As Chris says, move those styles to a CSS file to further tidy this up.
For such things I always use EJS.
http://embeddedjs.com/
Remove the angle brackets from your jQuery.
$( ".cancel" ).live( 'click', function() { $( this ).remove(); });
function reply( postId ) {
if ( $( "#reply" + postId ).size() == 0 ) {
var context = { postId: postId };
$( "#root" + postId ).after(new EJS({ url: '/template.ejs' }).render( context ));
}
}
Put them in a template with all their pointy little friends.
<div id="reply<%= postId %>">
<textarea cols="70" rows="8" class="reply_editor"></textarea>
<br>
<span class="ok_cancel">
<input type="button" value="Submit">
<input type="button" value="Cancel" class="cancel">
</span>
</div>
Inline styles are the devil's handiwork.
.reply_editor {
margin-bottom: 10px
}
.ok_cancel {
margin-bottom: 30px;
}
For extra legibility, don't attach handlers in your HTML. Attach them using jQuery.
Move the style stuff to a CSS file.
Remove the onclick event handler, replace it with a jQuery live.
Wrap the elementId in a variable.
$(".cancelButton").live("click", function(){$(this).remove();});
function Reply(postId) {
var elementId = "reply" + postId;
if (!document.getElementById(elementId )) {
var element = $("#" + elementId).after("<div id='" + elementId + "'><textarea cols='70' rows='8' ></textarea><br/><span ><input type='button' value='Submit' /><input type='button' value='Cancel' class='cancelButton'/></span></div>");
}
}