I have a single DIV that can hold many different images based on user input. When the user is done configuring the application, the final output is the images that have been rendered (one-by-one) in the same DIV. To capture the image, I am using html2canvas. The problem is that once I start the loop to redraw the images as needed in the div and capture them, only the first image is actually captured each time.
To put it another way, it's as if the showShelf() function in the code below never executes.
var exportJSON;
var exportDeviceList;
var renderNumber;
function exportAll()
{
exportJSON = [];
exportDeviceList = [];
renderNumber = 0;
for (var i = 0; i < devices.length; i++)
{
var elements = devices[i].elements;
for (var j = 0; j < elements.length; j++)
{
exportDeviceList.push({site: devices[i].site, device: elements[j].id, name: elements[j].tid, config: elements[j].config});
}
}
renderNext();
}
function renderNext()
{
site = exportDeviceList[renderNumber].site;
device = exportDeviceList[renderNumber].device;
config = exportDeviceList[renderNumber].config;
showShelf(site,device,config);
html2canvas(document.getElementById("baseImage"), {allowTaint: true}).then(function (canvas)
{
exportJSON.push({tid: exportDeviceList[renderNumber].name, image: canvas.toDataURL("image/png")});
renderNumber++;
if (renderNumber < exportDeviceList.length)
{
renderNext();
}
});
}
I found my own answer: After performing the showShelf() function, I perform a setTimeout() function containing the actual html2canvas() call and the call to perform the next render.
Related
I am new to Ember and in my APP I need to add some operations depending on the JSON I get from the server.
This is currently my logic:
In the component.js
var foo = [];
didInsertElement() {
var data = this.get('content');
//then I do some transformations with data to obtain what I want and assign it to foo
data.forEach(function(option) {
list.push( JSON.parse(JSON.stringify(option)))
})
for(i = 0; i < list.length; i++) {
//some logic code with list
}
this.set('foo', someTransformationFromList);
for (i = 0; i < count; i++) {
this.get('content').push(jQuery.extend(true, {}, this.get('content')[0]));
}
for(i = 0; i < foo.length; i++) {
this.get('content')[i].set('string1', foo[i].text);
this.get('content')[i].set('id', foo[i].value);
}
}
So now the question is, I need to move this logic from didInsertElement to somewhere else so it gets executed every time I get my JSON no just the first time when the component is rendered. I have tried to use a serializer or a transform but I don't know if I can use any of them. Can you please give me any pointers about how to do this task?.
Thank you.
I am trying to render an html page that contains all of the posts that a user has received. Right now the issue I am having (shown under Way 1) is that when I call the function renderPosts after the web socket is received, only the first post in the array is rendered (the array has more than one post in it).
On the other hand, Way 2 in which I have no for loop and instead manually render each post works in that all four posts are rendered. But I need to be able to work with an arbitrary number of posts which is why I need to use the for loop.
I am using socket.io and javascript.
Way 1:
socket.on('postsToRender', function(arrayOfPostsToRender) {
renderPosts(arrayOfPostsToRender);
});
function renderPosts(arrayOfPostsToRender) {
for (var index = 0; index < arrayOfPostsToRender.length; index++) {
renderPost(arrayOfPostsToRender[index]);
}
}
function renderPost(postToRender) {
var feed = document.getElementById("feed");
var postContent = document.createTextNode(postToRender.content);
var post = document.createElement("div");
post.appendChild(postContent);
feed.appendChild(post);
}
Way 2:
socket.on('postsToRender', function(arrayOfPostsToRender) {
renderPost(arrayOfPostsToRender[0]);
renderPost(arrayOfPostsToRender[1]);
renderPost(arrayOfPostsToRender[2]);
renderPost(arrayOfPostsToRender[3]);
});
function renderPost(postToRender) {
var feed = document.getElementById("feed");
var postContent = document.createTextNode(postToRender.content);
var post = document.createElement("div");
post.appendChild(postContent);
feed.appendChild(post);
}
Try this:
function renderPosts(arrayOfPostsToRender) {
for (var index = 0; index < arrayOfPostsToRender.length; index++) {
(function(i){
renderPost(arrayOfPostsToRender[i]);
})(index);
}
}
I'm relatively new to javascript/jquery.
I am trying to run a nested for loop which dynamically creates HTML content which I then append into a table in my body. The first 'for' loop pulls data from Parse, and creates an html table row script, which I then append to a table in html body. The nested 'for' loop should run for each item in the first loop, and create a table row element directly below.
However, for some reason (and I see this when I debug), the first for loop completes before triggering the nested loop. Is there any obvious reason or syntax that is causing this?
Thanks in advance!
$(document).ready(function(){
var currentUser = Parse.User.current();
var htmlContent = "";
if (currentUser) {
console.log(currentUser.get("full_name"));
$("#user").html(currentUser.get("full_name"));
var QrUrl = Parse.Object.extend("qr_url");
var qr_query = new Parse.Query(QrUrl);
qr_query.equalTo("createdBy", currentUser);
qr_query.include("createdBy");
qr_query.ascending("createdAt")
qr_query.find({
success: function(qrid_results) {
for (var i = 0; i < qrid_results.length; i++) {
var qridentry = qrid_results[i];
htmlContent="<tr><td>"+qridentry.get("title")+"</td><td>"+"Created"+"</td><td>"+qridentry.createdAt+"</td><td>"+qridentry.get("createdBy").get("full_name")+"</td></tr>";
$('#trackingtable').append(htmlContent);
var QrLogger = Parse.Object.extend("qr_logger");
var qrlog_query = new Parse.Query(QrLogger);
qrlog_query.equalTo("qrid", qridentry);
qrlog_query.include("createdBy");
qrlog_query.include("qrid");
qrlog_query.find({
success: function(qrlog_results) {
for (var j = 0; j < qrlog_results.length; j++) {
var qrlogentry = qrlog_results[j];
try{
var user_id = obj.get("createdBy").get("full_name");
console.log(user_id);
}
catch(err){
user_id="Unknown Scanner";
}
var dated = qrlogentry.updatedAt;
htmlContent="<tr><td>"+qrlogentry.get("qrid").get("title")+"</td><td>"+"Scanned"+"</td><td>"+dated+"</td><td>"+user_id+"</td></tr>";
$('#trackingtable').append(htmlContent);
}
}
});
//$('#trackingtable').dataTable({ });
}
}
});
}
});
Here's a way to make things work with Promises such that they run in the order they would if find were synchronous:
qr_query.find().then(function(qrid_results) {
var promise = Parse.Promise.as();
for (var i = 0; i < qrid_results.length; i++) {
promise = promise.then(function() {
// Build qrlog_query...
return qrlog_query.find();
}).then(function(qrlog_results) {
for (var j = 0; j < qrlog_results.length; j++) {
// Do whatever synchronous work you want...
}
});
}
return promise;
});
```
For more info, Google for [javascript promises].
Your call to the find method surrounding your second for loop is actually deferring execution until whenever that second find completes. If you want the inner for loop to execute synchronously with the first for loop you'll need to structure your code so that either 1. Each deferred execution is chained to start in your desired order. 2. You move all the HTML edits into a separate function that only executes after all qrlog queries have been succefully executed, storing the intermediate results somewhere until you're ready to render your HTML.
I'm trying to control the background if it available or not. I see onerror using everywhere, but not for me. I have bg folder and background1.jpg to background4.jpg background pictures. For first 4 there is no problem. But background5.jpg not available in that folder. Onerror doesn't work. How can i do about that problem? Any ideas?
<script>
var background = document.createElement("img");
var positive=1;
var x=0;
for(var i=0; i<6; i++)
{
background.src = "bg/background"+i+".jpg"
background.onerror = "finisher()"
background.onload = function(){alert("Worked!");}
function finisher()
{
positive = 0;
}
if(positive = 1)
{
alert("Vuhhuu! ->"+x);
x++;
}
else
{
alert("Image not loaded!");
}
}
</script>
There are a bunch of things wrong with your code. First off, you can use a for loop like this and expect it to try each image:
for (var i=0; i<6; i++) {
background.src = "bg/background"+i+".jpg"
background.onerror = "finisher()"
background.onload = function(){alert("Worked!");}
}
That just won't do what you're trying to do. That will rapidly set each successive .src value without letting any of them actually load (asynchronously) to see if they succeed.
Second off, don't use a string for .onerror. Assign the function reference directly such as background.onerror = finisher;
Thirdly, you MUST assign onerror and onload handlers BEFORE you assign .src. Some browsers (IE raise your hand) will load the image immediately if your image is in the browser cache and if your onload handler is NOT already installed, you will simply miss that event.
If you're really trying to try each image and know which ones work, you will have to completely redesign the algorithm. The simple way would be to create 6 images, load all of them and then when the last one finishes, you can see which ones had an error and which ones loaded properly.
If you're just trying to find the first one that succeeds, then you can pursue a different approach. Please describe what you're actually trying to accomplish.
To see how many of the images load successfully, you can do this:
function testImages(callback) {
var imgs = [], img;
var success = [];
var loadCnt = 0;
var errorCnt = 0;
var numImages = 6;
function checkDone() {
if (loadCnt + errorCnt >= numImages) {
callback(success, loadCnt, errorCnt);
}
}
for (var i = 0; i < 6 i++) {
img = new Image();
(function(index) {
img.onload = function() {
++loadCnt;
success[index] = true;
checkDone(this);
};
)(i);
img.onerror = function() {
++errorCnt;
checkDone();
};
img.src = "bg/background" + i + ".jpg";
imgs.push(img);
success.push(false);
}
}
testImages(function(successArray, numSuccess, numError) {
// successArray numSuccess and numError here will tell you
// which images and how many loaded
});
Note, this is an asynchronous process because images load in the background. You won't know how many images loaded or which images loaded until the callback is called sometime later when all the images have finished.
Try to use try-catch method.
try{
background.src = "bg/background"+i+".jpg";
background.onload = function(){alert("Worked!");}
}catch(e){
console.log("Error!");
finisher();
}
As already mentioned, you've got a couple of other problems, but this is a slightly more concise way of expressing the same, with a few errors tidied up. You're still requesting a bunch of different images, however.
var background = document.createElement("img");
var positive = 1;
var x = 0;
background.onerror = function() {
positive = 0;
alert("Image not loaded!");
}
background.onload = function() {
alert("Vuhhuu! -> " + x);
x++;
}
for (var i = 0; i < 6; i++) {
background.src = "bg/background" + i + ".jpg";
}
Explanation: You don't need to bind your onerror and onload handlers every time you loop. Doing it once will be just fine.
Alright, I've been working on a userscript that redirects when a specific page is loaded.
This is what I have so far:
function blockThreadAccess() {
var TopicLink = "http://www.ex.com/Forum/Post.aspx?ID=";
var Topics = [ '57704768', '53496466', '65184688', '41182608', '54037954', '53952944', '8752587', '47171796', '59564382', '59564546', '2247451', '9772680', '5118578', '529641', '63028895', '22916333', '521121', '54646501', '36320226', '54337031' ];
for(var i = 0; i < Topics.length; i++) {
if(window.location.href == TopicLink + Topics[i]) {
// Execute Code
}
}
}
The function is called on the page load, but it doesn't seem execute the code.
What it's supposed to do is check to see if the user is on that specific page, and if he is then execute the code.
Say someone goes to this link - http://www.ex.com/Forum/Post.aspx?ID=54646501, it then redirects the use. I'm trying to make it efficient so I don't have to add a bunch of if statements.
try converting both to lower case before comparing
var loc = window.location.href.toLowerCase();
var topicLnk = TopicLink.toLowerCase();
for(var i = 0; i < Topics.length; i++) {
if(topicLnk + Topics[i] == loc) {
// Execute Code
}
}