Προς το περιεχόμενο

jquery - javascript object variables


Προτεινόμενες αναρτήσεις

Δημοσ.

Καλημέρα,έχω το εξής θέμα και τον εξής κώδικα,

>
<script type='text/javascript'>
function person(){
   var _this = this;
   this.stoixeia = null;
   this.mathimata = null;
   this.requestData = function(){
       $.post("server.php","",function(data){
           _this.stoixeia = data.stoixeia; /* ston json_encoe έχω ένα key stoixeia */
           _this.mathimata = data.mathimata ; /* ston json_encoe έχω ένα key mathimata */
       },"json");
   }
   this.consoleData = function(){
       console.log(this.stoixeia);
       console.log(this.mathimata);
   }
   this.init = function(){
      this.requestData();
      this.consoleData();
   }
}

var me = new person();
me.init();
</script>

Ο κώδικας είναι για το παράδειγμα αυτό. Να διευκρινίσω ότι έχω κάνει include την jquery βιβλιοθήκη.

Το πρόβλημα είναι το εξής. Όταν στην requestData function δεν υπάρχει κλήση στον server (οπότε δεν υπάρχει και callback function) και απλά βάλω μια τιμή στην κάθε variable, τότε η consoleData function μπορεί να τις διαβάσει.εάν όμως πάω και τους αναθέσω μια τιμή μέσα στην callback του jquery.post τότε δεν είναι διαθέσιμες στην consoleData function και κατ΄επέκταση στις άλλες function του object(στην κονσόλα εμφανίζει null,null).

Ελπίζω να έγινα κατανοητός

Ευχαριστώ

Δημοσ.

Η λογική αυτού που πας να κάνεις είναι γενικά σωστή. Το πρόβλημά σου είναι ότι η κλήση στον server γίνεται ασύγχρονα (AJAX), οπότε δες τι συμβαίνει:

 

>this.init = function(){
  this.requestData(); // βάζει ένα HTTP request να ψήνεται και ΕΠΙΣΤΡΕΦΕΙ ΑΜΕΣΩΣ

  this.consoleData(); // το request δεν έχει ολοκληρωθεί ακόμα, οπότε οι μεταβλητές
                      // έχουν ακόμα την τιμή null
}

 

Ένας εύκολος τρόπος να διαπιστώσεις το παραπάνω είναι να βάλεις μια καθυστέρηση πριν την εκτέλεση της consoleData ούτως ώστε να προλάβει να πραγματοποιηθεί το request και να πάρουν τιμές οι μεταβλητές σου, π.χ. να το αλλάξεις σε

 

>
// προσοχή, δεν υπάρχουν παρενθέσεις μετά το όνομα της consoleData
// φαντάζομαι καταλαβαίνεις γιατί, αν όχι μη προχωρήσεις μέχρι να το καταλάβεις
window.setTimeout(this.consoleData, 1000);

 

Αυτό βέβαια κάνει μόνο για επιβεβαίωση και δεν είναι σωστή λύση.

 

Η σωστή λύση είναι να λάβεις υπόψη ότι η $.post επιστρέφει ένα jqXHR object, το οποίο ικανοποιεί τις προϋποθέσεις ενός promise (σου προτείνω ν' ασχοληθείς με το $.Deferred() μέχρι να καταλάβεις πως δουλεύει -- μια promise είναι ένα "read-only" interface του Deferred).

 

Μπορείς λοιπόν να επιστρέψεις αυτό το jqXHR object από την requestData και μετά να κάνεις chain πράγματα πάνω του καθώς όπως είπαμε, είναι promise:

 

>this.requestData = function(){
   // πρόσθεσα ένα return
   return $.post("server.php","",function(data){
       _this.stoixeia = data.stoixeia; /* ston json_encoe έχω ένα key stoixeia */
       _this.mathimata = data.mathimata ; /* ston json_encoe έχω ένα key mathimata */
   },"json");
}
this.init = function(){
   this.requestData().done(this.consoleData);
}

 

...και όλα θα δουλέψουν σωστά. Επειδή το callback μπαίνει με την .done(), η consoleData() θα εκτελεστεί μόνο στην περίπτωση που το POST request πετύχει. Αν θέλεις να εκτελεστεί και σε περίπτωση αποτυχίας, χρησιμοποιείς στη θέση της την .then() ή ισοδύναμα .always().

 

Σ' αυτό το σημείο μπορείς επίσης να καταλάβεις ότι και μέσα στη requestData() δεν κάνεις τίποτα άλλο από το να προσθέτεις ένα success callback, που σημαίνει ότι μπορείς να τη γράψεις ισοδύναμα (έβγαλα το hint ότι η απάντηση είναι JSON, αν από το server δίνεις τον header με το σωστό content type "Content-Type: application/json" δε χρειάζεται):

 

>this.requestData = function(){
   return $.post("server.php")
       .done(function(data){
           _this.stoixeia = data.stoixeia; /* ston json_encoe έχω ένα key stoixeia */
           _this.mathimata = data.mathimata ; /* ston json_encoe έχω ένα key mathimata */
       });
}

 

Εδώ τώρα μπορείς να δεις ότι στην ουσία (μαζί με τον κώδικα στην .init()) έχουμε ένα chain του στυλ $.post().done().done(), το οποίο μπορεί να συνεχιστεί όσο σου αρέσει.

Δημοσ.

Ευχαριστώ πολύ!!

 

Ξαναδιαβάζοντας τι σου έγραψα συνειδητοποίησα ότι σηκώνει κι άλλη βελτίωση... :-D

 

Δες αυτό:

 

>this.requestData().done(this.consoleData);

 

Εδώ υπάρχει η προϋπόθεση ότι η .requestData() πρέπει να επιστρέψει οπωσδήποτε ένα promise. Αυτό στην προκειμένη δεν είναι πρόβλημα, αλλά τι γίνεται αν θέλεις αύριο να την αλλάξεις με άλλη υλοποίηση (π.χ. μια που δίνει τιμές κατευθείαν)? Πρόβλημα.

 

Θα μπορούσες να κανονίσεις να επιστρέφεις πάντα μια εκπληρωμένη promise ως εξής:

 

>this.requestData = function(){
   _this.stoixeia = "foo";
   _this.mathimata = "bar";
   return $.Deferred().resolve().promise();
}

 

Αλλά δε χρειάζεται, γιατί το jQuery παρέχει τη $.when που τα κανονίζει όλα αυτόματα. Γράφεις λοιπόν:

 

>$.when(this.requestData()).done(this.consoleData);

 

Και τώρα δεν έχει απολύτως καμία σημασία αν η .requestData() επιστρέφει promise ή ο,τιδήποτε άλλο (δεν έχει σημασία όσον αφορά το ότι ο κώδικας θα παίξει, όχι όσον αφορά το τι αποτέλεσμα θα έχει αν όντως επιστρέψεις κάποιο promise). Μπορείς να το δοκιμάσεις και με τις 2 μορφές:

 

>this.requestData = function(){
   _this.stoixeia = "foo";
   _this.mathimata = "bar";
}

 

>this.requestData = function(){
   return $.post(...).done(...);
}

Δημοσ.

Σε ευχαριστώ πολύ για το χρόνο σου. Επειδή βλέπω ότι το κατέχεις το σπορ, θα ήθελα να σε ρωτήσω κάτι. Επειδή το web εξελίσσεται και έχουμε φύγει πλέον από τις σελίδες όπου παίρνουν μεταβλητές από το url , έχω αρχίσει να χρησιμοποιώ ajax στις εφαρμογές μου και στις σελίδες μου. Έχω όμως ένα πρόβλημα το οποίο έχει να κάνει με το back κουμπί των browsers. Δεν θα ήθελα να εκπαιδεύω τους χρήστες μου να μην πατούν το πίσω στους browsers.Επίσης έχω δει κάποια history plugins που υπάρχουν αλλά δεν μπορώ να τα βάλω σε λειτουργία. Εσύ πώς έχεις λύσει αυτό το θέμα? Μήπως έχεις κάποια πρόταση? Εάν έχεις χρόνο θα ήθελα να μου δώσεις 1-2 γραμμές στις οποίες θα πρέπει να κινηθώ.Δεν έχω αυτή τη στιγμή κάποιο project που κρέμεται από αυτή την απάντηση, οπότε ,όποτε μπορέσεις μου απαντάς.Ευχαριστώ!

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...