I've been tweaking this and that and the other in an attempt to get the "Stop running this script?" error to go away in IE7 - the browser all users are required to use at this time :P I've tried several improvement attempts; all of them have caused the script to stop working, instead of running long. I've tried using setTimeout(), with no luck. It's possible I didn't do it correctly. Can anyone suggest ways to improve this to make it more efficient (and get that dang long running script message to go away)?
Here's the code:
The HTML:
<div class="changeView" style="float:right;">Show All...</div>
<div id="accordion" style="width: 99%;">
<% foreach (var obj in Model.Objects) { %>
<h3><span class="title"><%:obj.Id%></span><span class="status" style="font-size:75%"> - <%:obj.Status%></span></h3>
<div id="<%:obj.Id %>">
<div class="loading"><img src="<%=Url.Content("~/Content/Images/ajaxLoader.gif") %>" alt="loading..." /></div>
</div>
<% } %>
</div>
Then we have an onclick function to start it off...
$(function () {
$(".changeView").click(function () {
var divText = $(this).html();
var src = '<%=Url.Content("~/Content/Images/ajax-loader.gif")%>';
if (divText == "Show All...") {
$(this).html("Show Filtered...");
$('#accordion').accordion('destroy');
$('#accordion').empty();
$('#accordion').addClass("loading");
$('#accordion').append('Loading Information...<img src="' + src + '" alt="loading..." />');
changePartialView("all");
}
else {
$(this).html("Show All...");
$('#accordion').accordion('destroy');
$('#accordion').empty();
$('#accordion').addClass("loading");
$('#accordion').append('Loading Information...<img src="' + src + '" alt="loading..." />');
changePartialView("filter");
}
});
});
Next the changeView function is called:
//change view and reinit accordion
function changePartialView(viewType) {
$.ajax({
type: "POST",
url: "<%:Model.BaseUrl%>" + "ToggleView",
data: "Type=<%:Model.Target%>&Id=<%:Model.Id%>&view=" + viewType,
success: function (result) {
$('#accordion').empty();
$('#accordion').removeClass();
for (var index = 0; index < result.Html.length; index++) {
$('#accordion').append(result.Html[index]);
}
var $acc = $("#accordion").accordion({
collapsible: true,
active: false,
autoHeight: false,
change: function (event, ui) {
var index = $acc.accordion("option", "active");
if (index >= 0) {
var clickedId = ui.newHeader.find("a").find(".title").text();
getRequirements(clickedId);
}
else {
// all panels are closed
}
}
});
},
error: function (xhr, err) {
alert("readyState: " + xhr.readyState + "\nstatus: " + xhr.status);
alert("responseText: " + xhr.responseText);
alert("Error in ajax: " + result);
}
});
}
Note: The result.Html returns a generic List of formatted HTML, one for each panel of the accordion. With the exception of the long running script error message, everyone works pretty sweet.
Clarification of returned value: The result.Html consists of about 200-250 instances of these strings:
"<h3><a href=\"#\"><span class=\"title\">" + obj.Id +
"</span><span class=\"status\" style=\"font-size:75%\"> - " + obj.Status + count +
"</span></a></h3><div id=\"" + obj.Id + "\"><div class=\"loading\"><img src=\"" +
Url.Content("~/Content/Images/ajaxLoader.gif") + "\" alt=\"loading...\" /></div></div>")
for (var index = 0; index < result.Html.length; index++) {
$('#accordion').append(result.Html[index]);
}
Appending a lot of nodes one-at-a-time into the DOM is slow, one way you might be able to speed this up is to insert them all into an unattached node and then move them all at once when you're done:
var holder = $('<div></div>');
for (var index = 0; index < result.Html.length; index++) {
holder.append(result.Html[index]);
}
$('#accordion').append(holder.children());
Change the server to return data instead of lots of HTML. Use a client-side templating solution.
Then, once you have an array, you can just update the display asynchronously (like with the setTimeout you mentioned)
You only have two dynamic things in that big HTML string, pretty wasteful.
Or return less items?
Related
My webpage is receiving through AJAX GET requests Arrays with strings, and a Boolean.
The objects within the array are displayed subsequently to shape a chat app, the received array represents messages to display in a chatbox. However, some of the messages have media in them.
Therefore, to recognize such message with image source in them, I added a Boolean Value (media=True : There is an image source).
With my current code, all arrays are testing their source in an empty <img src""> which creates a real mess on the chat box with unknown images. I need to be able to generate with JS an HTML image when an Object has a media = True with a source of 'mediasrc'.
AJAX Array in details
HTML:
<div id="display"></div>
JS:
<script>
$(document).ready(function() {
setInterval(function() {
$.ajax({
type: 'GET',
url: "/checkview",
success: function go(response) {
console.log(response);
$("#display").empty();
for (var model of response.models_to_return) {
var temp = "<div class='container darker'><b>" +
model.user_id + "</b><p>" +
model.room + "</p><span class='time-left'>" +
model.datetime + "</span><img src=../static/" +
model.mediasrc + ".png></div>";
$("#display").append(temp);
}
},
error: function(response) {
//alert('An error occured')
}
});
}, 1000);
})
</script>
By the way, this code works fine, but it's literally brute forcing all messages trying to fill an img:
while this is something that front-end frameworks handle particularly well, a common convention would be to split your template HTML. For example:
for (var model of response.models_to_return) {
var temp = "<div class='container darker'>"
+ "<b>" + model.user_id + "</b>"
+ "<p>" + model.room + "</p>"
+ "<span class='time-left'>" + model.datetime + "</span>";
if (model.media) {
//add img to template, could also check model.mediasrc != null
temp += "<img src=../static/" + model.mediasrc + ".png>"
}
temp += "</div>";
$("#display").append(temp);
}
If you want to write code up to the latest conventions, replace double quotes with back ticks, and reference variables with ${var_name}.
For example:
+ "<b>" + model.user_id + "</b>"
becomes:
+ `<b>${model.user_id}</b>`
Not 100% sure I understand the question, but you could create a utility function that takes the model and returns either the <img> markup or an empty string depending on whether model.mediasrc is present (or whatever condition is appropriate for your needs).
This probably isn't the exact implementation you need, but it demonstrates the pattern:
function imgMarkup (model) {
if (model.mediasrc) {
return `<img src="${model.mediasrc}" />`
}
return '';
}
for (var model of response.models_to_return) {
const temp=`
<div class='container darker'>
<b>${model.user_id}</b>
<p>${model.room}</p>
<span class='time-left'>${model.datetime}</span>
${imgMarkup(model)}
</div>`;
$("#display").append(temp);
}
Trying to loop through json received from wikipedia api using .each(), but it returns undefined on everything. What have I missed?
Here is codepen: https://codepen.io/ekilja01/pen/pRerpb
Here is my HTML:
<script src="https://use.fontawesome.com/43f8201759.js">
</script>
<body>
<h2 class="headertext">WIKIPEDIA <br> VIEWER </h2>
<div class="row">
<div class="col-10-md">
<input class="searchRequest blink_me" id="cursor" type="text" placeholder="__"></input>
</div>
<div class="searchIcon col-2-md"> </div>
</div>
<div class="results">
</div>
</body>
Here is jQuery:
$(document).ready(function() {
var icon = "<i class='fa fa-search fa-2x'></i>";
$('#cursor').on("keydown", function() {
$(this).removeClass("blink_me");
var searchIcon = $(".searchIcon");
searchIcon.empty();
if ($(".searchRequest").val().length > 0) {
searchIcon.append(icon);
}
searchIcon.on("click", function() {
console.log("clicked!");
var search = $(".searchRequest").val();
var url = "https://en.wikipedia.org/w/api.php?action=opensearch&format=json&search=" + search + "&format=json&callback=?";
$.ajax({
dataType: "jsonp",
url: url,
success: function(data) {
$("ul").empty();
$.each(data[1], function(value, index) {
$(".results").append("<ul><li><h3>" + data[1][index] + "</h3><p>" + data[2][index] + " Read More...</p></li></ul>");
});
searchIcon.empty();
}
});
});
});
});
in $.each(data[1], function(value, index) you've to switch value to index and viceversa like this $.each(data[1], function(index, value)
For reference: jQuery.each()
I have gone through your code. Please change
$.each(data[1], function(value, index) to
$.each(data[1], function(index, value)
This is a bit of a crude way of going about this but one way I verify that the information is what it should be is to iterate with a nested for loop.
It may not solve the immediate problem, but its a way to go to understand how this thing is working.
for(var i = 0; i < data.length; i++)
{
///alert(data[i]); //See what data you're passing to WIKIPEDIA's API
for(var j = 0; j < data[i].length; j++)
{
//See what data WIKIPEDIA's API is passing to you
//From here, you can determin which value (j) to us (e.g. j = 0 is the Title)
//Once you hav that, you can use it to append to you 'results' class
alert('i = ' + i + '| j = ' + j);
alert('data = ' + data[i][j]);
///////////
//$(".results").append("<ul><li><h3>" + data[i][j] + "</h3><p>"
//+ data[i][j] + "<a href=\"" + data[i][j]
//+ "\"> Read More...</a></p></li></ul>");
///////////
}
While this is not a fix for your problem (fixed by Roberto Russo), there is something else going on that's probably not intended: you register searchIcon.on("click") callback inside $('#cursor').on("keydown") callback. What this means is that every time keydown event fires on the $(#cursor) element, a new listener will be added to searchIcon.on("click"). That's why you see "clicked!" printed multiple times for just one click. Also, if you check the network log, you'll see multiple requests sent to the wiki api for the same reason.
I'd suggest moving searchIcon.on("click") outside $('#cursor').on("keydown").
You need to swap value and index to this:
$.each(data[1], function(index, value)
Make sure whenever you call $.each() function, you cannot change the order of the arguments.
Example : $.each(arryName, function(index, value)
index = The index associates with arryName
value = The value associates with the index
I'm trying to find all divs that have been created from my click event and split them into another div (.wrapAll) on a count of 3. I can't seem to get anything back when i console.log the vars length. I know this works when I do that same process on the html thats been statically typed. Below is my code and thank you fo the thoughts!
jQuery(document).ready(function($) {
// load default twitch channels
$.getJSON('https://api.twitch.tv/kraken/streams/freecodecamp?callback=?', function(data) {
//console.log(data);
});
// Bind 'Enter' to click event
$(document).bind('keypress', function(e) {
if (e.keyCode == 13) {
$('#search').trigger('click');
}
});
// manually search for games
$('#search').on("click", function() {
// clear previous results and get search term
$('#results').html('');
search = $('#searchTerm').val();
// begin API call
$.getJSON( "https://api.twitch.tv/kraken/search/streams?q=" + search + "", function(data2) {
// console.log(data2.streams.length);
data2.streams.forEach(function(entry) {
//console.log(entry._links);
var streamURL = entry.channel.url;
url = entry.preview.medium;
$('#results').append('<div class="searchResults"><img class="games" src=' + url + '/><p id="title"> Game: ' + entry.channel.game + '<br> Viewers: ' + entry.viewers +'<br> Is Mature: ' + entry.channel.mature + '<br> Status: ' + entry.channel.status + ' </p></div><hr>');
});
});
// Get 3 divs and slice into one div to style ** problem child **
var a = $('div[id^=searchResu]').find('div');
console.log(a.length);
for( var i = 0; i < a.length; i+=3 ) {
a.slice(i, i+3).wrapAll('<div class="slide"></div>');
}
});
});
Check out this plunker here. I believe this does what your looking for.
<!DOCTYPE html>
<html>
<head>
<script data-require="jquery#2.1.4" data-semver="2.1.4" src="https://code.jquery.com/jquery-2.1.4.js"></script>
<script src="https://cdn.jsdelivr.net/lodash/4.13.1/lodash.min.js"></script>
<script>
jQuery(document).ready(function($) {
function appendHtmlContent(resultHtmlContent) {
resultHtmlContent = '<div class="slide">' + resultHtmlContent + '</div>';
$('#results').append(resultHtmlContent);
}
function processSvcResponse(data2) {
var count = 0,
searchResultContents = '',
$div = $("<div>", { class: "searchResults"});
data2.streams.forEach(function(entry) {
var streamURL = entry.channel.url;
url = entry.preview.medium;
searchResultContents += '<div class="searchResults"><a href="' + streamURL
+ '" target="_blank"><img class="games" src=' + url + '/><p id="title"> Game: ' + entry.channel.game
+ '<br> Viewers: ' + entry.viewers + '<br> Is Mature: ' + entry.channel.mature
+ '<br> Status: ' + entry.channel.status + ' </p></a></div><hr>';
count++;
if(count === 3) {
appendHtmlContent(searchResultContents);
searchResultContents = '';
count = 0;
}
});
// more results that have not been appended?
if(searchResultContents) {
appendHtmlContent(searchResultContents);
}
}
// load default twitch channels
$.getJSON('https://api.twitch.tv/kraken/streams/freecodecamp?callback=?', function(data) {});
// Bind 'Enter' to click event
$(document).bind('keypress', function(e) {
if (e.keyCode == 13) {
$('#search').trigger('click');
}
});
// manually search for games
$('#search').on("click", function() {
// clear previous results and get search term
$('#results').html('');
search = $('#searchTerm').val();
// begin API call
$.getJSON("https://api.twitch.tv/kraken/search/streams?q=" + search, processSvcResponse);
});
});
</script>
</head>
<body>
<input id="searchTerm" type="text" />
<button id="search" type="button">Search</button>
<div id="results"></div>
</body>
</html>
If I understand correctly you are wanting to iterate over the results and for every third one wrap it inside a div with class "slider". As mentioned in the comments by #charlietfl in order to query newly created DOM elements using jQuery you have to query them after they are created. In the call to jQuery.getJSON the second argument accepts a callback function. The signature is jQuery.getJSON(url, someCallbackFunction). In order to make your code a bit more readable I moved "function(data2)" up and named it processSvcResponse. Inside processSvcResponse I build up an HTML string from the results and track how many results are processed by using a counter variable. Once the counter reaches 3 I append the contents to the results div and reset the counter. This solution does not "find" the divs and slice/wrapAll as you were intending to do originally, however, I believe this still accomplishes your goal.
As #charlietfl said, you'll need to place the code that wraps your divs in the callback for getJSON. Your click event listener would look something like this then:
$('#search').on("click", function() {
// clear previous results and get search term
$('#results').html('');
search = $('#searchTerm').val();
// begin API call
$.getJSON( "https://api.twitch.tv/kraken/search/streams?q=" + search + "", function(data2) {
// console.log(data2.streams.length);
data2.streams.forEach(function(entry) {
//console.log(entry._links);
var streamURL = entry.channel.url;
url = entry.preview.medium;
$('#results').append('<div class="searchResults"><img class="games" src=' + url + '/><p id="title"> Game: ' + entry.channel.game + '<br> Viewers: ' + entry.viewers +'<br> Is Mature: ' + entry.channel.mature + '<br> Status: ' + entry.channel.status + ' </p></div><hr>');
});
// Get 3 divs and slice into one div to style ** problem child **
var a = $('div[id^=searchResu]').find('div');
console.log(a.length);
for( var i = 0; i < a.length; i+=3 ) {
a.slice(i, i+3).wrapAll('<div class="slide"></div>');
}
});
});
I'm trying to build a little app where the user enters a store name which will become the alt text to an image and the URL of their store which will become a h ref, which will then generate some copy and paste code to use on their website.
The problem I have is that when trying to use vanilla JavaScript to read the value of the store name nothing is showing.
Please see my fiddle:
http://jsfiddle.net/willwebdesigner/gVCcm/
$(document).ready(function() {
// Creates a method and prototype for the Array for splicing up words
Array.prototype.removeByValue = function(val) {
for(var i=0; i<this.length; i++) {
if(this[i] == val) {
this.splice(i, 1);
break;
}
}
}
var myStore = {
storeName: document.getElementById("storeName").value,
Url: document.getElementById("yourURL"),
instructions: "<p>Please copy the code above and paste it into your webpage to display the shop4support logo and a link to your store.</p>",
blackLogo: function() {
return "<img src="https://www.shop4support.com/Resources/home/information/InformationForProviders/Availables4s-bk.jpg" alt="" + this.storeName + " is available on shop4support" />";
}
}
$("#urlForm").submit(function(e) {
// Clear output form first
$(output).html(' ');
e.preventDefault();
// Create an array for conditional statements
var address = [];
address = $(myStore.Url).val().split("www");
// Need to put a conditional in here to detect if https://
if(address[0] === "https://") {
$(output)
.slideDown()
.prepend("<a href=""+ $(myStore.Url).val() + "">" + myStore.blackLogo() + "</a> ")
.append(myStore.instructions);
} else if(address[0] === "http://") {
// Remove the http part off the URL
var removeHttp = address;
removeHttp.removeByValue('http://');
$(output)
.slideDown()
.prepend("<a href="https://www" + removeHttp + "">" + myStore.blackLogo() + "</a> ")
.append(myStore.instructions);
} else {
$(output)
.slideDown()
.prepend("<a href="https://"+ $(myStore.Url).val() + "">" + myStore.blackLogo() + "</a> ")
.append(myStore.instructions);
}
});
});
Thanks Will
The moment you are initializing the myStore object the values aren't filled in yet. You will have to do this on submit.
So you can move the var myStore = {} into the submit callback:
http://jsfiddle.net/gVCcm/1/
update your code as :
$("#urlForm").submit(function(e) {
myStore.storeName= (document.getElementById("storeName").value);
/* The rest of your code */
}
Initialize your myStore variable in:
$("#urlForm").submit(function(e) {
var myStore = {}
});
It's probably something stupid I've done but I can't work it out. Heres the function:
function loadguides(softwareid){
var $softwareid = $('#'+softwareid);
$softwareid.load("devices/" + phoneid + firmwareid + ".html " + "#" + softwareid);
}
loadguides('ms1');
loadguides('ms2');
loadguides('ms3');
loadguides('ms4');
loadguides('ms5');
loadguides('ps1');
loadguides('ps2');
loadguides('ps3');
If you need more of the code just ask which parts. To give a comparison, this works:
loadtab('mac');
loadtab('pc');
loadtab('linux');
loadtab('safari');
loadtab('redsn0wM');
loadtab('redsn0wP');
loadtab('pwnagetool');
loadtab('limera1n');
loadtab('greenpois0n');
loadtab('spiritM');
loadtab('spiritP');
loadtab('sn0wbreeze');
function loadtab(tab){
var $tab = $('#'+tab);
$tab.hide();
$tab.load("devices/" + phoneid + firmwareid + ".html " + "#" + tab,
function(){
var tabcontent = $("#"+tab).text();
if (tabcontent == "1"){
$tab.show();
}
else{
$tab.hide();
}
});
}
It's not clear on what the problem is. Are you getting an error? Does it just simply not load?
It does not appear that you have phoneid or firmwareid JS variables defined.
BTW, you can post your full code on: http://jsfiddle.net
I would install/use Firebug and look at the console to determine if there is a javascript or network error.
should your function declaration go above where you are calling it? For example:
function loadtab(tab){
var $tab = $('#'+tab);
$tab.hide();
$tab.load("devices/" + phoneid + firmwareid + ".html " + "#" + tab,
function(){
var tabcontent = $("#"+tab).text();
if (tabcontent == "1"){
$tab.show();
}
else{
$tab.hide();
}
});
}
loadtab('mac');
loadtab('pc');
loadtab('linux');
loadtab('safari');
loadtab('redsn0wM');
loadtab('redsn0wP');
loadtab('pwnagetool');
loadtab('limera1n');
loadtab('greenpois0n');
loadtab('spiritM');
loadtab('spiritP');
loadtab('sn0wbreeze');