I'm using AJAX to add more articles to a list of articles when you press a button. So my AJAX call returns data that includes a title, author and 1 to 3 images associated with the article. Below is the code I'm using to output it, but it feels VERY clunky.
What are the best practices for printing out HTML with JavaScript/jQuery in a scenario like this where I need to add many new tags with new information? Thanks for the help!
Also, I know some of the code isn't super well written because it's a first draft just to make stuff work, so please only answer this question with regards to printing out the HTML or things that will make printing the HTML easier
$j.getJSON(ajaxurl, {action: 'load_articles', issues: $issues}, function(data) {
if (data.message != null) {
alert(data.message);
return
}
list = $j('.all-articles ul');
for (i in data.articles) {
article = data.articles[i];
//Hides articles already on page
if ($j("#" + article.id).size() === 0) {
list.append('<li class="article-preview" id="' + article.id + '">' +
'<h3 class="article-headline">' + article.title + '</h3>' +
'</li>');
current = $j("#" + article.id)
current.append('<p class="authors"></p>');
authors = $j("#" + article.id + " .authors")
for (a in article.authors) {
authors.append(article.authors[a].data.display_name + " ");
}
current.append('<div class="images"></div>');
images = $j("#" + article.id + " .images")
for (i in article.image) {
text = "<div class='image-expand-container'>";
if (i == 0) {
text += ('<img id="' + article.image[i].id + '"class="selected" src="' + article.image[i].medium + '"></img>');
}
else {
text += ('<img id="' + article.image[i].id + '" src="' + article.image[i].medium + '"></img>');
}
text += '<div class="dashicons dashicons-editor-expand"></div></div>';
images.append(text);
}
}
}
There are a few approaches you can take.
As you're doing here, you can return data from your ajax call (e.g. as JSON) and then use a javascript function to generate the corresponding HTML by building strings. This, as you're finding, is often messy.
You can generate the actual HTML on the server side, and have the ajax call return an HTML fragment, which you insert into your DOM. This has the advantage that, if some of your HTML is loading when the page loads, and some is loading via ajax, you can use the same approach (PHP, XSLT, ASP.NET Razor, any kind of server-side templating) to generate all of the HTML.
You can use a javascript templating framework to turn your JSON data into HTML. If all of your HTML is being generated via javascript (e.g. in a single-page application) this may be your best bet.
Related
I configured action cable, now I would like to use the following js function
$('.scroll-bar').scrollTop(row);
to scroll down the chat after submitting a message
So I tried to include the previous code in both app/assets/channels/messages.js and app/assets/javascripts/room.js.
The problem is until after I execute app/assets/channels/messages.js the html does not have then new <p></p> tag appended.
App.messages = App.cable.subscriptions.create('MessagesChannel', {
received: function(data) {
$("#messages").removeClass('hidden')
return $('#messages').append(this.renderMessage(data));
},
renderMessage: function(data) {
return "<p> <b>" + data.user + ": </b>" + data.message + "</p>";
}
});
This are my chat messages, I can not run .scrollTop(row) on a row that does not still exist.
I tested and the <p> tags are added after messages.js.
I found a temporary solution to solve this, by commenting return from return $('#messages').append(this.renderMessage(data)); and calling after the .scrollTop(row) method. The solution works, but this way only the html is appended to the page without <p> tags.. Somehow renderMessage is not working properly.
I am available for any info
Thanks a lot
Fabrizio Bertoglio
This is my temporary solution, not working correctly, because like this I will not append a <p> tag but just the text.
Basically like this the I am just appending the html without
"<p> <b>" + data.user + ": </b>" + data.message + "</p>"
You can see from the picture below that the message is not inside <p> tags.
This is what I have done, I commented the return to execute the .scrollTop() function after $('#messages').append(this.renderMessage(data));
app/assets/channels/messages.js
App.messages = App.cable.subscriptions.create('MessagesChannel', {
received: function(data) {
$("#messages").removeClass('hidden');
$('#messages').append(this.renderMessage(data));
height = $('.scroll-bar')[0].scrollHeight;
$('.scroll-bar').scrollTop(height);
/*return $('#messages').append(this.renderMessage(data));*/
},
renderMessage: function(data) {
return "<p> <b>" + data.user + ": </b>" + data.message + "</p>";
}
});
I think the solution is hear, from this post I followed to implement action cable, I don't understand who is directly calling the received: function(data) {}
is it the callback method subscribed inside messages_channel.rb?
class MessagesChannel < ApplicationCable::Channel
def subscribed
stream_from 'messages'
end
end
I don't have a clear idea how this callback method is calling the other method and how is the application flow.
Heroku Action Cable
I use WinJS in my application and try to print some content. Made my printer class according to this tutorial https://dzone.com/articles/windows-8-print-contract-%E2%80%93.
function registerForPrintContract(participiantData) {
var printManager = Windows.Graphics.Printing.PrintManager.getForCurrentView();
printManager.addEventListener("printtaskrequested", onPrintTaskRequested, false);
}
function onPrintTaskRequested(printEvent) {
var printTask = printEvent.request.createPrintTask("Print Example", function (args) {
printCurrentPage(args);
printTask.oncompleted = onPrintTaskCompleted;
});
}
function printCurrentPage(args) {
var docHtml = document.createDocumentFragment();
docHtml.appendChild(createDocumentContent());
args.setSource(MSApp.getHtmlPrintDocumentSource(docHtml));
}
function createDocumentContent() {
var container = document.createElement("div");
container.innerHTML = "<h2>" + firstname + " " + lastname + "</h2>" +
"<h4>" + emailaddress1 + "<h4>";
return container;
}
function showPrintUI() {
Windows.Graphics.Printing.PrintManager.showPrintUIAsync();
}
My problem is that I do not know how to forward some object data to createDocumentContent() function. In this example I put firstname, lastname and email. Those data I cannot get from html page I need to send them on print button click.
All examples I saw are about printing current page or making new content from data which we can get from HTML page by querying DOM, no example where I can send custom object.
What is the best way to do this ?
My problem is that I do not know how to forward some object data to createDocumentContent() function. In this example I put firstname, lastname and email. Those data I cannot get from html page I need to send them on print button click.
Do you mean you want to put the html output of "<h2>"+firstname + " " +lastname+"</h2>"+"<h4>" + emailaddress1 + "<h4>" to your print page?
The behavior of innerHTML has changed in Windows Store App Development.
see HTML and DOM API changes list innerHTML section:
Content is filtered as through it was processed by the toStaticHTML method
But WinJS offers a method that you can utilize to inject HTML.
Here is the link to documentation of this method: WinJS.Utilities.insertAdjacentHTML
Here is a code snippet that shows a simple use this method:
function createDocumentContent() {
var obj = {
firstname: "winffee",
lastname: "xia",
emailaddress1:"test#126.com"
}
var htmlString = "<h2>" + obj.firstname + " " + obj.lastname + "</h2>" +
"<h4>" + obj.emailaddress1 + "<h4>";
var container = document.createElement("div");
WinJS.Utilities.insertAdjacentHTML(container, "beforeend", htmlString);
return container;
}
I want to create something like Facebook wall. Currently I am getting the data in a json format and displaying using jQuery $each and then appending it to the main div. I am looking for an alternative way of doing this.
The problem in the current code is that i cannot use the div class to call any method like on.click . The on.click method need to be inside the $each to be get called and it gets called the number of object present in data.
And if i want to update the wall then i need to update the data and has to refresh the whole structure. Is there any other way by which i can add the new post to the wall without rebuilding the structure.
$.each(data, function () {
var status_id = this['Id'];
var like_id = "like" + status_id;
var commennt_id = "commnet-tem" + status_id;
var likes = 0;
$("<div class=\"post-indi\" id=\"post-item" + status_id + "\">" +
"<div class=\"post-content\">" +
" <div class=\"status-profile\" >" +
"<img src="">" +
"</div>" +
"<div class=\"content\">" + this['status'] + "</div>" +
"</div>" +
"<div class=\"commentbox-info\">" +
"<a id=\""+like_id+"\" href=\"#\" class=\"postddlike\">Like</a><img </div></div>").appendTo("div.post");
I've been developing a web game, with jquery doing some of the work. It was on a server, but I've moved it back to my laptop. Everything seems to work fine, except the most important function, which imports the contents of an html file.
$(".ReportList a").live('click', function(){
var getreportname = $(this).text();
$("#scroller").append("<span>The reportname is " + getreportname + "</span>");
var usersreport = "ReportList_" + User + "";
jQuery.get('Reports/' + getreportname + '.html', function (data) {
$("#" + usersreport).html(data);
$("#" + usersreport + " span").addClass("Py" + User);
updateCount();
});
});
Not sure why it stopped working. Would appreciate any insight.
I didn't need the .get() method to do what I wanted, .html() was good enough if I re-formulated the script.
I'm trying to get the last 50 tweets using a certain hash tag, on a mobile device using PhoneGap (0.9.6) and jQuery (1.6.1). Here's my code:
function getTweets(hash, numOfResults) {
var uri = "http://search.twitter.com/search.json?q=" + escape(hash) + "&callback=?&rpp=" + numOfResults;
console.log("uri: " + uri);
$.getJSON(uri, function(data) {
var items = [];
if(data.results.length > 0) {
console.log("got " + data.results.length + " results");
$.each(data.results, function(key, val) {
var item = "<li>";
item += "<img width='48px' height='48px' src='" + val.profile_image_url + "' />";
item += "<div class='tweet'><span class='author'>" + val.from_user + "</span>";
item += "<span class='tweettext'>" + val.text + "</span>";
item += "</div>";
item += "</li>";
items.push(item);
});
}
else {
console.log("no results found for " + hash);
items.push("<li>No Tweets about " + hash + " yet</li>");
}
$("#tweetresults").html($('<ul />', {html: items.join('')}));
});
}
This code works great in a browser, and for a while worked in the iPhone simulator. Now it's not working on either the iPhone or Android simulator. I do not see any of the console logs and it still works in a browser.
What am I doing wrong? If it's not possible to call getJson() on a mobile device using PhoneGap, what is my alternative (hopefully without resorting to native code - that would beat the purpose).
Bonus: how can I debug this on a mobile simulator? In a browser I use the dev tools or Firebug, but in the simulators, as mentioned, I don't even get the log messages.
As always, thanks for your time,
Guy
Update:
As #Greg intuited, the function wasn't called at all. Here's what I found and how I bypassed it:
I have this <a> element in the HTML Get tweets
Then I have this code in the $(document).ready() function:
$("#getTweets").click(function() {
var hash = "#bla";
getTweets(hash, 50);
});
That didn't call the function. But once I changed the code to:
function gt() {
var hash = "#bla";
getTweets(hash, 50);
}
and my HTML to:
Get Tweets
it now works and calls Twitter as intended. I have no idea what's screwed up with that particular click() binding, but I ran into similar issues with PhoneGap before. Any ideas are appreciated.
Considering that (a) there isn't much that could go wrong with the first line of your function and (b) the second line is a log command, then it would seem that the function isn't being called at all. You'll have to investigate the other code in your app.
Or are you saying that you don't have a way to read logged messages on your mobile devices?