ugrás a tartalomhoz

Jquery onComplete függvény paraméterrel (egyből lefut)

Reactor · 2012. Feb. 1. (Sze), 13.14
Üdvözletem!
Tegnap egy problémába ütköztem, amikor Jquery animate() függvényének onComplete paraméterének akartam adni egy függvényt, aminek paraméterként át akartam adni az idxA animáció megkezdéskori értékét.

A jelenség az, hogy az animáció megkezdésekor lefut, nem pedig a befejezésekor.
function displayTiles(){
    var rid = Math.floor(Math.random()*(tileDirs.length));
    var tdiv = null;
    var tch = null;
    
    $('img.tilech').css('opacity', 0);
    for(idxA = 1; idxA <=6; idxA++){
    tdiv =$('div#tdiv'+idxA);
    tch = tdiv.children('img.tilech');
    tch.attr("src","images/tiles/"+tileDirs[rid]+'/tile'+idxA+'.png');
    tch.animate({'opacity' : '1'}, Math.floor(Math.random()*1000)+250, (function(tn){
        tdiv.css('background-image', 'url(images/tiles/'+tileDirs[rid]+'/tile'+tn+'.png)');
        $('img.tilech').css('opacity', 0); // OK
    })(idxA));
    }
}
A konkrét project itt elérhető

Keveset dolgoztam JavaScriptben, gondolom nagy baki lehet. :>
A segítséget előre is köszönöm.
 
1

Closure

Poetro · 2012. Feb. 1. (Sze), 14.01
A closure használatát úgy látom, még szoknod kell. Az animate egy függvényt vár onComplete paraméternek, de te nem adsz neki vissza semmit. Mivel meghívsz egy függvényt, ami le is fut, de nem ad vissza semmit (undefined), ami átadsz az animate függvénynek.
Nézzük, mi is történik itt:
    function(tn){  
        tdiv.css('background-image', 'url(images/tiles/'+tileDirs[rid]+'/tile'+tn+'.png)');  
        $('img.tilech').css('opacity', 0); // OK  
    }
Van ugye a fenti függvényünk. Ezt meghívjuk azonnal az idxA paraméterrel, ezért a függvény azonnal le is fut, azaz beállítja az opacity-t 0-ra, valamint átállítja a háttérképet azonnal, még az animate lefutása előtt. Majd visszaad egy undefined értéket a függvény (mivel ha nem adsz vissza semmit egy függvényből, akkor automatikusan az undefined érték adódik vissza). Ezt az undefined-ot átadod az animate függvénynek. Gondolom nem ezt szeretnéd.
Valamint ha már closure-t használsz, akkor figyelned kell arra, hogy a tdiv a függvényen belül a legutoljára beállított értéket fogja jelenteni akkor, amikor a függvény lefut. Azaz ebben az esetben ha ténylegesen sikerül átadni ezt a függvényt majd az animate-nek, akkor a tdiv ebben a formában $("div#tdiv6") lesz minden esetben.
2

függvényt függvénnyel

Reactor · 2012. Feb. 1. (Sze), 14.24
Azt hiszem értem. Köszönöm.
Tehát onComplete nem egy "meghívott", hanem egy "meghívandó" függvény.
Ha írok egy függvényt, ami visszaadja azt a függvényt, amit meg kell hívni?
function(tn){
        return (function(){alert(tn);})
})(idxA)
szerk:
function displayTiles(){
    var rid = Math.floor(Math.random()*(tileDirs.length));
    var tdiv = null;
    var tch = null;
    
    $('img.tilech').css('opacity', 0);
    for(idxA = 1; idxA <=6; idxA++){
    tdiv =$('div#tdiv'+idxA);
    tch = tdiv.children('img.tilech');
    tch.attr("src","images/tiles/"+tileDirs[rid]+'/tile'+idxA+'.png');
    tch.animate({'opacity' : '1'}, Math.floor(Math.random()*1000)+250, (function(atdiv, atch, tn, arid){
        return (function(){
            atdiv.css('background-image', 'url(images/tiles/'+tileDirs[arid]+'/tile'+tn+'.png)');
            atch.css('opacity', 0);
        })
    })(tdiv, tch, idxA, rid));
    }
}
3

detto

Totti 1986 · 2012. Ápr. 3. (K), 10.24
Hello!

Nekem is hasonló problémám van, ezért is nem nyitottam új témát.
Egy toplistát szeretnék folyamatosan frissíteni úgy, hogy időközönként meghívok egy ajax-ot, ami visszaad 3 ul-t (3-féle toplistát). Ezt beteszem egy láthatatlan div-be, ul-enként beteszem egy-egy változóba, aztán li-nként megnézem, hogy hányadik helyen áll az eredeti toplistában, majd a jelenlegi helyzetéhez animálom marginTop-pal.
A gond az, hogy a callback-et nem ismerem még, meg azt, hogy pontosan hogy kell változókat átadni pl. egy animate fgv.-nek, de a beszélgetésetekből okulva átalakítottam a script-et, és egy része működik is, de a másik része nem.

Itt a script:
$.fn.toplistRefresh = function(settings) {
	var settings = $.extend({
		gameID : ''
	}, settings);
	$.ajax({
		url: 'php/xzonaGameApp.php?content=' + settings.content + settings.gameID + '&toplist=3',
		success: function(data)	{
			$('.toplist' + settings.content + 'Tmp').html(data);
			var uls = new Array();
			var lis = new Array();
			for(var i=0; i<3; i++) {
				uls[i] = $('.toplist' + settings.content + 'Tmp ul:eq(0)');
				$('.toplist' + settings.content + 'Tmp ul:eq(0)').remove();
				var targetUl = $('.toplist' + settings.content + 'Tmp').parents('.topList').find('.codaSlider .toplistOrig:eq(' + i + ')');
				var ulOverTmp = '<ul class="toplist ulOver"></ul>';
				targetUl.parent().prepend(ulOverTmp);
				var ulOver = targetUl.parent().find('ul.ulOver').css({
					'position' : 'absolute',
					'zIndex' : (i + 10),
					'display' : 'none'
				});
				lis[i] = new Array();
				var fbidClasses = '';
				var liHeight = 40;
				var liWidth = 268;
				ulOver.fadeIn(500, (function(targetUl, thisUl, thisLis, ulOver){
					return (function(){
						$('li', thisUl).each(function(j){
							thisLis[j] = $(this).clone();
							var liFbidClass = thisLis[j].attr('class').replace('first', '').replace(' ', '');
							fbidClasses += liFbidClass + ',';
							if($('li.' + liFbidClass, targetUl).index('') == -1) {
								var marginTopStart = ($('li', targetUl).length + j)*liHeight;
							} else {
								var marginTopStart = $('li.' + liFbidClass, targetUl).index('')*liHeight;
							}
							var marginTopEnd = j*liHeight;
							if(marginTopStart > marginTopEnd) {
								var borderColor = '#98ce9d';
							} else if(marginTopStart < marginTopEnd) {
								var borderColor = '#daa7a7';
							} else {
								var borderColor = '#eaeaea';
							}
							ulOver.append(thisLis[j]);
							
							thisLis[j].css({
								'marginTop' : marginTopStart,
								'position' : 'absolute',
								'zIndex' : (marginTopStart/liHeight) + 10,
								'borderColor' : borderColor,
								'width' : liWidth
							});
							thisLis[j].animate({
								'marginTop' : marginTopEnd
							}, 3000, (function(targetUl, thisUl, ulOver){
								return (function(){
									if(targetUl.prev().is('ul')) {
										targetUl.replaceWith(thisUl);
										targetUl.fadeIn(500);
										ulOver.fadeOut(500, (function(ulOver){
											return (function(){
												ulOver.remove();
											});
										})(ulOver));
									}
								});
							})(targetUl, thisUl, ulOver));
						});
						$('li', targetUl).each(function(j){
							var newLi = $(this).clone();
							var liFbidClass = $(this).attr('class').replace('first', '').replace(' ', '');
							if(fbidClasses.indexOf(liFbidClass) == -1) {
								var marginTopStart = $(this).index('')*liHeight;
								var marginTopEnd = ($('li', targetUl).length + j)*liHeight;
								if(marginTopStart > marginTopEnd) {
									var borderColor = '#98ce9d';
								} else if(marginTopStart < marginTopEnd) {
									var borderColor = '#daa7a7';
								} else {
									var borderColor = '#eaeaea';
								}
								ulOver.append(newLi);
								
								newLi.css({
									'marginTop' : marginTopStart,
									'position' : 'absolute',
									'zIndex' : (marginTopStart/liHeight) + 10,
									'borderColor' : borderColor,
									'width' : liWidth
								});
								newLi.animate({
									'marginTop' : marginTopEnd
								}, 3000, (function(targetUl, thisUl, ulOver){
									return (function(){
										if(targetUl.prev().is('ul')) {
											targetUl.replaceWith(thisUl);
											targetUl.fadeIn(500);
											ulOver.fadeOut(500, (function(ulOver){
												return (function(){
													ulOver.remove();
												});
											})(ulOver));
										}
									})
								})(targetUl, thisUl, ulOver));
							}
						});
					});
				})(targetUl, uls[i], lis[i], ulOver));
				targetUl.fadeOut(500);
			}
			stoTPL = setTimeout('$(this).toplistRefresh({content : \'' + settings.content + '\', gameID : \'' + settings.gameID + '\'});', 10000);
		}
	});
};
Úgy kellene működnie, hogy ul-enként nézve először elhalványodik az eredeti lista, és előjön az új, ez a kettő egyszerre fut le. Az új listában az li-k position:absolute-tal egymás alá vannak rendezve aszerint, hogy mi volt a régi sorrendjük, majd új sorrend szerint animálódnak az új helyükre.. Az új listából kettő van, az egyik (uls[i]) tartalmazza magát a html kódot, a másik (ulOver) pedig a színezett, position:absolute-tal elrendezett li-ket. Ha az animáció lefutott, a régi lista helyére (targetUl) beteszem az elmentett új lista (uls[i]) teljes tartalmát. Ezután targetUl fadeIn, ulOver fadeOut, majd ulOver remove. Elvileg az animáció végén akartam meghívni újból a toplistRefresh fgv.-t, de egyelőre még nem úgy van.

A fadeIn-re és az animate-re betettem a return-ös megoldást, és az animate-re működik is, de a fadeIn-re nem.

Átadtam a fgv.-eknek a tömböket, de a fadeIn valahogy nem fut le.

Előre is köszi
4

Minimális példa

Poetro · 2012. Ápr. 3. (K), 11.13
Mi lenne, ha csinálnál egy kompaktabb változatot, amiben csak a probléma van benne? Mivel ezt ebben a formában lehetetlen futtatni. Azaz mutass egy olyan kódot, ami önmagában futtatható, és a probléma jelentkezik benne.
5

példa

Totti 1986 · 2012. Ápr. 3. (K), 12.34
Csináltam egy minimál példát, csak 1 frissítendő ul-lel.
ITT
Script ITT
Ez pont ugyanúgy működik, mint az eredeti, ajax hivás nélkül, meg az alján, ami a látható rész alá csúszik, az eredetileg tényleg nem látszik.
6

Minimál? :)

T.G · 2012. Ápr. 3. (K), 17.46
A minimál példa alatt általában azt szokták érteni, hogy csak a probléma/felvetés kiemelésére szolgáló néhány soros mintakód, indokolt esetben 10-15 soros kódrészlet.
Ez nem az. :)

A kód fele ekkora lenne, ha a felesleges függvények, függvényt visszaadó függvények egyszerűsödnének.
ulOver.fadeOut(500, (function(ulOver){
    return (function(){
        ulOver.remove();
    });
})(ulOver));
ulOver.fadeOut(500, function () {
    ulOver.remove();
});
vagy
$(function(){
    $(this).toplistRefresh();
});

$(this).toplistRefresh();
7

Mivel nem tudom, mi a hiba,

Totti 1986 · 2012. Ápr. 3. (K), 18.21
Mivel nem tudom, mi a hiba, így nem tudom, melyik részt hagyjam ki. Nem tudom, hogy az-e a baj, hogy a fadeIn után teszem bele az adatokat, vagy hogy rosszul adom át a változókat. Erre szerettem volna választ kapni. Ha kiszedek belőle mindent, akkor pont azt a részt nem fogom megtudni, ami a hibát okozhatja.
8

De

Poetro · 2012. Ápr. 3. (K), 18.33
De pedig pont azt fogod kapni. Csinálsz egy minimális HTML-t, ahhoz egy minimális JavaScript kódot. Ha az már azt csinálja, amit szeretnél, akkor elkezdheted visszapakolni a további részeket (lehetőleg nem egyben behányva, hanem függvényekbe strukturálva).
9

Kiszedtem mindent, ami nem

Totti 1986 · 2012. Ápr. 4. (Sze), 17.55
Kiszedtem mindent, ami nem kell, remélem, így már elég minimál.
HTML ITT
SCRIPT ITT

Ami ebből is látszik már, hogy egyszerre fut le az aminate és a fadeIn.
Úgy kellene, hogy először a targetUl fadeOut és ulOver fadeIn egyszerre, és utána fusson csak le az animate. Aztán ulOver fadeOut, targetUl fadeIn egyszerre és utána ulOver remove.
10

gyanú

T.G · 2012. Ápr. 4. (Sze), 18.47

ulOver.fadeIn(3000, (function(targetUl, thisUl, ulOver){
	liAnimate(targetUl, thisUl, ulOver);
})(targetUl, ul, ulOver));
Ez itt nagyon gyanús. (nem tudom mit szerettél volna, de ez tuti nem azt csinálja)
12

Kiszedtem minden olyan

Totti 1986 · 2012. Ápr. 5. (Cs), 16.19
Kiszedtem minden olyan dolgot, ami csak bonyolítja a scriptet, és betettem egy sima animációt, ami nem azt csinálja, amit kell, csak simán egy animáció, hogy lássam, hogy sorban futtatja-e le, vagy egyszerre. És a gond az, hogy a fadeIn-nel egyidőben animál, pedig utána kéne.
13

függvény vs. függvényhívás

T.G · 2012. Ápr. 5. (Cs), 16.36
Az általam kivágott részlet egyenértékű ezzel:

liAnimate(targetUl, thisUl, ulOver);  
ulOver.fadeIn(3000);  
Tehát igen, hamarabb fut le a liAnim, mint a fadeIn.

Sok helyen feleslegesen van függvényt visszaadó függvény, de itt szimpla függvényhívás van, becsomagolva egy függvényhívásba.
14

Dehát a jquery nem úgy

Totti 1986 · 2012. Ápr. 5. (Cs), 16.48
Dehát a jquery nem úgy működik, hogy van egy fgv., pl. fadeIn, beírom az idejét, aztán meg azt, hogy mi történjen azután, hogy lefutott? Nekem eddig mindig így működött, akkor most miért fut le előtte az, amit oda írtam be, ahova azt kell, hogy mi fusson le utána?
15

így:

T.G · 2012. Ápr. 5. (Cs), 17.23

ulOver.fadeIn(3000, function () {
    liAnimate(targetUl, thisUl, ulOver);
});
16

Legelőször így csináltam, de

Totti 1986 · 2012. Ápr. 5. (Cs), 17.55
Legelőször így csináltam, de így undefined minden változó, ami az animate-ben van.
17

thisUl vs. ul

T.G · 2012. Ápr. 5. (Cs), 18.24
A thisUl helyett ul, mert valóban kihagyjuk a függvényhívást, akkor thisUl nem létezik.

Ezért is jobb egyszerűen írni, mert a sok ugyanolyan változó között nehéz átlátni, hogy éppen, mikor, hogyan, hol... de az biztos, ha az eredeti függvénynek át tudtad adni azt a három változót, akkor így is át kellene tudni. :)
18

A változót át tudom adni, de

Totti 1986 · 2012. Ápr. 5. (Cs), 19.06
A változót át tudom adni, de ha átadom, akkor azonnal fut le, nem utána. Ha nem adom át, akkor undefined.
19

Kipróbáltad?

T.G · 2012. Ápr. 5. (Cs), 19.42
Kipróbáltad és nem működik? (vagy ránézésre megállapítottad, hogy úgyis undefined lenne?) Vagy rá se néztél? :)

ulOver.fadeIn(3000, function () {
  liAnimate(targetUl, ul, ulOver);
});
Lelövőm a poént, ez a script és a legelső script között hatalmas különbség van, ott li[i] és társai voltak a függvényben, ahol az i érték kavart be, de most ez már nem áll fent!
20

Persze, hogy kipróbáltam, de

Totti 1986 · 2012. Ápr. 5. (Cs), 19.50
Persze, hogy kipróbáltam, de ha gondolod, nézd meg most, most úgy is hagytam, ahogy írtad. Így nem undefined, de cserébe az ulOver.fadeIn le se fut, csak az animáció utána. Ez volt az első verzió, amit kipróbáltam, innen alakítottam utána tovább, és akkor volt az, hogy egyszerre hajtotta végre a fadeIn-t és az animate-et.
21

A ulOver.fadeIn lefut...

T.G · 2012. Ápr. 6. (P), 06.29
A ulOver.fadeIn lefut, csak ilyen az, amikor üres ul animálódik. :)

Én egy technikai hibára hívtam fel a figyelmedet. Ha egy függvényt várunk valahol paraméterként, akkor annak így kell kinéznie.

Viszont itt logikai hiba is van, létrehozol egy ul-t, majd animáltatod, majd animáció végén teszel bele elemeket. A liAnim függvényt tovább kell bontanod. Egyik felét az ulOver.fadeIn előtt, másik felét utána kell futattni.

Közhely, de örök igazság: azért kell kis, rövid függvényeket írni, hogy minden függvénynek pontosan tudjuk a feladatát. Ha egy kilométeres függvényt írsz, akkor persze, hogy egy idő után teljesen átláthatatlan, hogy mit is csinál, miért is csinálja és egyáltalán nem lesz egyértelmű, hogy mit szerettünk volna, hogy csináljon...
22

Sejtettem, hogy az üres ul

Totti 1986 · 2012. Ápr. 6. (P), 12.39
Sejtettem, hogy az üres ul animálás probléma lesz, viszont érted, nem akartam 2x végigmenni ugyanazon a cikluson. Először végigmegyek az összes li-n, beteszem őket az ul-be, megadom a kezdő margin-t, majd mikor mind benne van, meghivom a fadeIn-t, majd egy anim fgv.-t, amiben újra végigmegyek elölről az összes elemen, megadom a cél margint, és leanimálom. Ezért csináltam így. De akkor szétszedem, megnézem, akkor hogy viselkedik.
23

korai optimalizálás

T.G · 2012. Ápr. 6. (P), 13.02
Knuth: "A túl korai optimalizálás minden baj gyökere".
24

De végre összeállt a

Totti 1986 · 2012. Ápr. 6. (P), 13.12
De végre összeállt a fejemben, hogy mi a hiba, és hogy nagyjából mi hogy működik.
Köszi a segítséget, most már legalább működik minden úgy, ahogy akartam, összerakom újra az egészet! :)
11

targetUl.fadeIn(500); ulOver.

Poetro · 2012. Ápr. 4. (Sze), 19.02
targetUl.fadeIn(500);
ulOver.fadeOut(500, function() {
  valami.animate(...);
});