Kom ihåg mig?
Home Menu

Menu


jQuery, Event Binding, gör jag rätt?

Ämnesverktyg Visningsalternativ
Oläst 2012-05-03, 16:07 #1
mojitoo mojitoo är inte uppkopplad
Medlem
 
Reg.datum: Jun 2010
Inlägg: 125
mojitoo mojitoo är inte uppkopplad
Medlem
 
Reg.datum: Jun 2010
Inlägg: 125
Standard jQuery, Event Binding, gör jag rätt?

Hej!

Jag håller på att försöka lära mig event binding från följande sida:
http://docs.jquery.com/Tutorials:AJAX_and_Events

Jag skulle vilja att ni scrollade ned till
Scoping an Event Binding Function och följande kodsnutt:
Kod:
$(document).ready(function() {
 var bindBehaviors = function(scope) {
   $('h3', scope).click(function() {
     $(this).toggleClass('highlighted');
   });
 }

 bindBehaviors(this);

 $('#letter-a .button').click(function() {
   $('#dictionary').hide().load('a.html', function() {
     bindBehaviors(this);
     $(this).fadeIn();
   });
 });
});
I click funktionen längst ned så skickar jag istället in den div som jag har uppdaterat vilken kan vara
Kod:
<div class="wrapper">
<p class="p1"></p>
</div>
Är detta rätt eller borde jag istället skicka in this som de gör i exemplet, anledningen till att jag bara skickar in diven är eftersom att this innehåller så mycket annan information än bara de nya elementen.

Min andra fråga gäller:
Kod:
   $('h3', scope).click(function() {
vad innebär scope i detta exempel? För om jag sätter scope på samma sätt så fungerar det inte för mig men om jag gör utan scope så fungerar den bra. Är det nödvändigt att ha scope där och vad är meningen med det?
mojitoo är inte uppkopplad   Svara med citatSvara med citat
Oläst 2012-05-03, 16:25 #2
allstars allstars är inte uppkopplad
Klarade millennium-buggen
 
Reg.datum: Apr 2006
Inlägg: 2 126
allstars allstars är inte uppkopplad
Klarade millennium-buggen
 
Reg.datum: Apr 2006
Inlägg: 2 126
istället för att skicka in this (som jag antar betyder "document" i ditt fall) så kan man skicka in en container istället för hela sidan om bindingen ska gälla en vis del på sidan istället för hela.

i andra fallet är scopet $('#dictionary').
allstars är inte uppkopplad   Svara med citatSvara med citat
Oläst 2012-05-16, 22:25 #3
mojitoo mojitoo är inte uppkopplad
Medlem
 
Reg.datum: Jun 2010
Inlägg: 125
mojitoo mojitoo är inte uppkopplad
Medlem
 
Reg.datum: Jun 2010
Inlägg: 125
Tack för det klarläggandet allstar, dock så har jag nu legt runt lite med det utan att egentligen få det att fungera som jag vill.

Säg att jag har följande
PHP-kod:
$(document).ready(function() {
 var 
bindBehaviors = function(scope) {
   $(
'.comment'scope).on('click', function() {
     
console.log('wn');
   });
 } 
Denna kod fungerar utmärkt för objekt som jag inte lägger till i efterhand.
säg att jag senare i koden skickar in en div med en massa innehåll, däribland classen comment. Jag har kollat så att det är exakt denna div jag vill använda mig av.

PHP-kod:
bindBehaviors(div_med_lull_lull); 
Som koden är nu fungerar det inte att klicka på commentknappen för den tillagda diven. Dock så skulle det fungera om jag ändrade i bindBehaviors till följande:

PHP-kod:
$(document).ready(function() {
 var 
bindBehaviors = function(scope) {
   $(
'.comment').on('click', function() {
     
console.log('wn');
   });
 } 
Dvs det fungerar om jag tar bort scope från bindBehaviors men problemet som uppstår då är att knappen blir intryckt mer än en gång. Jag har suttit i timmar och slitit mitt hår för att försöka förstå varför det inte fungerar för tillagda objekt med jquery och scope men att det fungerar utan scope för tillagda objekt med jquery. Det skulle vara vänligt om någon av er kunde förklara varför det inte verkar fungera som jag vill.
mojitoo är inte uppkopplad   Svara med citatSvara med citat
Oläst 2012-05-16, 22:40 #4
mojitoo mojitoo är inte uppkopplad
Medlem
 
Reg.datum: Jun 2010
Inlägg: 125
mojitoo mojitoo är inte uppkopplad
Medlem
 
Reg.datum: Jun 2010
Inlägg: 125
För att bättre visa vad som inte fungerar ger jag er ett exempel, det fungerar inte med scope här:

PHP-kod:
$('.comment'scope).on('click', function(e) { 
Och jag behöver det i mitt projekt annars så klickas det hur många gånger som helst.

index.html
PHP-kod:
<!DOCTYPE HTML>
<
html lang="en-US">
<
head>
    <
meta charset="UTF-8">
    <
title></title>
    <
script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
    <script src="js/script.js" type="text/javascript"></script>
</head>
<body>
    <div class="comment_wrapper">
        <a href="#" class="comment">Write your comment</a>
    </div>

    <p>
        <a href="#" class="insert">Insert New Object</a>
    </p>
</body>
</html> 
script.js
PHP-kod:
$(document).ready(function() {


    var 
bindBehaviors = function(scope) {

        $(
'.comment'scope).on('click', function(e) {

            
e.preventDefault();
            
console.log('comment');
        });
    }

    

    $(
'.insert').on('click', function(e) {

        
e.preventDefault();
        
console.log('insert');

        var 
tempDiv '<div class="comment_wrapper"><a href="#" class="comment">Write your comment</a></div>';
        $(
this).before(tempDiv);
        
bindBehaviors(tempDiv);
    });

    
bindBehaviors(this);


}); 
mojitoo är inte uppkopplad   Svara med citatSvara med citat
Oläst 2012-05-18, 12:44 #5
dAEks avatar
dAEk dAEk är inte uppkopplad
Mycket flitig postare
 
Reg.datum: Dec 2006
Inlägg: 678
dAEk dAEk är inte uppkopplad
Mycket flitig postare
dAEks avatar
 
Reg.datum: Dec 2006
Inlägg: 678
En sak jag reagerar på är att du i din $(".insert")-klicklyssnare skickar in en sträng till din bindBehaviors-method som dock förväntar sig en selektor eller eventuellt ett jquery-objekt. Eftersom du skickar in en sträng till metoden kan den inte regga eventlyssnaren som den ska. Jquery har ibland beteendet att - på gott och ont - faila tyst när man gör saker som inte funkar. Man får inte reda på att man gör nånting tokigt utan saker och ting funkar helt enkelt bara inte.
Även om man rättar misstaget ovan och istället skickar in rätt scope (dvs bindBehaviors(".comment_wrapper")) finns det en liten tankevurpa där. De tidigare registrerade eventlyssnarna finns kvar men när bindBehaviors körs igen reggas det en till för varje ny rad som infogas. Dvs lägger man till en kommentar och sedan klickar på den första kommentarslänken kommer det resultera i 2 rader i konsollen.

En annan sak som är värd att nämna i när man pysslar med javascript är att man inte behöver regga en lyssnare på varje element. Det är t.o.m. ganska dumt om man kan tänkas ha många element som man ska kunna klicka på. Då är det bättre att använda sig av s.k. delegates som innebär att man reggar en (1) eventlyssnare oavsett hur många kommentarer man har. Det funkar som så att man lägger eventlyssnaren på föräldernoden och säger åt den att köra en method när event triggas på en child-selektor.

I ditt fall skulle javascriptet kunna skrivas om till nåt i stil med:

Kod:
$(document).ready(function() { 
	
	$('.insert').on('click', function(e) { 
		e.preventDefault(); 
		console.log('insert'); 
		
		var tempDiv = '<div class="comment_wrapper"><a href="#" class="comment">Write your comment</a></div>'; 
		$(this).before(tempDiv); 
	}); 

	$("body").delegate(".comment", "click", function (event) {
		event.preventDefault(); 
		console.log('comment'); 
	});
});
Eftersom det är en delegate som används behöver du inte regga eventlyssnare på nya element som du försökte göra tidigare.

Istället för att lägga lyssnaren på body kan du såklart wrappa dina kommentarer runt t.ex. <div id="#comments"> och skicka in id:t i delegaten istället för body.
dAEk är inte uppkopplad   Svara med citatSvara med citat
Oläst 2012-05-18, 14:21 #6
mojitoo mojitoo är inte uppkopplad
Medlem
 
Reg.datum: Jun 2010
Inlägg: 125
mojitoo mojitoo är inte uppkopplad
Medlem
 
Reg.datum: Jun 2010
Inlägg: 125
Tack så mycket dAEK, din kod fungerar bra och det var väldigt bra förklarat!

Jag har dock ett par små frågor, säg att min .comment skulle ha legat i en div som heter .side_wrapper_comment. Skulle jag då ha skrivit .side_wrapper_comment istället för body eftersom att den då skulle ha varit den närmsta föräldern? Det var åtminstone så som jag förstod din förklaring eller ska den alltid ligga i body?

Anledningen till att jag skickar in en sträng i .insert är att jag vill att koden ska fungera även om den första kommentaren inte existerar. Vilket för mig till min nästa fråga som lyder om det finns något bättre sätt att skapa denna nya div eftersom mitt sätt tydligen inte var att rekommendera?
mojitoo är inte uppkopplad   Svara med citatSvara med citat
Oläst 2012-05-18, 15:40 #7
dAEks avatar
dAEk dAEk är inte uppkopplad
Mycket flitig postare
 
Reg.datum: Dec 2006
Inlägg: 678
dAEk dAEk är inte uppkopplad
Mycket flitig postare
dAEks avatar
 
Reg.datum: Dec 2006
Inlägg: 678
Aha, ser nu att jag var lite otydlig i det där med föräldernoden. När man använder delegates vill man sätta lyssnaren på ett element som alltid finns där. Den första noden som inte tas bort med javascript kan vara ett bra resonemang.

I ditt första exempel ser strukturen ut såhär:
Kod:
-html
|--body
|----.comment_wrapper
|-------.comment
När en ny kommentar läggs till blir trädet:

Kod:
-html
|--body
|----.comment_wrapper
|-------.comment
|----.comment_wrapper
|-------.comment
och då kan man se att det inte skulle funka att sätta delegaten på .comment_wrapper eftersom man då behöver binda eventen på samma mindre effektiva sätt som jag beskrev ovan. Närmsta förälder som inte påverkas när nya kommentarer infogas är i det här fallet body men om alla kommentarer omsluts av ett annat element blir strukturen:

Kod:
-html
|--body
|----.side_wrapper_comment
|-------.comment_wrapper
|----------.comment
|-------.comment_wrapper
|----------.comment
eller som jag skrev tidigare med #comments:

Kod:
-html
|--body
|----#comments
|-------.comment_wrapper
|----------.comment
|-------.comment_wrapper
|----------.comment
och då sätter man delegaten på .side_wrapper_comment eller på #comments. Hoppas att det blev lite tydligare nu.



Ang. den andra frågan: jo, det finns bättre sätt. Det finns olika templatebibliotek som gör livet enklare men jag brukar trots det föredra att göra det för hand.
När man gör jobbet själv innebär det i kort att man ser till att det alltid finns en mall/template i Html-koden. När man sedan behöver infoga nya poster med Javascript tar man en kopia på mallen, klonar den, lägger in nytt innehåll och infogar den.

I ditt fall skulle $(".insert")-klickfunktionen skrivas om till följande:
Kod:
$('.insert').on('click', function(e) { 
	e.preventDefault(); 
	console.log('insert'); 

	var template = $(".side_wrapper_comment").find(".template").first();
	var clone = template.clone();
	$(this).before(clone); 
});
Och Html-koden:
Kod:
<html>
[...]
<body> 
	<div class="side_wrapper_comment">
		<div class="comment_wrapper"> 
			<a href="#" class="comment">Write your comment</a> 
		</div> 
		
		<p> 
			<a href="#" class="insert">Insert New Object</a> 
		</p> 
	</div>
</body> 
</html>




Om vi tänker oss att vi vill hämta nya kommentarer från servern eller liknande skulle vi kunna infoga dessa på detta ganska fiffiga sätt:
Kod:
$(".reload").on("click", function(e) {
	e.preventDefault();
	console.log("hämtar kommentarer..."); 
	
	reloadComments();
});

function reloadComments() {
	var comments = getCommentsFromServerOrWhatever(); //returnerar en array av kommentarer
	var template = $("#comments").find(".template").clone();
	
	$.each(comments, function(i, comment) {
		var newComment = template.clone();
		newComment.find(".text").html(comment.Text);
		newComment.find(".author").html(comment.Author);
		newComment.find(".time").html(comment.PostedAt);
		newComment.removeClass("template");
		
		$("#comments").append(newComment);
		newComment.show();
	});
}
Html-markuppen för detta scenario:

Kod:
<body> 
	<div class="side_wrapper_comment">
		<div id="comments">
			<div class="comment_wrapper template"> 
				<div class="text"></div>
				<span class="author"></span>
				<span class="time"></span>
			</div>
		</div>
		<p> 
			<a href="#" class="reload">Ladda om kommentarerna</a> 
		</p> 
	</div>
</body>
dAEk är inte uppkopplad   Svara med citatSvara med citat
Svara


Aktiva användare som för närvarande tittar på det här ämnet: 1 (0 medlemmar och 1 gäster)
 

Regler för att posta
Du får inte posta nya ämnen
Du får inte posta svar
Du får inte posta bifogade filer
Du får inte redigera dina inlägg

BB-kod är
Smilies är
[IMG]-kod är
HTML-kod är av

Forumhopp


Alla tider är GMT +2. Klockan är nu 20:18.

Programvara från: vBulletin® Version 3.8.2
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Svensk översättning av: Anders Pettersson
 
Copyright © 2017