Ajax call in a jQuery plugin not working properly - javascript

I'm trying to create a jQuery plugin, inside I need to do an AJAX call to load an xml.
jQuery.fn.imagetags = function(options) {
s = jQuery.extend({
height:null,
width:null,
url:false,
callback:null,
title:null,
}, options);
return this.each(function(){
obj = $(this);
//Initialising the placeholder
$holder = $('<div />')
.width(s.width).height(s.height)
.addClass('jimageholder')
.css({
position: 'relative',
});
obj.wrap($holder);
$.ajax({
type: "GET",
url: s.url,
dataType: "xml",
success:function(data){ initGrids(obj,data,s.callback,s.title); } ,
error: function(data) { alert("Error loading Grid data."); },
});
function initGrids(obj, data,callback,gridtitle){
if (!data) {
alert("Error loading Grid data");
}
$("gridlist gridset",data).each(function(){
var gridsetname = $(this).children("setname").text();
var gridsetcolor = "";
if ($(this).children("color").text() != "") {
gridsetcolor = $(this).children("color").text();
}
$(this).children("grid").each(function(){
var gridcolor = gridsetcolor;
//This colour will override colour set for the grid set
if ($(this).children("color").text() != "") {
gridcolor = $(this).children("color").text();
}
//addGrid(gridsetname,id,x,y,height,width)
addGrid(
obj,
gridsetname,
$(this).children("id").text(),
$(this).children("x").text(),
$(this).children("y").text(),
$(this).children("height").text(),
$(this).children("width").text(),
gridcolor,
gridtitle
);
});
});
}
function addGrid(obj,gridsetname,id,x,y,height,width,color,gridtitle){
//To compensate for the 2px border
height-=4;
width-=4;
$grid = $('<div />')
.addClass(gridsetname)
.attr("id",id)
.addClass('gridtag')
.imagetagsResetHighlight()
.css({
"bottom":y+"px",
"left":x+"px",
"height":height+"px",
"width":width+"px",
});
if(gridtitle != null){
$grid.attr("title",gridtitle);
}
if(color != ""){
$grid.css({
"border-color":color,
});
}
obj.after($grid);
}
});
}
The above plugin I bind with 2 DOM objects and loads two seperate XML files but the callback function is run only on the last DOM object using both loaded XML files.
How can I fix this, so that the callback is applied on the corresponding DOMs. Is the above ajax call is correct?
Sample usage:
<script type="text/javascript">
$(function(){
$(".romeo img").imagetags({
height:500,
width:497,
url: "sample-data.xml",
title: "Testing...",
callback:function(id){
console.log(id);
},
});
});
</script>
<div class="padding-10 min-item background-color-black">
<div class="romeo"><img src="images/samplecontent/test_500x497.gif" alt="Image"> </div>
</div>
<script type="text/javascript">
$(function(){
$(".romeo2 img").imagetags({
height:500,
width:497,
url: "sample-data2.xml",
title: "Testing...",
callback:function(id){
console.log(id);
},
});
});
</script>
<div class="padding-10 min-item background-color-black">
<div class="romeo2"><img src="images/samplecontent/test2_500x497.gif" alt="Image"> </div>
</div>
Here is the sample XML data:
<?xml version="1.0" encoding="utf-8"?>
<gridlist>
<gridset>
<setname>gridset4</setname>
<color>#00FF00</color>
<grid>
<color>#FF77FF</color>
<id>grid2-324</id>
<x>300</x>
<y>300</y>
<height>60</height>
<width>60</width>
</grid>
</gridset>
<gridset>
<setname>gridset3</setname>
<color>#00FF00</color>
<grid>
<color>#FF77FF</color>
<id>grid2-212</id>
<x>300</x>
<y>300</y>
<height>100</height>
<width>100</width>
</grid>
<grid>
<color>#FF77FF</color>
<id>grid2-1212</id>
<x>200</x>
<y>10</y>
<height>200</height>
<width>10</width>
</grid>
</gridset>
</gridlist>

You might be experiencing issues because your calling the ajax load on same url, thus the second call cancels the first call.
If you reading in the same url for each div, why don't you call the ajax once then loop the elements when it returns.
jQuery.fn.imagetags = function(options) {
s = jQuery.extend({
height:null,
width:null,
url:false,
callback:null,
title:null,
}, options);
var elems = $(this);
$.ajax({
type: "GET",
url: s.url,
dataType: "xml",
success:function(data){
elems.each(function() {
obj = $(this);
//Initialising the placeholder
$holder = $('<div />')
.width(s.width).height(s.height)
.addClass('jimageholder')
.css({
position: 'relative',
});
obj.wrap($holder);
initGrids(obj,data,s.callback,s.title);
});
},
error: function(data) { alert("Error loading Grid data."); }
});
return $(this);
}
Basically, what your doing here is calling the ajax function then instantly return the set. then, when the ajax callback gets fired, your looping the elements and appending the data.

This might be a scoping issue. You should use the 'var' statement when declaring variables inside functions. Otherwise, the variables go into the global scope.
var s = jQuery.extend({
height:null,
width:null,
url:false,
callback:null,
title:null,
}, options);
elems.each(function() {
var obj = $(this);
....
}
Since the variables are living in the global scope, they get overwritten by each iteration through the loop, and ultimately resulting in the the last DOM element.

Related

Reload script (Poptrox) after ajax request

So I'm using an AJAX request to load data from the database into a DIV. At the same time, I'm using the same data inside the DIV in a different script (Poptrox) witch does some design stuff.
Without the AJAX request, poptrox works, but if I'm using it together with poptrox it doesn't do the designing anymore.
Is there a way to reload the poptrox-script after the ajax request?
NOTE: the AJAX-Code and the Poptrox-code are placed inside the "main.js"!
Thanks in advance!
php:
<script src="assets/js/jquery.min.js"></script>
<section class="wrapper">
<form action="kochbuch.html" method="get" id="searchfilter">
<input type="text" class="searchBox" name="searchBox" id="searchBox" placeholder="Search..">
<button type="submit" id="searchBtn"><i class="fas fa-search"></i></button>
</form>
</section>
<section class="wrapper">
<div id="gerichte"></div>
</section>
<script src="assets/js/main.js"></script>
js-ajax:
var queryString = window.location.search;
var urlParams = new URLSearchParams(queryString);
if (urlParams.has('searchBox')){
var searchBox = urlParams.get('searchBox');
$.ajax({
type: "POST",
url: "kochbuch/fetchdata.php",
data: {
"search_post_btn": 1,
"searchBox": searchBox,
},
dataType: "json",
success: function (response) {
$("#gerichte").html(response);
}
});
};
js-poptrox:
// Gerichte.
var $gerichte = $('#gerichte');
// Thumbs.
$gerichte.children('.thumb').each(function() {
var $this = $(this),
$image = $this.find('.image'), $image_img = $image.children('img'),
x;
// No image? Bail.
if ($image.length == 0)
return;
// Image.
// This sets the background of the "image" <span> to the image pointed to by its child
// <img> (which is then hidden). Gives us way more flexibility.
// Set background.
$image.css('background-image', 'url(' + $image_img.attr('src') + ')');
// Set background position.
if (x = $image_img.data('position'))
$image.css('background-position', x);
// Hide original img.
$image_img.hide();
});
// Poptrox.
$gerichte.poptrox({
baseZIndex: 20000,
caption: function($a) {
var s = '';
$a.nextAll().each(function() {
s += this.outerHTML;
});
return s;
},
fadeSpeed: 300,
onPopupClose: function() { $body.removeClass('modal-active'); },
onPopupOpen: function() { $body.addClass('modal-active'); },
overlayOpacity: 0,
popupCloserText: '',
popupHeight: 150,
popupLoaderText: '',
popupSpeed: 300,
popupWidth: 150,
selector: '.thumb > a.image',
usePopupCaption: true,
usePopupCloser: true,
usePopupDefaultStyling: false,
usePopupForceClose: true,
usePopupLoader: true,
usePopupNav: true,
windowMargin: 50
});
// Hack: Set margins to 0 when 'xsmall' activates.
breakpoints.on('<=xsmall', function() {
$main[0]._poptrox.windowMargin = 0;
});
breakpoints.on('>xsmall', function() {
$main[0]._poptrox.windowMargin = 50;
});
alright, i found one possible solution, but know the preloaded data ist formated:
the whole poptrox code has to be wrapped by this function:
$(document).ajaxStop(function () {
// function after ajax
});
If you know any better solution, feel free to submit :)
EDIT:
alright, my solution was as follows:
if (urlParams.has('searchBox')){
var searchBox = urlParams.get('searchBox');
} else {
var searchBox = '';
}
$.ajax({ .....

Updating an element via ajax: shall I use global variable to keep element's id or it is a bad habit?

On a page I have a list of dates which I want to edit via AJAX.
Example:
<li>January 2015<a data-update_url="/frame_date/22/update/" class="update" id="update_framedate_22" href="javascript:void(0)">Edit</a>
When the user clicks on the Edit link, I catch element id and the edit link.
Than AJAX requests the update form from the server. And now I have to place the form instead of the element with the mentioned id.
In other words, in frame_date_update_show_get I need element's id. In the example below, I keep it in the global variable date_id. But inside me there is a protest: I was always taught that global variables is a bad practice. But in this case I don't know how to get along without the global variable date_id.
Could you give me some piece of advice: is my code acceptable or there is a better way to cope with the problem.
function frame_date_update_show_get(data){
$("#" + date_id).replaceWith(data);
}
function frame_date_update_get_data(){
date_id = this.getAttribute('id')
var cuaghtUrl = this.getAttribute('data-update_url');
$.ajax({
method: 'get',
url: cuaghtUrl,
success: frame_date_update_show_get,
error: fail
});
}
var date_id = ""
Use an anonymous function as success callback function and then call frame_date_update_show_get with an additional date_id parameter:
function frame_date_update_show_get(data, date_id) {
$("#" + date_id).replaceWith(data);
}
function frame_date_update_get_data() {
var date_id = this.getAttribute('id')
var cuaghtUrl = this.getAttribute('data-update_url');
$.ajax({
method: 'get',
url: cuaghtUrl,
success: function(data) {
frame_date_update_show_get(data, date_id);
},
error: fail
});
}
I would use contenteditable combined with AJAX this way:
function dateChange(options){
switch( options.action ) {
case 'update':
if( options.id && options.text && options.updateUrl ) {
$.ajax({
method: 'post',
url: options.updateUrl,
data: {
id: options.id,
html: options.text
},
success: function(response) {
options.element.html( response );
options.element.removeClass('editing');
},
error: function(err) {
console.log( 'request failed: ' + err.text );
}
});
};
break;
default:
console.log( 'action invalid' );
return false;
break;
};
};
var editTimeout = null;
$('li[data-update-url]').on('input', function(e) {
var thisText = $(this);
thisText.addClass('editing');
clearTimeout( editTimeout );
editTimeout = setTimeout(function() {
var updateUrl = thisText.data('updateUrl');
var id = thisText.data('id');
dateChange({
'action': 'update',
'element': thisText,
'id': id,
'updateUrl': updateUrl,
'text': thisText.html()
});
}, 1000);
});
.editing {
color: orange;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li data-update-url="/echo/html/" data-id="update_framedate_22" contenteditable>January 2015</li>
</ul>
Check how it works on JSFiddle.
This code would be easy to expand for other actions you may need, as delete, add.

How call variable outside function .each with Jquery?

I want to be able to access the value of a nested each() function outside of the function.
I have code below or http://jsfiddle.net/z36UK/6/
HTML:
<div id="wrap">
<ul data-role="listview" data-filter="true" data-filter-placeholder="Search..." id="ds-canho">
</ul>
</div>
Javascript:
$(document).ready(function() {
var urlx=[];
parseXml();
alert(urlx);
console.log(urlx);
$.mobile.loading( "show" );
$.ajax({
type: "GET",
url: 'https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%27http://saigonpearl.info/home/notype/-0-trang-chu.html%27%20and%20xpath%3D%22%2F%2Fdiv%5B%40class%3D%27tindang%27%5D%22&diagnostics=true',
dataType: "xml",
success: parseXml
});
function parseXml(xml) {
$(xml).find("div.tindang").each(function() {
var url = $(this).find('a').attr("href"),
urlx= url.replace('#menutop','');
$("ul#ds-canho").append('<li>' + $(this).find('h3').text() + '</li>');
$('ul#ds-canho').listview('refresh');
$.mobile.loading( "hide" );
});
}
});
Please update below js code
$(document).ready(function() {
$.mobile.loading( "show" );
$.ajax({
type: "GET",
url: 'https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%27http://saigonpearl.info/home/notype/-0-trang-chu.html%27%20and%20xpath%3D%22%2F%2Fdiv%5B%40class%3D%27tindang%27%5D%22&diagnostics=true',
dataType: "xml",
success: parseXml
});
$( document ).ajaxComplete(function() {
parseXml();
});
function parseXml(xml) {
window.urlx = '';
$(xml).find("div.tindang").each(function() {
var url = $(this).find('a').attr("href"),
urlx = url.replace('#menutop','');
$("ul#ds-canho").append('<li>' + $(this).find('h3').text() + '</li>');
$('ul#ds-canho').listview('refresh');
$.mobile.loading( "hide" );
});
}
});
EDIT
Add FSFIDDLE
It's not about the each, is it? You can easily put the urlx variable there and assign to it from the inside:
function parseXml(xml) {
var urlx;
$(xml).find("div.tindang").each(function() {
var url = $(this).find('a').attr("href"),
urlx = url.replace('#menutop','');
$("ul#ds-canho").append('<li>' + $(this).find('h3').text() + '</li>');
$('ul#ds-canho').listview('refresh');
$.mobile.loading( "hide" );
});
console.log(urlx);
// if you wanted an array, use `urlx = [];` and `urlx.push(…);`
}
However, where you currently have placed the log and alert statements is
before the ajax request
outside of the ajax request callback
which means that it cannot work. You need to put them inside the callback, because you cannot return the data outside of it.

How to unbind or turn off all jquery function?

I have constructed an app with push state. Everything is working fine. However in some instances my jquery function are fireing multiple times. That is because when I call push state I bind the particular js file for each page I call. Which means that the same js functions are binded many times to the html while I surf in my page.
Tip: I am using documen.on in my jquery funciton because I need my function to get bound to the dynamical printed HTML through Ajax.
I tried to use off in the push state before printing with no success!
Here is my code:
var requests = [];
function replacePage(url) {
var loading = '<div class="push-load"></div>'
$('.content').fadeOut(200);
$('.container').append(loading);
$.each( requests, function( i, v ){
v.abort();
});
requests.push( $.ajax({
type: "GET",
url: url,
dataType: "html",
success: function(data){
var dom = $(data);
//var title = dom.filter('title').text();
var html = dom.find('.content').html();
//alert(html);
//alert("OK");
//$('title').text(title);
$('a').off();
$('.push-load').remove();
$('.content').html(html).fadeIn(200);
//console.log(data);
$('.page-loader').hide();
$('.load-a').fadeIn(300);
}
})
);
}
$(window).bind('popstate', function(){
replacePage(location.pathname);
});
Thanks in advance!
simple bind new function with blank code
$( "#id" ).bind( "click", function() {
//blank
});
or
used
$('#id').unbind();
Try this,
var requests = [];
function replacePage(url) {
var obj = $(this);
obj.unbind("click", replacePage); //unbind to prevent ajax multiple request
var loading = '<div class="push-load"></div>';
$('.content').fadeOut(200);
$('.container').append(loading);
$.each(requests, function (i, v) {
v.abort();
});
requests.push(
$.ajax({
type: "GET",
url: url,
dataType: "html",
success: function (data) {
var dom = $(data);
//var title = dom.filter('title').text();
var html = dom.find('.content').html();
//alert(html);
//alert("OK");
//$('title').text(title);
obj.bind("click", replacePage); // binding after successfulurl ajax request
$('.push-load').remove();
$('.content').html(html).fadeIn(200);
//console.log(data);
$('.page-loader').hide();
$('.load-a').fadeIn(300);
}
}));
}
Hope this helps,Thank you

jQuery GET not succeeding

I'm trying to read from a list of threads as described in a file 'forum.xml'. I have come to realise that my GET request is not succeeding. Here is the XML file (which is not modifiable)
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE forum SYSTEM "forum.dtd">
<forum>
<thread>
<title>Tea Party</title>
<posts>teaParty.xml</posts>
</thread>
<thread>
<title>COMP212 Exam</title>
<posts>crypto.xml</posts>
</thread>
</forum>
and here is my js. I have tested that the element at target is being selected.
//threadReader.js
//Gets and display list of threads
var Threads = (function() {
var pub = {};
var target = $( ".thread");
var xmlSource = 'forum.xml';
function showThreads() {
console.log("showThreads called");
console.log(xmlSource);
$({
type: "GET",
url: xmlSource,
cache: false,
success: function(data) {
console.log(data);
parseThreads(data, target);
}
});
}
function parseThreads(data, target) {
console.log("parseThreads called");
console.log(target);
console.log(data);
target.append("<ul>");
$(data).find("title").each(function () {
$(target).append("<li>");
$(target).append($(this).text());
$(target).append("</li>");
});
}
pub.setup = function() {
showThreads();
}
return pub;
}());
$(document).ready(Threads.setup);
any insight is always appreciated
Change this
function showThreads() {
console.log("showThreads called");
console.log(xmlSource);
$({
to
function showThreads() {
console.log("showThreads called");
console.log(xmlSource);
$.ajax({
Also be aware that your call to $(".thread") may not match any elements at the time you're calling it. Best to do that in your document ready handler.
This may help in future. To get the correct Jquery Ajax syntax
http://api.jquery.com/jQuery.ajax/
In your case, I guess this should fire the call.
function showThreads() {
console.log("showThreads called");
console.log(xmlSource);
$.ajax({
type: "GET",
url: xmlSource,
cache: false,
success: function(data) {
console.log(data);
parseThreads(data, target);
}
});
}

Categories

Resources