Duplicate onClick events on LI element in iScroll - javascript

Here is my code.. When I am calling this function, iScroll() added duplicate events on LI element after change page.
function collectionOffen(asseID, imgsInFile) {
$("#thelist").empty();
// append image files into slider div..
for (var imgPageCnt = 0; imgPageCnt <= imgsInFile; imgPageCnt++) {
var html = "";
html += "<li id=" + imgPageCnt + ">";
html += "<img src='" + preThmb + "'>";
html += "</li>";
$("#thelist").append(html);
funcPreImg = function () {
previewImageBackside(asseID);
}
document.getElementById(imgPageCnt).addEventListener("click", funcPreImg);
}
$("#thelist").listview("refresh");
$.mobile.changePage("#collectionOfFiles", {
transition: "slide",
reverse: true
});
var myScroll = new iScroll('wrapper');
}
Tell me solution if any..

duplicated events are a common problem in jqm.
Try this (untestet braincode):
$(document).on('pageinit', function () {
$("#thelist").empty();
// append image files into slider div..
for (var imgPageCnt = 0; imgPageCnt <= imgsInFile; imgPageCnt++) {
var html = "";
html += "<li id='" + imgPageCnt + "' class='imgClass'>";
html += "<img src='" + preThmb + "'>";
html += "</li>";
$("#thelist").append(html);
}
//is 'asseID' defined in this context?
$(document).on('click', '.imgClass', function (e) {
if(e.handled !== true)
{
previewImageBackside(asseID);
e.handled = true;
}
});
$("#thelist").listview("refresh");
$.mobile.changePage("#collectionOfFiles", {
transition: "slide",
reverse: true
});
var myScroll = new iScroll('wrapper');
});
this should add your list elements only on initialization of the page.
also changed your javascript function into a nicer and performant jquerycall.
you also had a typo in "<li id='" + imgPageCnt + "'>", missing quotes

I found solution. Destroy iScroll object after rendering images.
Ex:-
var myScroll = new iScroll('wrapper');
myScroll.refresh();
myScroll.destroy();
take myScroll as static variable to destroy object.

Related

Can't addEventListener('click', ...) to a div created programmatically

I parse the result of XMLHttprequest() into a JSON object, then for each node of that object I create a div to store the informations.
Finally I add each div as innerHTML of a parent div.
Here the relevant part
xhr.onreadystatechange = function() {//Call a function when the state changes.
if(xhr.readyState == 4 && xhr.status == 200) {
var response = JSON.parse(xhr.responseText);
var html="";
var linksDiv = document.getElementById('links');
if (response.error != true){
for (var i=0; i< response.links.length; i++){
var l = response.links[i];
var curId = l.id;
var curLink = l.link;
var curCreated = l.created_at;
var curOrigin = l.origin;
html = "<div id=\"link"+curId+"\" >"+
"<label><b>Id </b></label><label>"+curId+"</label> </br>"+
"<label><b>Link </b></label><label>"+curLink+"</label> </br>"+
"<label><b>Created </b></label><label>"+curCreated+"</label> </br>"+
"<label><b>Origin </b></label><label>"+curOrigin+"</label> </br></br>"+
"</div>";
linksDiv.innerHTML += html;
var curDiv = document.getElementById('link'+curId);
console.log("curDiv is"+'link'+curId);
curDiv.addEventListener('click', function(){
curDiv.style.background="gray";
getLink(curId);
});
}
}
}
}
unfortunately
curDiv.addEventListener('click', function(){
curDiv.style.background="gray";
getLink(curId);
});
doesn't work.
I already tried to make sure that the div exist (the console.log("curDiv is"+'link'+curId); works just fine)
and even used different ways like curdDiv.onmouseover = function(){curDiv.style.background="gray";}
If i put curDiv.style.background="gray"; outside the addEventListener() every div's background gets correctly changed.
If i put onmouseover="this.style.background='gray';" as inline property of the div tag when i generate it, it works as well, but i don't want javascript in the html since I will transform this page in a Chrome Extension and javascript must be separated
Please don't get confused from the mouseover tries, I need onclick behavior, but was just testing different thing to see if they worked.
I looked for a long time on SO for an answer, as you can see from my tries, but couldn't find something that worked for me. Probably there is something that I don't get.
Ps.
Let me know if you need a sample JSON data to test the function.
I think you should use
html = document.createElement('div');
html.id = 'link' + curId;
html.innerHTML = "<label><b>Id </b></label><label>" + curId
+ "</label> </br><label><b>Link </b></label><label>" + curLink
+ "</label> </br><label><b>Created </b></label><label>" + curCreated
+ "</label> </br><label><b>Origin </b></label><label>" + curOrigin
+ "</label> </br></br>";
html.addEventListener('click', function(){
this.style.background="gray";
getLink(this.id);
});
linksDiv.appendChild(html);
instead of
html = "<div id=\"link"+curId+"\" >"+
"<label><b>Id </b></label><label>"+curId+"</label> </br>"+
"<label><b>Link </b></label><label>"+curLink+"</label> </br>"+
"<label><b>Created </b></label><label>"+curCreated+"</label> </br>"+
"<label><b>Origin </b></label><label>"+curOrigin+"</label> </br></br>"+
"</div>";
linksDiv.innerHTML += html;
var curDiv = document.getElementById('link'+curId);
console.log("curDiv is"+'link'+curId);
curDiv.addEventListener('click', function(){
curDiv.style.background="gray";
getLink(curId);
});
Check this working code. make delay so that event will attached to element.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script type="text/javascript">
function populateLink() {
var html = "";
var linksDiv = document.getElementById('links');
for (var i = 0; i < 10; i++) {
var l = 'l-' + i;
var curId = i;
var curLink = 'l.link-' + i;
var curCreated = 'l.created_at_' + 1;
var curOrigin = 'l.origin_' + i;
html = "<div id=\"link" + curId + "\" >" +
"<label><b>Id </b></label><label>" + curId + "</label> </br>" +
"<label><b>Link </b></label><label>" + curLink + "</label> </br>" +
"<label><b>Created </b></label><label>" + curCreated + "</label> </br>" +
"<label><b>Origin </b></label><label>" + curOrigin + "</label> </br></br>" +
"</div>";
linksDiv.innerHTML += html;
//var curDiv = document.getElementById('link' + curId)
//curDiv.addEventListener('click', function () {
// this.style.background = "gray";
// getLink(this.id);
//});
attachEvent(curId);
}
}
function attachEvent(curId) {
setTimeout(function () {
var curDiv = document.getElementById('link' + curId)
curDiv.addEventListener('click', function () {
this.style.background = "gray";
//getLink(this.id);
});
}, 100);
}
window.onload = populateLink;
</script>
</head>
<body>
<div id="links"></div>
</body>
</html>

Modifying innerHTML in nested get() jQuery

I'm currently using the jQuery get method to read a table in another page which has a list with files to download and links to others similar webpages.
$.get(filename_page2, function(response, status){
var data = $("<div>" + response + "</div>");
var target_element = data.find(target_element_type_page2 + '#' + target_element_id_page2)[0];
var container = document.getElementById(element_change_content_page1);
if (typeof target_element !== "undefined"){
var rows = target_element.rows;
for (var i = 1, n = rows.length; i < n; i++) {
var table = rows[i].cells[1].getElementsByTagName("TABLE")[0];
var isFolder = table.getAttribute("CType") == "Folder";
var elem = table.rows[0].cells[0];
var text = elem.innerText || elem.textContent;
var link = elem.getElementsByTagName("A")[0].getAttribute("href");
if (!isFolder) {
container.innerHTML += "<li class=\"mainfolderfile\">" + "<a class=\"filelink\" href=\"" + link + "\">" + text + "</a></li>";
} else {
container.innerHTML += "<li class=\"folderlist\">" + "<a class=\"folderlink\" onclick=\"open_submenu(this)\" href=\"#\">" + text + "</a><ul></ul></li>";
var elem_page1 = container.getElementsByTagName("li");
var container_page1 = elem_page1[elem_page1.length - 1].getElementsByTagName("ul")[0];
create_subfolder(container_page1, link);
}
}
} else {
container.innerHTML += "<li class=\"mainfolderfile\">" + "<a class=\"filelink\" href=\"" + "#" + "\">" + "Error..." + "</a></li>";
}
}, page2_datatype);
This is working fine, and all the folders and files are being listed. But when I try to do the same thing with the folders (calling the create_subfolder function) and create sublists with their subfolders and files, I'm getting a weird behavior.
function create_subfolder(container2, link1) {
$.get(link1, function(response, status){
var data = $("<div>" + response + "</div>");
var target_element = data.find("table" + "#" + "onetidDoclibViewTbl0")[0];
if (typeof target_element !== "undefined"){
var rows = target_element.rows;
for (var i = 1, n = rows.length; i < n; i++) {
var table = rows[i].cells[1].getElementsByTagName("TABLE")[0];
var elem = table.rows[0].cells[0];
var text = elem.innerText || elem.textContent;
var link2 = elem.getElementsByTagName("A")[0].getAttribute("href");
//nothing is changed in the webpage. The modifications in the html don't appear
container2.innerHTML += "<li>" + text + "</li>";
}
}
alert(container2.innerHTML); // Print the html with all the modifications
}, "html");
}
The second get(), inside the create_subfolder() function are not changing anything in the webpage, so no sublist is created. But, when I call the alert() function at the end of the get() function, it prints the code with all the modifications it should have made in the html at the second get callback. I believe the problem is related with the asynchronous behavior of the get function but I don't know exactly why. Any guess?

Javascript ID groupings

I'm looking to create an exception which creates 2 groupds based on their .php ID numbers.
I currently have a form that fills a table of images, and want to split them into groups using javascript.
currently the script looks like this:
var currentResults;
function init() {
getProducts();}
function getProducts() {
$.ajax({
url:"php/products.php",
dataType: "json",
data: { public: true },
success:function(result){
processResults(result);
}
});}
function processResults(results) {
currentResults = null;
if (!results && !results.products)
return;
currentResults = results.products;
for (var i = 0; i < results.products.length; i++) {
processResult(results.products[i]);}
$(".galleryitem").click(handleThumbnailClick);}
function processResult(result) {
var newDiv = '<div id="galleryitem' + result.id + '" class="galleryitem">';
newDiv += '<div class="imageHover" style="background: ' + result.color + '"> </div>';
newDiv += '<img class="galleryImage" src="' + encodeImagePath(result.thumbnail) + '" />';
if (result.artist)
newDiv += '<div class="imageArtist">' + result.artist + '</div>';
newDiv += '</div>';
$('#gallery').append(newDiv);}
function handleThumbnailClick(e) {
if (!e || !e.currentTarget || !e.currentTarget.id)
return;
var id = e.currentTarget.id.substring(11);
window.location = 'product.php?id=' + id;}
function encodeImagePath(path) {
return path.replace(/#/g, '%23');}
I am looking for some simple advice on how to split this into multiple div's based on the product's ID number to do sections of 6 images at a time with different header text.
please advise!! thanks much!
Not sure if I got your idea right but something like this should solve your problem (in case you have a "parent" property in the products JSON you're getting from the server):
function processResult(result) {
if (typeof(result.parent) !== 'undefined') { // see if the element has a parent
var newDiv = 'markup goes here'; // if some of the markup would be reused you can create a new function for this
$('#galleryitem' + result.parent).append(newDiv); // just make sure the parent is already there
} else {
var newDiv = '<div id="galleryitem' + result.id + '" class="galleryitem">'; // default behavior that you alreay had
// code skipped for brevity
$('#gallery').append(newDiv);
}
}
P.S. You should work on your code formatting -- it can be much easier to read if formatted well.

AngularJS - can´t execute methods with ng-click when markup is generated with a directive

I've created my paginator directive:
myApp.directive("paginator", function($timeout) {
return {
restrict: "E",
link: function (scope, element, attr) {
var totalProducts = scope.productsConfig.total,
MAX_PER_PAGE = +(scope.productsConfig.limit),
pagesQty = Math.ceil(totalProducts/MAX_PER_PAGE),
markup = "";
//Add initial markup ul open tag
markup += "<ul class='ch-pagination'>";
//Add the previous button if needed
if(scope.lastStatus.p > 1) {
//Then add the previous button
var previousPage = +(scope.lastStatus.p) - 1;
markup += "<li><a ng-click='goToPage(" + previousPage + ")'>Previous</a></li>";
}
//Add the elements
for (var i = 1; i <= pagesQty; i++) {
if(scope.lastStatus.p == i){
var activeClass = "class='ch-pagination-current'";
} else {
activeClass = "";
}
markup += "<li " + activeClass + "><a ng-click='goToPage(" + i + ")'>" + i + "</a></li>"
}
//Add the next element if any
if(scope.lastStatus.p < pagesQty) {
//Then add the previous button
var nextPage = +(scope.lastStatus.p) + 1;
markup += "<li><a ng-click='goToPage(" + nextPage + ")'>Next</a></li>";
}
//Close the paginator
markup += "</ul>";
//Inject the code into the wrapper
$(".inventory-paginator").html(markup);
}
}
});
Line where my method is injected (among others):
markup += "<li " + activeClass + "><a ng-click='goToPage(" + i + ")'>" + i + "</a></li>"
Then my method goToPage is called when clicking the generated markup. When using the paginator, trying to click some page button, nothing happens, ng-click never executes goToPage method, even when the generated markup is:
"ng-click='goToPage(2)'"
The method inside the main controller:
$scope.goToPage = function (intPage) {
var requestUrl = $scope.buildSearchRequestUrl(intPage);
console.log("goToPage requestUrl: " + requestUrl);
//Request the data, on success show the table again
$http.get(requestUrl)
.success(function (data) {
$scope.inventoryData = data;
}).error(function (data) {
if(window.console){
console.log("The article couldnt be paused");
}
});
}
I´m guessing that Im missing some linking, but can´t figure out where, or why.
Thanks so much in advance,
Guillermo
Have you tried to compile it? A directive should be compiled whenever you want to invoke it from HTML.
See http://docs.angularjs.org/guide/directive
As roland pointed out you must use the $compile service to compile the html and then append it directive element. Without the $compile step angular has no way to link the ng-click directives.
myApp.directive("paginator", function($timeout, $compile) {
return {
restrict: "E",
link: function (scope, element, attr) {
var totalProducts = scope.productsConfig.total,
MAX_PER_PAGE = +(scope.productsConfig.limit),
pagesQty = Math.ceil(totalProducts/MAX_PER_PAGE),
markup = "";
//Add initial markup ul open tag
markup += "<ul class='ch-pagination'>";
//Add the previous button if needed
if(scope.lastStatus.p > 1) {
//Then add the previous button
var previousPage = +(scope.lastStatus.p) - 1;
markup += "<li><a ng-click='goToPage(" + previousPage + ")'>Previous</a></li>";
}
//Add the elements
for (var i = 1; i <= pagesQty; i++) {
if(scope.lastStatus.p == i){
var activeClass = "class='ch-pagination-current'";
} else {
activeClass = "";
}
markup += "<li " + activeClass + "><a ng-click='goToPage(" + i + ")'>" + i + "</a> </li>"
}
//Add the next element if any
if(scope.lastStatus.p < pagesQty) {
//Then add the previous button
var nextPage = +(scope.lastStatus.p) + 1;
markup += "<li><a ng-click='goToPage(" + nextPage + ")'>Next</a></li>";
}
//Close the paginator
markup += "</ul>";
//append and compile code to element
element.append($compile(markup)(scope));
});

Elements added with appendTo() not immediately available

I'm having a problem with elements added with appendTo() not being immediately available in the DOM.
First, I'm reading some data from a JSON file and then appending some html to a div. Then I'm calling a random shuffler plugin to show one of the added divs at a time.
jsonUrl = "js/performers.json";
$.getJSON(jsonUrl, function(json) {
$.each(json.performers, function(i, performer) {
var html = '<div class="performer_mini">';
html += '<img src="' + performer.thumbnail + '" alt="' + performer.name + '" /><br />';
html += performer.name + '<br /></div>';
$(html).appendTo("div#performer_spotlight");
});
});
$("#performer_spotlight").randomShuffler(".performer_mini", 3000, 3000, 9000);
The random shuffler does the following:
(function($) {
$.fn.randomShuffler = function(shuffledElements, fadeInTime, fadeOutTime, timeout) {
fadeInTime = fadeInTime || 3000;
fadeOutTime = fadeOutTime || 3000;
timeout = timeout || 9000;
$(shuffledElements).hide();
var $old_element;
var $new_element;
var old_index = 0;
var new_index = 0;
function shuffleElement() {
$old_element = $new_element;
old_index = new_index;
while ($(shuffledElements).length > 0 && old_index == new_index) { // don't display the same element twice in a row
new_index = Math.floor(Math.random()*$(shuffledElements).length);
}
$new_element = $(shuffledElements + ":eq(" + new_index + ")");
if ($old_element != undefined) {
$old_element.fadeOut(fadeOutTime, function() {
$new_element.fadeIn(fadeInTime);
});
} else {
$new_element.fadeIn(fadeInTime);
}
setTimeout(shuffleElement, timeout);
}
$(this).show();
shuffleElement();
}
})(jQuery);
The first time the shuffleElement() function is called $(shuffledElements).length equals 0, so no element is displayed. On the next call to shuffleElement(), the elements added with appendTo() are available and one is selected at random as expected. Everything works correctly after that.
Is there some way to refresh the DOM or make these elements available to jQuery immediately after I add them with appendTo()? Any other suggestions for how to accomplish this?
When exactly do you call randomShuffler? You call this function after the AJAX-request succeeds? I have always believed that the element added by appendTo available immediately after the addition.
This code works very well for me:
<script language="javascript">
var test = "<div class=\"test\">1</div>";
$(test).appendTo("div#performer_spotlight");
$("div.test").html("<b>Hello</b>");
</script>
Yes, like #MeF Convi says you need to call the plugin only after the getJSON finishes:
$.getJSON(jsonUrl, function(json) {
$.each(json.performers, function(i, performer) {
var html = '<div class="performer_mini">';
html += '<img src="' + performer.thumbnail + '" alt="' + performer.name + '" /><br />';
html += performer.name + '<br /></div>';
$(html).appendTo("div#performer_spotlight");
});
$("#performer_spotlight").randomShuffler(".performer_mini", 3000, 3000, 9000);
});

Categories

Resources