Display of duplicate records in Firefox - javascript

I am working on an online music store. There are buttons like myplaylists, mydownloads etc...
On clicking on these buttons, a list of songs appears accordingly in a grid view.
The problem is that when I click on the buttons twice quickly the list appears two times like 1..4..8 1..4..8 and if I click thrice quickly it happens three times.The function that displays the list uses append() to add songs to the list.
These things happen only on Firefox
I cannot figure out the problem.
function fillMyMusicSongGrid
{
// code to fetch data from the database
embedSongGrid(.....);//displays the grid
}
embedSongGrid(.....)
{
//displays the grid
tableContent = '...............'
$(tableCont).appendTo('table#songList');
}

If I'm guessing correctly, pressing these buttons makes and Ajax call back to the server to get the information, probably as a JSON array. You then loop through these and append() them to the appropriate div. Either that or you get HTML and just append it.
Simply solution: just empty() it before you add it:
$.ajax({
...
success: function(data) {
$("#songlist").empty();
for (song in data) {
$("#songlist").append(...);
}
}
});
or
$.ajax({
...
success: function(html) {
$("#songlist").html(html);
}
});

Try
$(tableCont).empty();
$(tableCont).appendTo('table#songList');
instead of
$(tableCont).appendTo('table#songList');

Related

Reinitialize jQuery on Window Load event after AJAX

I have the following jQuery code that adjusts the product grid on the Window Load event:
$j(window).load(function(){
// Remove list class if thumbview
if ( $j("ul#products-list").hasClass("thumb_view") ) {
$j("ul#products-list").removeClass("list") };
// Equalize all thumb heights on switch if list view default
var maxHeight = 0;
$j('ul.thumb_view div.product-container').each(function() { maxHeight = Math.max(maxHeight, $j(this).height()); }).height(maxHeight +8);
// Undo equalized heights for list
$j('ul.list div.product-container').css("height","auto");
});
On the page we have a way of filtering the products based on for example price. When the price range is adjusted by the customer an AJAX call takes care of the actual filtering of products. However the jQuery script is not run again and the product grid fails to load correctly. I've done a lot of research and found to solutions that could solve this issue; use an "m-ajax-after" event, or use a jQuery delegate function.
The first option would involve this piece of code:
jQuery(document).bind('m-ajax-after', function (e, selectors, url, action) {
// reinitialize your script
});
Which I haven't managed to get it working. Knowledge on this function is very limited.
In my opinion the second option has the most chance on actual success however I haven't been able to reproduce this into code that actually works. Many topics are to be found I just can combine this with the (window).load function. What would be the right way to do this?
It's hard to say without seeing the complete code, but here's an idea:
function formatGrid() {
// Remove list class if thumbview
if ( $j("ul#products-list").hasClass("thumb_view") ) {
$j("ul#products-list").removeClass("list") };
// Equalize all thumb heights on switch if list view default
var maxHeight = 0;
$j('ul.thumb_view div.product-container').each(function() { maxHeight = Math.max(maxHeight, $j(this).height()); }).height(maxHeight +8);
// Undo equalized heights for list
$j('ul.list div.product-container').css("height","auto");
}
$j(window).load(function(){
formatGrid();
});
And then call this function on Ajax success:
$.ajax({
//your current ajax code
//and then call the formatting function
success: function() {
formatGrid();
}
});

Share Angular Expression with onclick Function

Let me try explaining things again. I have an app running in a javascript framework on Node.js w/ Bootstrap. In one of the bootstrap panels I embedded an Angular Elasticsearch search client. Here's some code that displays the results:
<section class='results'><article class='result' ng-repeat='result in results track by $id(result)' /><div id="addThisInfo" ng-repeat='ng-repeat='result in results track by $id(result)' style="display: none;"> {{$id}},{{result.code}},{{result.expression}},{{result.source}}</div>Code:{{result.code}}<br>Description: {{result.expression}}<br>div ng-if='result.source ==4'> Type: Source 1</div><div ng-if='result.source ==10'> Type: Source 2</div></article> </section>
There are 5 results per page.
Note that the only portion of this app written in Angular is this search mechanism.
Ultimately I want the user to be able to click on either the text of the desired result or click on a button that would add their choices to a separate table.
Here's how it works rignt now. When I click on any of the 5 results per page it invokes this:
document.addEventListener("click", function() {
var packy = document.getElementById("addThisInfo").innerHTML; //div above
addInfo(packy);
});
It doesn't matter which ever one of the results I click, it always sends the "first" result of the active page. Even though the div "addThisInfo" has been repeated and is part of the result, it doesn't
The web socket call looks something like this:
{"params":"0ij,I77.812ZZ,"Full Expression","100"}
I'm not having any luck uploading an image of the Inspect Element. But there you can see that all of the data is there.
I'd like to schedule a http://join.me session with someone so I could show you how it's currently working. Help is greatly appreciated!!
Thanks!
why must you pass them individually? I'm unsure of what you're trying to accomplish, exactly, but I'd handle it something like this:
for the markup:
<button ng-click="addInfo(result)">
then in the controller
$scope.addInfo = function(result) {
var foo = result.code,
bar = result.source;
etc...
}
Angular. directive('notNgClick', function () { return {
restrict: 'A',
scope: {
values: '&'
},
link: function (scope,elem, attr) {
elem.addEventListener(function () {alert (scope.values.someValue ) } )
}
}
}

Tooltipster not working properly in the beginning

I am using the tooltipster plugin tool where I got gantt chart drawn with some td given id.
So, which ever id is defined and the mouse over it will get ajax data and show accordingly.
Below is snippet of my codes. Issue here is that the tool tip only appear after few times I mouse the td. Thereafter, it works fine.
I can see, in my debug window, that ajax page is called and following error:
Tooltipster: one or more tooltips are already attached to this element: ignoring. Use the "multiple" option to attach more tooltips. jquery.tooltipster.min.js:1
$(document).ready(function () {
$('td[id]').tooltipster({
// content: 'Loading...',
functionBefore: function(origin, continueTooltip) {
// We'll make this function asynchronous and allow the tooltip to go ahead and show the loading notification while fetching our data
continueTooltip();
var idval=0;
// Next, we want to check if our data has already been cached
//if (origin.data('ajax') !== 'cached') {
$.ajax({
type: 'GET',
url: 'getDetails.php',
data:idval,
success: function(data) {
// Update our tooltip content with our returned data and cache it
//alert("Data is : "+data);
var finalData = 'Total Data : 300 <br> Total Completed : 200';
//alert("DATA");
//origin.tooltipster: $('<span>testst<strong>This text is in bold case !</strong></span>')
origin.tooltipster({
content: finalData,
multiple: true,
contentAsHTML: true
});
//origin.tooltipster({content: data,contentAsHTML: true}).data('ajax', 'cached');
}
});
//}
}
});
});
The Tooltipster plugin really should be initialised before all of this. Using the mouseenter enter to trigger it's initialisation every time a user hover's over a <td> element is not great practice and is the root problem to your issue. Ideally you would want to break it down into the following:
Find your <td> elements with id's defined.
Apply tooltipster to these elements.
Let tooltipster handle everything from there.
1. Finding your <td> elements
With the magic of jQuery you can fetch these with a clever use of selectors rather than querying a larger set with your initial implementation, gathered from the answers within the StackOverflow thread here, jquery get only all html elements with ids, we get:
$('td[id]')
This will fetch you all <td> elements with an id defined, be warned this could be a bit slow if you have an extensive table. Alternatively you can select, then apply a filter to narrow down your set:
$('td').filter(function(){
return $(this).attr('id') !== undefined;
});
Both will essentially do the same!
2. Applying tooltipster to these elements
I've not done much here since you had a lot of commented out code, so I've kept it the same, with some minor tweaks, here is my version of the "working code":
$('td[id]').tooltipster({
// content: 'Loading...',
functionBefore: function(origin, continueTooltip) {
// We'll make this function asynchronous and allow the tooltip to go ahead and show the loading notification while fetching our data
continueTooltip();
// Next, we want to check if our data has already been cached
//if (origin.data('ajax') !== 'cached') {
$.ajax({
type: 'GET',
url: 'getDetails.php',
data: $(this).attr('id'),
success: function(data) {
// Update our tooltip content with our returned data and cache it
//alert("Data is : "+data);
var finalData = 'Total Data : 300 <br> Total Completed : 200';
//alert("DATA");
//origin.tooltipster: $('<span>testst<strong>This text is in bold case !</strong></span>')
origin.tooltipster({
content: finalData,
multiple: true,
contentAsHTML: true
});
//origin.tooltipster({content: data,contentAsHTML: true}).data('ajax', 'cached');
}
});
//}
}
});
3. Letting tooltipster handle everything from here
Tooltipster (when intialised) is triggered by default when hovering over an element, this means your functionBefore will be run before this "hover" event, causing your AJAX request to be run each time, there is no need to do anything more thereafter :D
I hope this helps! :)
You can use this code :
var tooltipInstance;
$("body").on('mouseover', 'td[id]:not(.tooltipstered)', function(){
tooltipInstance = $(this).tooltipster({
//your code ...
});
tooltipInstance.tooltipster('open');
});

Can't find element in DOM after loading it with ajax (want to bind jquery plug in to it)

So I have 2 html pages. 1 that functions as container and 1 that functions as content.
When I load the content page with a table I'm able to use drag and drop.
But when I go to my container page and load the content page into a div with ajax, the drag and drop stops working. All other javascript functionalities inside the content page still work. How can I bind the jquery dnd plugin to the table loaded with ajax?
I'm using drag & drop with this as tutorial http://isocra.com/2008/02/table-drag-and-drop-jquery-plugin/
my code looks like this:
$(window).load(function()
{ if(temp == 0)
{
DP("eerste keer")
load_table();
temp = 1;
}
} );
function load_table()
{
DP('load_table');
$.ajax({
//async: false,
type: "POST",
url: "/diagnose_hoofdpagina/table_diagnose/" + DosierID, // <== loads requested page
success: function (data) {
$("#diagnoses_zelf").html(''); //<== clears current content of div
$("#diagnoses_zelf").append(data).trigger('create'); // <== appends requested page
},
error: function(){
alert('error');
}
}).done(function() {
update_table();
initialize_table(); // <== calls jquery plug in
});
return false;
}
function initialize_table()
{
var tableid = $('#diagnoses_zelf table').attr('id'); //< this finds the correct table thanks to Fábio Batista => this option worked, rest didn't
alert(tableid);
$(tableid).tableDnD({
onDrop: function(table, row) {
alert(table + " " + row);
},
onDragStart: function(table,row){
var tette = $(row).index;
alert(tette);
},
dragHandle: ".dragHandle"
});
}
How is this possible and what can I do about it?
Can anyone help me with this please.
Very short:
I want access to the ID of the table I load into my container page with ajax and use the jquery drag and drop plug in on it.
EDIT
Findings:
Somehow my table in the container page got renamed to pSqlaTable instead of the id I gave to it in the controller page which is.
<table id="tableDiagnose" class="table table-hover">
Thats why the code couldn't find the table annymore Got fixed by this code thanks to Fábio Batista:
$('#diagnoses_zelf table').tableDnD( ... );
, but how can I use the dnd plugin now ?
It finds the table now, but I'm still not able to bind the dnd plugin to it, Am I able to bind a jquery plug in to ajax loaded tables ?
EDIT
//drag & drop http://isocra.com/2008/02/table-drag-and-drop-jquery-plugin/
function initialize_table()
{
var tableid = $('#diagnoses_zelf table').attr('id');
alert(tableid);
$('#' + tableid).tableDnD({
onDrop: function(table, row) {
alert(table + " " + row);
},
onDragStart: function(table,row){
alert('issemer?');
},
dragHandle: ".dragHandle"
});
}
This is the code i'm still stuck with. tableid is correct but the initialisation of the jquery isn't. I can't drag the drows in the table. Is my syntax wrong ?
EDIT
Could it be that I can't bind the jquery to the table because I dynamicaly generate the table on the other page with ZPT (or javascript) ?
The issue with plugins.
You're mixing lots of external libraries and code. This results in possible mis-matches between versions, and a lot of black boxes in your code.
As a developer, this should make you feel very uneasy. Having code you do not fully understand in your code base can get really frustrating really fast.
The alternative.
Often, these sort of plugins provide functionality we, as JavaScript developers can accomplish just as easily without them. This development process, in simple enough scenarios, lets us create code we understand and have an easier time maintaining. Not only do we learn from this process, but we also create smaller bits of specific code. Community driven solutions are very good in general, but it's important to remember they're not a silver bullet. Often you're stuck using a not-so-active project which has a bug for your specific case and you have to dig through a large, unfamiliar code base.
Your code
So what does this drag and drop plugin do?
Well, I'd break it down as the following:
Listens to the mousedown event on table rows
When such an event fires, start moving the table row to match the mouse position
When mouseup occurs, detect that, and finalize the position.
Let us see how we can do something similar.
Let's assume the table's HTML is something like:
<table>
<tbody>
<tr>
<td> Hello 1</td>
</tr><tr>
<td> Hello 2</td>
</tr>
</tbody>
</table>
Here is a fiddle with the table with some basic styling applied
Next, we'll listen to the selection events. We'll add an event to the table rows for selection and to the document to when the mouse is up. jQuery has event listeners for such events. Since we want these events to stick even after AJAX, we'll use .on which lets us use delegated events. .on means that even if we add content to the table later, it won't matter.
var selected; // currently selected row
$(document).on("mousedown","#MySpecialTable tr",function(){
$("#textDiv").text(this.textContent);
selected = this;
});
$(document).on("mouseup",function(){
$("#textDiv").text("Left "+selected.textContent);
selected = null;
});
Here is a working fiddle of such code.
Now, we'll want to actually change the drag&drop to work when, that is, update the current position to the one reflecting the mouse position. We can listen to mousemove events, and detect the element we're currently on. Something like
$(document).on("mousemove",function(e){
$("#textDiv").text($(e.target).html());
});
You can see a working fiddle here
That's nice, but we want to actually change the element position. So we'll need to change the table structure to allow that. We can remove the element, and append it at the correct position. We'll check if we have a selected element, and if we do, we can track it compared to the current element in the mousemove event. We can for starters detect if we should drag with something like:
$(document).on("mousemove",function(e){
if(selected !=null){// got an element selected
if($("#MySpecialTable").has(e.target).length > 0){ //in the table
$("#mousePos").text("DRAGGING");
}
}else{
$("#mousePos").text("NOT SELECTED");
}
});
(Fiddle)
Now, we'll add actual selection, we'll replace the elements when the target is not our element and we're in the table. Our full code should be something like:
var selected;
$(document).on("mousedown","#MySpecialTable tr",function(e){
e.preventDefault();//stop the text selection;
$("#textDiv").text(this.textContent);
selected = $(this);
selected.find("td").css("background-color","#999");
});
$(document).on("mouseup",function(){
$("#textDiv").text("Left "+selected.text());
selected.find("td").css("background-color","");
selected = null;
});
$(document).on("mousemove",function(e){
if(selected !=null){// got an element selected
if($("#MySpecialTable").has(e.target).length > 0){ //in the table
var el = $(e.target).closest("tr");//the tr element we're on
el.before(selected);// replace the elements
}
}else{
$("#mousePos").text("NOT SELECTED");
}
});
$("#MySpecialTable").on('selectstart', false);//Don't let the user select the table
(Fiddle)
Now, so far we only have a few lines of code, which is nice since we know exactly what's going on and didn't need to use lots of lines of external code we don't fully understand.
But will it AJAX?
Let's load the data into the table with AJAX and see! We'll simulate an AJAX response using a setTimeout which would allow us to simulate an asynchronous request. We'll use
setTimeout(function(){
$("#MySpecialTable").html("<tr><td> Hello 1</td></tr><tr><td> Hello 2</td></tr><tr><td> Hello 3</td></tr><tr><td> Hello 4</td></tr><tr><td> Hello 5</td></tr><tr><td> Hello 6</td></tr>");
},1000);
This means, update the HTML of #MySpecialTable after one second. Let's see if it works shall we?
So why does it work? well, we used delegated events which means we don't care if the elements we're loading are in the screen right now or not. We had the insight to do this since we built our code ourselves and knew what our final goal was. The only thing left to do is clean the code a little.
We'll wrap our code in the following, to prevent $ from being an issue in non-conflict mode (that is, $ is already taken in the page:
(function($){
})(jQuery);
Next we'll add a binding for our table event:
$.GertVDragTable = function(elementSelector){ // rest of code.
Eventually, our code might look something like this.
Using it, would be a simple $.GertVDragTable("#MySpecialTable"); alternatively, we can put it on $.fn and allow every function to call it. Which is a matter of taste.
No copy-pasta please :) I'd appreciate it if you stop on every stage and think why the next step was taken.
You don't need to use the ID as a selector, you can use any expression that can find your table.
If there's only one table on the resulting $.ajax call, you can search for "a table inside the container", using the container ID, which won't change:
$('#diagnoses_zelf table').tableDnD( ... );
If there's more than one table, use a different kind of selector, instead of the ID. A CSS class works fine:
$('table.table-diagnose').tableDnD( ... );
So does a data- attribute:
$("table[data-diagnose]").tableDnD( ... );
Try adding a title to your table, like so:
<table id = "tableDiagnose" class = "table table-hover" title = "table-content">
Then use the jQuery attribute selector to find this table instead of finding it by id.
$('table[title="table-content"]').tableDnD({
// the rest of your code
If your id is changing you should not use an ID then:
<table class="tableDiagnose table table-hover">
Plugin
function initialize_table()
{
$('.tableDiagnose.table').tableDnD({
onDrop: function(table, row) {
alert(table + " " + row);
},
dragHandle: ".dragHandle"
});
DP('nee');
}
EDIT: ajax is asynchronous :
function load_table()
{
DP('load_table');
$.ajax({
//async: false,
type: "POST",
url: "/diagnose_hoofdpagina/table_diagnose/" + DosierID, // <== loads requested page
success: function (data) {
$("#diagnoses_zelf").html(''); //<== clears current content of div
$("#diagnoses_zelf").append(data).trigger('create'); // <== appends requested page
update_table();
initialize_table(); // <== calls jquery plug in
},
error: function(){
alert('error');
}
});
//removed .done as you already have a success option in ajax
return false;
}
EDIT: found your bug........
you retrieve the table id then select it in $(tableid) but you missed the #
function initialize_table()
{
/*
var tableid = $('#diagnoses_zelf table').attr('id'); //< this finds the correct table thanks to Fábio Batista => this option worked, rest didn't
alert(tableid);
// but you really should limit the use of variables when you don't need them*/
//$('#'+tableid).tableDnD({
//like this directly
$('#diagnoses_zelf table').tableDnD({
onDrop: function(table, row) {
alert(table + " " + row);
},
onDragStart: function(table,row){
var tette = $(row).index;
//alert(tette);
},
dragHandle: ".dragHandle"
});
}
See the demo here
EDIT
Do you include the script file in the container page or in the content page? I guess you might want to try to load it when calling the dnd plugin with getScript:
...
$.getScript('pathTotableDnDlib').done(function(){
$(tableid).tableDnD({
onDrop: function(table, row) {
alert(table + " " + row);
},
onDragStart: function(table,row){
var tette = $(row).index;
alert(tette);
},
dragHandle: ".dragHandle"
});});
...
more on getscript: here
#BenjaminGruenbaum Hi thx a lot for the tutorial, i modified a bit the code to block the drag n'drop on table headers and to improve the drag fluidity tracking the mouse direction.
var old_y = 0;
(function ($) {
$.GertVDragTable = function (tableName) {
var selected;
$(document).on("mousedown", tableName+" tr",function (e) {
e.preventDefault(); //stop the text selection;
if (($(this).find('th').length)== 0){ //prevent dragging on tr containing th
selected = $(this);
selected.find("td").css("background-color", "black");
selected.find("td").css("color", "white");
}
});
$(document).on("mouseup", function () {
selected.find("td").css("background-color", "");
selected.find("td").css("color", "");
selected = null;
});
$(document).on("mousemove", function (e) {
if (selected != null ) { // got an element selected
if ($(tableName).has(e.target).length > 0) { //in the table
var el = $(e.target).closest("tr"); //the tr element we're on
if (el.find('th').length==0){ //prevent dropping on headers row
if (e.pageY > old_y){ //**
el.after(selected);}else{ //**-->more fluid dragging based on mouse direction
el.before(selected); //**
}
}
}
old_y = e.pageY;
}
});
$(tableName).on('selectstart', false); //Don't let the user select the table
}
})(jQuery);
here's the fiddle http://jsfiddle.net/59rdq/
I hope it will be useful for someone.

jQuery AJAX Request Repeating on Click event

Im building a small application and I have some click events binded to some span tags that trigger AJAX requests to a PHP file which queries a MySQL database and spits out the results to populate the targeted area.
However, sometimes i will be clicking the buttons and I have conditionals in place to stop multiple clicking to prevent duplicate content being added numerous times.
I click on a button and firebug tells me that the ajax request had actioned more than once, sometimes it will multiply - so it will start by doing it 2 times or another time it will carry our the request 8 times on one click and obviously flood my content area with duplicate data.
Any ideas?
EDIT
Code for a button is as follows:
<span class="btn"><b>Material</b></span>
This would be enabled by
$('.btn').bind('click', matOption);
and this would be controlled by something like this
var matOption = function() {
$(this).addClass('active');
// remove colours if change of mind on materials
if($('#selectedColour').val() >= 1) {
$('.colour').slideUp(500).children().remove();
$('#selectedColour').val('');
$('.matColOpt .btn').html('<b>Material Colour</b>').removeClass('active').css('opacity', 0.55);
$('.btn').eq(2).unbind('click', colOption); // add click to colour
$('#stage h1 span').eq(2).fadeOut(500);
$('.paperOpt .btn').css('opacity', 0.55).unbind('click', selectPaper);
}
// ajax req for available materials
var cid = $('#selectedColour').val();
var target = $('#notebookOpts .matOpt ul');
$.ajax({
type: "GET",
url: ajaxFile+"?method=getMaterials",
beforeSend: function() {if($('.mats').children('li').size() >= 1) { return false; }},
success: function(data) {
target.append(data).slideDown(500);
$('.mats li').bind('click', matSelect);
},
error: function() {alert('An unexpected error has occurred! Please try again.');}
});
};
You're probably binding your matOption function more than once.
if(!window.matOptionBound){
$('.btn').bind('click', matOption);
window.matOptionBound = true;
}
If you have a code that binds an event handler to a DOM element repeatedly then that event handler does gets executed repeatedly on the event. so if your code such
$("span").click(myHandlerFunction)
gets executed thrice, then you have just told jQuery to fire myHandlerFunction thrice on every click of span. It would be good to make sure there is no such condition goign on in your code. If that is not true then please post your code so that I can help further.
PS: The safest way to do this will be as
$("span").unbind("click",myHandlerFunction).bind("click",myHandlerFunction)

Categories